#!/bin/sh # # Unified Segger J-Link script for RIOT # # This script is supposed to be called from RIOTs build system, # as it depends on certain environment variables. # # The minimum supported version of J-Link is V6.74. # # Global environment variables used: # JLINK: J-Link Commander command name, default: "JLinkExe" # JLINK_SERVER: J-Link GDB Server command name, default: "JLinkGDBServer" # JLINK_DEVICE: Device identifier used by J-Link # JLINK_SERIAL: Device serial used by J-Link # JLINK_IF: Interface used by J-Link, default: "SWD" # JLINK_SPEED: Interface clock speed to use (in kHz), default "2000" # FLASH_ADDR: Starting address of the target's flash memory, default: "0" # IMAGE_OFFSET: Offset from the targets flash memory, for flashing the # image # JLINK_PRE_FLASH: Additional J-Link commands to execute before flashing # JLINK_POST_FLASH: Additional J-Link commands to execute after flashing # # The script supports the following actions: # # flash: flash # # flash given binary format file to the target. # # options: # : path to the binary file that is flashed # # debug: debug # # starts J-Link as GDB server in the background and # connects to the server with the GDB client specified by # the board (DBG environment variable) # # options: # : path to the ELF file to debug # GDB_PORT: port opened for GDB connections # TELNET_PORT: port opened for telnet connections # DBG: debugger client command, default: 'gdb -q' # TUI: if TUI!=null, the -tui option will be used # # debug-server: starts J-Link as GDB server, but does not connect to # to it with any frontend. This might be useful when using # IDEs. # # options: # GDB_PORT: port opened for GDB connections # TELNET_PORT: port opened for telnet connections # # reset: triggers a hardware reset of the target board # # # term-rtt: opens a serial terminal using J-Link RTT (Real-Time Transfer) # # # @author Hauke Peteresen # Set IMAGE_OFFSET to zero by default. : ${IMAGE_OFFSET:=0} # Allow overwriting the reset commands. : ${JLINK_RESET_FILE:=${RIOTTOOLS}/jlink/reset.seg} # default GDB port _GDB_PORT=3333 # default telnet port _TELNET_PORT=4444 # default J-Link command names, interface and speed _JLINK=JLinkExe _JLINK_SERVER=JLinkGDBServer _JLINK_IF=SWD _JLINK_SPEED=2000 # default terminal frontend _JLINK_TERMPROG=${RIOTTOOLS}/pyterm/pyterm _JLINK_TERMFLAGS="-ts 19021 ${PYTERMFLAGS}" # # a couple of tests for certain configuration options # test_config() { if [ -z "${JLINK}" ]; then JLINK=${_JLINK} fi if [ -z "${JLINK_SERVER}" ]; then JLINK_SERVER=${_JLINK_SERVER} fi if [ -z "${JLINK_IF}" ]; then JLINK_IF=${_JLINK_IF} fi if [ -z "${JLINK_SPEED}" ]; then JLINK_SPEED=${_JLINK_SPEED} fi if [ -z "${JLINK_DEVICE}" ]; then echo "Error: No target device defined in JLINK_DEVICE env var" exit 1 fi if [ -z "${FLASH_ADDR}" ]; then echo "Error: No flash address defined in FLASH_ADDR env var" exit 1 fi } test_binfile() { if [ ! -f "${BINFILE}" ]; then echo "Error: Unable to locate BINFILE" echo " (${BINFILE})" exit 1 fi } test_ports() { if [ -z "${GDB_PORT}" ]; then GDB_PORT=${_GDB_PORT} fi if [ -z "${TELNET_PORT}" ]; then TELNET_PORT=${_TELNET_PORT} fi } test_elffile() { if [ ! -f "${ELFFILE}" ]; then echo "Error: Unable to locate ELFFILE" echo " (${ELFFILE})" exit 1 fi } test_tui() { if [ -n "${TUI}" ]; then TUI=-tui fi } test_serial() { if [ -n "${JLINK_SERIAL}" ]; then JLINK_SERIAL_SERVER="-select usb='${JLINK_SERIAL}'" JLINK_SERIAL="-selectemubysn '${JLINK_SERIAL}'" fi } test_dbg() { if [ -z "${DBG}" ]; then DBG="${GDB}" fi } test_term() { if [ -z "${JLINK_TERMPROG}" ]; then JLINK_TERMPROG="${_JLINK_TERMPROG}" fi if [ -z "${JLINK_TERMFLAGS}" ]; then JLINK_TERMFLAGS="${_JLINK_TERMFLAGS}" fi } test_version() { if [ -z "${JLINK_SKIP_VERSION}" ]; then JLINK_MINIMUM_VERSION="6.74" # Adding '-nogui 1' will simply return 'Unknown command line option -nogui' # on older versions, JLINK_VERSION will still be parsed correctly. JLINK_VERSION=$(echo q | "${JLINK}" "${JLINK_SERIAL}" -nogui 1 2> /dev/null | grep "^DLL version*" | grep -oE "[0-9]+\.[0-9]+") if [ $? -ne 0 ]; then echo "Error: J-Link appears not to be installed on your PATH" exit 1 fi "$RIOTTOOLS"/has_minimal_version/has_minimal_version.sh "$JLINK_VERSION" "$JLINK_MINIMUM_VERSION" 2> /dev/null if [ $? -ne 0 ]; then echo "Error: J-Link V$JLINK_MINIMUM_VERSION is required, but V${JLINK_VERSION} is installed" exit 1 fi fi } # # now comes the actual actions # do_flash() { BINFILE=$1 test_config test_serial test_version test_binfile # clear any existing contents in burn file /bin/echo -n "" > ${BINDIR}/burn.seg # create temporary burn file if [ ! -z "${JLINK_PRE_FLASH}" ]; then printf "${JLINK_PRE_FLASH}\n" >> ${BINDIR}/burn.seg fi # address to flash is hex formatted, as required by JLink ADDR_TO_FLASH=$(printf "0x%08x\n" "$((${FLASH_ADDR} + ${IMAGE_OFFSET}))") echo "loadbin ${BINFILE} ${ADDR_TO_FLASH}" >> ${BINDIR}/burn.seg if [ ! -z "${JLINK_POST_FLASH}" ]; then printf "${JLINK_POST_FLASH}\n" >> ${BINDIR}/burn.seg fi cat ${JLINK_RESET_FILE} >> ${BINDIR}/burn.seg # flash device sh -c "${JLINK} ${JLINK_SERIAL} \ -nogui 1 \ -exitonerror 1 \ -device '${JLINK_DEVICE}' \ -speed '${JLINK_SPEED}' \ -if '${JLINK_IF}' \ -jtagconf -1,-1 \ -commandfile '${BINDIR}/burn.seg'" } do_debug() { ELFFILE=$1 test_config test_serial test_version test_elffile test_ports test_tui test_dbg # start the J-Link GDB server sh -c "${JLINK_SERVER} ${JLINK_SERIAL_SERVER} \ -nogui \ -silent \ -device '${JLINK_DEVICE}' \ -speed '${JLINK_SPEED}' \ -if '${JLINK_IF}' \ -port '${GDB_PORT}' \ -telnetport '${TELNET_PORT}'" & # save PID for terminating the server afterwards DBG_PID=$? # connect to the GDB server ${DBG} -q ${TUI} -ex "tar ext :${GDB_PORT}" ${ELFFILE} # clean up kill ${DBG_PID} } do_debugserver() { test_config test_serial test_version test_ports # start the J-Link GDB server sh -c "${JLINK_SERVER} ${JLINK_SERIAL_SERVER} \ -nogui \ -device '${JLINK_DEVICE}' \ -speed '${JLINK_SPEED}' \ -if '${JLINK_IF}' \ -port '${GDB_PORT}' \ -telnetport '${TELNET_PORT}'" } do_reset() { test_config test_serial test_version # reset the board sh -c "${JLINK} ${JLINK_SERIAL} \ -nogui 1 \ -exitonerror 1 \ -device '${JLINK_DEVICE}' \ -speed '${JLINK_SPEED}' \ -if '${JLINK_IF}' \ -jtagconf -1,-1 \ -commandfile '${JLINK_RESET_FILE}'" } do_term() { test_config test_serial test_version test_term # temporary file that save the J-Link Commander pid JLINK_PIDFILE=$(mktemp -t "jilnk_pid.XXXXXXXXXX") # will be called by trap cleanup() { if [ -f $JLINK_PIDFILE ]; then JLINK_PID="$(cat ${JLINK_PIDFILE})" kill ${JLINK_PID} rm -r "${JLINK_PIDFILE}" fi exit 0 } # cleanup after script terminates trap "cleanup ${JLINK_PIDFILE}" EXIT INT # start J-link as RTT server sh -c "${JLINK} ${JLINK_SERIAL} \ -nogui 1 \ -exitonerror 1 \ -device '${JLINK_DEVICE}' \ -speed '${JLINK_SPEED}' \ -if '${JLINK_IF}' \ -jtagconf -1,-1 \ -commandfile '${RIOTTOOLS}/jlink/term.seg' >/dev/null & \ echo \$! > $JLINK_PIDFILE" & sleep 1 sh -c "${JLINK_TERMPROG} ${JLINK_TERMFLAGS}" } # # parameter dispatching # ACTION="$1" shift # pop $1 from $@ case "${ACTION}" in flash) echo "### Flashing Target ###" echo "### Flashing at base address ${FLASH_ADDR} with offset ${IMAGE_OFFSET} ###" do_flash "$@" ;; debug) echo "### Starting Debugging ###" do_debug "$@" ;; debug-server) echo "### Starting GDB Server ###" do_debugserver "$@" ;; reset) echo "### Resetting Target ###" do_reset "$@" ;; term-rtt) echo "### Starting RTT terminal ###" do_term ;; *) echo "Usage: $0 {flash|debug|debug-server|reset|term-rtt}" echo " flash " echo " debug " ;; esac