Skip to content

Instantly share code, notes, and snippets.

@hwhw
Last active November 16, 2023 20:20
Show Gist options
  • Save hwhw/fc43892785aa84913d03495c97b0f25a to your computer and use it in GitHub Desktop.
Save hwhw/fc43892785aa84913d03495c97b0f25a to your computer and use it in GitHub Desktop.
Flashing CC2538 using OpenOCD (&UART)

Flashing CC2538 using OpenOCD (&UART)

Problem description

CC2538 SoCs are Cortex-M4 based SoCs by Texas Instruments for 802.15.4 PAN networking, especially for Zigbee communication using their Zigbee Stack solution. It also is a solid foundation for hobbyist-grade solutions involving Zigbee communication, especially for running a self-implemented Zigbee coordinator (often called "Zigbee gateway" in commercial distribution of similar tech). Software-wise, this is usually done by running "ZNP" (Zigbee Network Processor) firmware on the SoC and using a separate controller/computer to act as the "ZAP" (Zigbee Application Processor). In a hobbyist setting, the former is usually a cheap module from china containing the chip, capacitors and an antenna or antenna connector, while the latter is e.g. a Raspberry Pi or an Intel NUC or whatever floats your boat. The API between both components is specified and so the software side on the ZAP does not need to bother with Zigbee communication states but can act on a higher level. Examples for such software are zigbee2mqtt by koenkk or zigbee-lua by yours truly. This software usually was built on the CC2530/31 chipsets - however, the CC2538 is compatible in the ZNP/ZAP API and generally much more crafty and stable as it has a faster CPU core and more available memory. RF wise, as per the specs, they are mostly on par.

While the CC2530/31 uses an 8051 based CPU core and has its own proprietary two-wire debugging protocol that is also used for flashing the firmware, the CC2538 uses cJTAG (and in a second stage optionally JTAG) for this purpose. The easy way to flash firmware onto the CC2538 is therefore the Segger J-Link. In its "Edu" variant, which probably fits hobbyists best license-wise, it is somewhat affordable for hobbyists - but still not a bargain.

The reason of this short gist is therefore a short description on how to use a generic approach to flash CC2538 devices using open source OpenOCD software.

Approach

The CC2538 allows debug access using cJTAG (this is active by default upon boot) and - after switching over - using JTAG. We will use this facility to write to CC2538 memory. Currently, there does not seem to be available code that allows for easy flashing a full firmware blob. So we're resorting to a trick and do this in two steps:

  • first we access the internal flash controller control registers. We will write a few values that will make the CC2538 erase its last flash page. This will, among other things, clear the "valid firmware present" indicator in said flash page, and will also set a flag that in combination will activate the integrated bootloader in the CC2538.
  • then after a reset, the CC2538 will be in bootloader mode. Via its UART port, https://github.com/JelmerT/cc2538-bsl can be used to flash a full firmware image.

NOTE: using a (slightly forked) variant of OpenOCD, erasing the flash page and then using the serial bootloader is obsolete: it has a flash loader for the CC2538. So flashing a firmware is now as easy as connecting JTAG and running OpenOCD. See this comment: https://gist.github.com/hwhw/fc43892785aa84913d03495c97b0f25a#gistcomment-3518720

Prerequisites

In order to flash the CC2538 using OpenOCD, you need

  • a reasonably recent version of OpenOCD (https://openocd.org/)
  • an "interface" that OpenOCD can use. This can e.g. be FT2232 based USB/multiprotocol adapter, or in my case a Raspberry Pi (and in that case you would run OpenOCD on said RPi).
  • some telnet client to interact with OpenOCDs CLI.
  • https://github.com/JelmerT/cc2538-bsl for flashing after we used OpenOCD to prepare bootloader mode (not needed when using forked OpenOCD with CC2538 flash loader)

By the way: now is a good point in time to check if said bootloader mode is active on your CC2538 anyway (just wire up UART connection and run cc2538-bsl.py), which will save you lots of time since then you don't need to use OpenOCD.

Wiring up the CC2538 for (c)JTAG

From now on, information in the CC2538 reference manual is indispensible: http://www.ti.com/lit/ug/swru319c/swru319c.pdf When using OpenOCD in combination with a Raspberry Pi, you need to check the according OpenOCD interface configuration. By default, you'll find this in /usr/share/openocd/interface/raspberrypi2-native.cfg (for RPi >=2). The RPi pins used for JTAG communication are specified there. I suggest you go with the defaults. Note that there's two numbering schemes for RPi GPIOs, which will make things veeeeery awkward. At some point, you'll get this right, I guess. Default config is:

  • JTAG TCK - GPIO 11 - Pin 23
  • JTAG TMS - GPIO 25 - Pin 22
  • JTAG TDI - GPIO 10 - Pin 19
  • JTAG TDO - GPIO 9 - Pin 21

You need to wire up the full JTAG interface, as we will be using cJTAG just for switching over to JTAG mode. The CC2538 side is as follows:

  • JTAG TCK = cJTAG TCK - dedicated TCK pin 47.
  • JTAG TMS = cJTAG TMSC - dedicated TMS pin 46.
  • JTAG TDI - PB6 (=pin 49)
  • JTAG TDO - PB7 (=pin 48)

Also connect at least a common ground connection. You can also power the CC2538 using the RPi's 3.3V rail. Make double sure that you use the 3.3V rail, not the 5V rail.

Running OpenOCD

On the RPi (or whatever host you are using), run

openocd -f /usr/share/openocd/interface/raspberrypi2-native.cfg -f /usr/share/openocd/target/cc2538.cfg

(adapt to the interface you're using if it is not a RPi >= 2.)

It should output some status that will basically tell you it communicated successfully with the CC2538. Well, probably it won't on try #1 and you need to re-check your cables and so on, but at some point it hopefully will.

Use the OpenOCD CLI

In a different terminal - possibly even on another computer - run telnet localhost 4444 You should be greeted by the OpenOCD command line then. The following commands are to be entered on this OpenOCD command line interface.

erase flash CCA

using a fork of OpenOCD, this is not needed anymore, see https://gist.github.com/hwhw/fc43892785aa84913d03495c97b0f25a#gistcomment-3518720

Set erase address:

mww 0x400D300C 0x7F800

(note that this was shifted in an earlier release of this document - with a current version of OpenOCD of today, this seems to work instead now)

Issue erase command (also set flags to unlock)

mww 0x400D3008 0x0205

That's it, the CCA should be erased and all flags should be cleared now. I tried to reconstruct this from my OpenOCD history. I sincerely hope that these are the right commands. You can check the CCA contents using the command mdb 0x0027F800 2048 and hopefully, everything is cleared. If you want to read up on what those register writes did, check the reference manual for the CC2538 and read up on the flash controller in the memory section.

Use the bootloader

using a fork of OpenOCD, this is not needed anymore, see https://gist.github.com/hwhw/fc43892785aa84913d03495c97b0f25a#gistcomment-3518720

wiring up an UART

Use whatever UART adapter you like - e.g. maybe the built-in UART of the RPi you used for flashing? Or a simple USB-UART adapter? Make sure it has an adequate voltage level, then connect it as follows:

  • cc2538 UART RX is on PA0
  • cc2538 UART TX is on PA1
  • make sure you have a common ground connection and to power the cc2538 with a 3.3V source

run cc2538-bsl.py

https://github.com/JelmerT/cc2538-bsl will show you information about a connected cc2538 in bootloader mode and will allow flashing. Be sure that you've read the documentation. Especially about the bootloader backdoor configuration (also have a look into the cc2538 reference manual to learn about the exact way how to configure the backdoor enable pin). Note that using the JTAG method described above you do not need the bootloader backdoor. It might still be handy to enable it if possible, as this saves a step and some wiring.

@glsf91
Copy link

glsf91 commented Nov 28, 2020

I did not pass the error. I bought another CC2538.

@hwhw
Copy link
Author

hwhw commented Nov 28, 2020

@Ant1q: does that mean you're seeing the same errors? The spurious ACKs look a bit like connection problems. Too long/flimsy cables somewhere? Is there a stable power source for the CC2538? I found them to get a bit funny if their 3.3V rail is flaky. Do the errors only happen when trying to issue the program command? Is there a stable connection without giving the command to openocd?

@Ant1q
Copy link

Ant1q commented Nov 29, 2020

I have that

pi@raspberrypi:~/openocd $ sudo src/openocd -f tcl/interface/raspberrypi2-native.cfg -f tcl/target/cc2538.cfg -s tcl/ -c "program {123.hex}"
Open On-Chip Debugger 0.10.0+dev-01083-gb1fa3bf7 (2020-11-28-00:48)
Licensed under GNU GPL v2
For bug reports, read
        http://openocd.org/doc/doxygen/bugs.html
BCM2835 GPIO nums: swclk = 11, swdio = 25

Info : auto-selecting first available session transport "jtag". To override use 'transport select <transport>'.
Info : BCM2835 GPIO JTAG/SWD bitbang driver
Info : JTAG and SWD modes enabled
Info : clock speed 100 kHz
Info : JTAG tap: cc2538.jrc tap/device found: 0x8b96402f (mfg: 0x017 (Texas Instruments), part: 0xb964, ver: 0x8)
Info : JTAG tap: cc2538.cpu enabled
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (4) in DAP response
in procedure 'program'
** OpenOCD init failed **
shutdown command invoked

i have doublechecked connections between pins and chip legs, so i think the wiring is ok, and try different sources of 3.3v, still same problem.
But i noticed - my chip have different design, so i do not have PB6\PB7 pins. I have
cc2538

i connect RPi3 pins 19 and 21 to TDI and TDO on cc2538

@hwhw
Copy link
Author

hwhw commented Nov 30, 2020

These very probably are PB6/PB7. The quoted output you gave is still with running the "program" command, so I'm not sure if it is specific to that. The point where the error occurs is likely the cJTAG-to-JTAG switch, though, so it is probably something about the TDI/TDO lines. Can you visually inspect the module and possibly electronically probe that the pads are connected to the correct SoC pins and there's no funky business with other components on these lines?

@Roman-RV78
Copy link

У меня есть это

pi@raspberrypi:~/openocd $ sudo src/openocd -f tcl/interface/raspberrypi2-native.cfg -f tcl/target/cc2538.cfg -s tcl/ -c "program {123.hex}"
Open On-Chip Debugger 0.10.0+dev-01083-gb1fa3bf7 (2020-11-28-00:48)
Licensed under GNU GPL v2
For bug reports, read
        http://openocd.org/doc/doxygen/bugs.html
BCM2835 GPIO nums: swclk = 11, swdio = 25

Info : auto-selecting first available session transport "jtag". To override use 'transport select <transport>'.
Info : BCM2835 GPIO JTAG/SWD bitbang driver
Info : JTAG and SWD modes enabled
Info : clock speed 100 kHz
Info : JTAG tap: cc2538.jrc tap/device found: 0x8b96402f (mfg: 0x017 (Texas Instruments), part: 0xb964, ver: 0x8)
Info : JTAG tap: cc2538.cpu enabled
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (6) in DAP response
Error: Invalid ACK (4) in DAP response
in procedure 'program'
** OpenOCD init failed **
shutdown command invoked

Я дважды проверил соединения между контактами и ножками микросхемы, поэтому я думаю, что с проводкой все в порядке, и пробую разные источники 3,3 В, все та же проблема.
Но я заметил - мой чип имеет другой дизайн, поэтому у меня нет контактов PB6 \ PB7. я имею
cc2538

Я подключаю контакты 19 и 21 RPi3 к TDI и TDO на cc2538

Hello. Was it possible to solve this problem? I have the same connection problems

@glsf91
Copy link

glsf91 commented Dec 29, 2020

I had also a CC2538 with messages like: Error: Invalid ACK (6) in DAP response when using Pi with openocd. See my message of 17 Oct above.
I could flash this device with a Segger J-Link clone by using this

@znanev
Copy link

znanev commented Jan 1, 2021

I had exactly the same experience as @ant1k and @Roman-RV78.

Then I tried with a J-Link and when connecting to the target it complained something in the lines that the debug interface of the chip was locked. So I erased it and after that I couldn't connect to the target until I disconnected the USB interface of the J-Link and plugged it back in. After that connecting and identifying the chip was successful and I programmed it with the latest firmware and the device now functions as expected. So probably there are steps missing in OpenOCD (or instructions for using it with this particular MCU), which prevents flashing it via JTAG with a Raspberry Pi.

@hwhw
Copy link
Author

hwhw commented Jan 2, 2021

I am sorry it didn't work for you. It did for me. Very definitely. All the errors mentioned above do not really lead anywhere, it would need more debugging to see what the culprit is. As for now, I'm not even convinced it is just cabling and possibly a few passives on the modules in question getting in the way.

@janis-veinbergs
Copy link

janis-veinbergs commented Jan 24, 2021

In case anyone using raspberry pi 4 with Ubuntu.

I installed openocd on ubuntu 20.04 using apt-get install openocd. However this lacked bcm2835gpio interface/adapter resulting in error: Error: The specified debug interface was not found (bcm2835gpio). So had to manually get openocd from github and compile it with that support. After removing openocd package:

git clone https://git.code.sf.net/p/openocd/code openocd
cd openocd
./bootstrap
./configure --enable-maintainer-mode --enable-bcm2835gpio --enable-sysfsgpio
make -j4

Credit: https://movr0.com/2016/09/02/use-raspberry-pi-23-as-a-jtagswd-adapter/ (code blocks are white in that site, but if you select all text, text is revealed)

And then adjust config for Rpi4:

sudo cp /usr/local/share/openocd/scripts/interface/raspberrypi2-native.cfg /usr/local/share/openocd/scripts/interface/raspberrypi4-native.cfg
sudo vim /usr/local/share/openocd/scripts/interface/raspberrypi4-native.cfg

Change bcm2835gpio_peripheral_base and bcm2835gpio_speed_coeffs to these values:

bcm2835gpio_peripheral_base 0xFE000000
bcm2835gpio_speed_coeffs 236181 60

Credit: https://www.raspberrypi.org/forums/viewtopic.php?t=252551

@hwhw
Copy link
Author

hwhw commented Jan 25, 2021

Thank you! Oh yes, I gather the frequency scaling of the RPi might run havoc with timing, so this might be another thing to look at. Clocked data shouldn't be all that touchy but... well, very irregular timing might be an issue.

@SBA7
Copy link

SBA7 commented Mar 8, 2021

Yes, I have used this openocd: https://git.jim.sh/jim/openocd. That can make maybe a difference.
I had also troubles with the commands from this topic and the confusing shifts or not. So I tried this flash.

I did this:

pi@raspberrypi:~/openocdcc2538 $ git clone https://git.jim.sh/jim/openocd.git
cd openocd
./bootstrap
./configure --enable-sysfsgpio --enable-bcm2835gpio
make

Then edit the file tcl/target/cc2538.cfg
Adjust this 2 lines:
source [find tcl/target/icepick.cfg]
source [find tcl/target/ti-cjtag.cfg]

Hi, I did all exactly as posted above but getting only this:

pi@raspberrypi:~/openocd $ sudo src/openocd -f tcl/interface/raspberrypi2-native.cfg -f tcl/target/cc2538.cfg -s tcl/ -c "program {/home/pi/firmware/MODKAMV3.hex}"
Open On-Chip Debugger 0.10.0+dev-01083-gb1fa3bf7 (2021-03-08-17:31)
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
BCM2835 GPIO nums: swclk = 11, swdio = 25

Info : auto-selecting first available session transport "jtag". To override use 'transport select '.
Info : BCM2835 GPIO JTAG/SWD bitbang driver
Info : JTAG and SWD modes enabled
Info : clock speed 100 kHz
Error: JTAG scan chain interrogation failed: all ones
Error: Check JTAG interface, timings, target power, etc.
Error: Trying to use configured scan chain anyway...
Error: cc2538.jrc: IR capture error; saw 0x3f not 0x01
Warn : Bypassing JTAG setup events due to errors
Info : Listening on port 3333 for gdb connections
Error: JTAG scan chain interrogation failed: all ones
Error: Check JTAG interface, timings, target power, etc.
Error: Trying to use configured scan chain anyway...
Error: cc2538.jrc: IR capture error; saw 0x3f not 0x01
Warn : Bypassing JTAG setup events due to errors
** Programming Started **
Error: Target not examined yet
Error: auto_probe failed
embedded:startup.tcl:510: Error: ** Programming Failed **
in procedure 'program'
in procedure 'program_error' called at file "embedded:startup.tcl", line 575
at file "embedded:startup.tcl", line 510

Any idea what is wrong and how to fix it?

@mr-dxdy
Copy link

mr-dxdy commented May 2, 2021

@Roman-RV78 @Ant1q did you flash cc2538?

@olvint
Copy link

olvint commented May 5, 2021

У меня есть это
Info : JTAG tap: cc2538.cpu enabled
Error: Invalid ACK (6) in DAP response
in procedure 'program'
** OpenOCD init failed **
shutdown command invoked
Я дважды проверил соединения между контактами и ножками микросхемы, поэтому я думаю, что с проводкой все в порядке, и пробую разные источники 3,3 В, все та же проблема.
Но я заметил - мой чип имеет другой дизайн, поэтому у меня нет контактов PB6 \ PB7. я имею
cc2538
Я подключаю контакты 19 и 21 RPi3 к TDI и TDO на cc2538

Hello. Was it possible to solve this problem? I have the same connection problems

I had the same problem with CC2652. I tried lots of tweaks of openocd, no success.
I solved problem, I flashed my modules via uart. Modules that I brought had backdoor bootloader enabled (bsl) from factory!
In openocd I got this:
Info : JTAG tap: cc26x2.cpu enabled
Error: Invalid ACK (6) in DAP response
.....
DAP init failed.
....
I used this instruction for cc2652, but for cc2538 the same instruction exists.

Also, jusi in case , try to flash via openOCD activating bootloader by enabling bsl pin. Connect gnd and pin used for BSL. For CC2652 it is DIO_15.

@chuvihi
Copy link

chuvihi commented Mar 26, 2022

Indeed, this is a version of OpenOCD that has the flash loader for the cc2538 (in contrib/loaders/flash, plus glue code). That's marvellous! I'll add a corresponding note at the top of this document.

Hi, I'm trying this way using fork OpenOCD but I'm getting the following error.

Open On-Chip Debugger 0.11.0+dev-01935-gd295721ee-dirty (2022-03-26-10:02)
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
BCM2835 GPIO nums: swclk = 11, swdio = 25

Info : auto-selecting first available session transport "jtag". To override use 'transport select '.
Info : BCM2835 GPIO JTAG/SWD bitbang driver
Info : clock speed 100 kHz
Info : JTAG tap: cc2538.jrc tap/device found: 0x8b96402f (mfg: 0x017 (Texas Instruments), part: 0xb964, ver: 0x8)
Info : JTAG tap: cc2538.cpu enabled
Info : cc2538.cpu: hardware has 6 breakpoints, 4 watchpoints
Info : starting gdb server for cc2538.cpu on 3333
Info : Listening on port 3333 for gdb connections
Info : JTAG tap: cc2538.jrc tap/device found: 0x8b96402f (mfg: 0x017 (Texas Instruments), part: 0xb964, ver: 0x8)
Info : JTAG tap: cc2538.cpu enabled
Warn : Only resetting the Cortex-M core, use a reset-init event handler to reset any peripherals or configure hardware srst support.
target halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x0000136c msp: 0x20008000
** Programming Started **
Warn : no flash bank found for address 0x00000000
** Programming Finished **
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections

I don't know what I'm doing wrong!

I've could connect using telnet but once I'm connected I don't know what I have to do.
I've sent the messages mww 0x400D300C 0x7F800 and mww 0x400D3008 0x0205 but I think these are not doing anything because if I send mdb 0x0027F800 2048 this is what I've got.

0x0027f800: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027f820: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027f840: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027f860: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027f880: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027f8a0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027f8c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027f8e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027f900: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027f920: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027f940: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027f960: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027f980: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027f9a0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027f9c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027f9e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027fa00: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027fa20: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027fa40: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027fa60: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027fa80: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027faa0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027fac0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027fae0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027fb00: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027fb20: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027fb40: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027fb60: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027fb80: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027fba0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027fbc0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027fbe0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027fc00: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027fc20: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027fc40: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027fc60: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027fc80: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027fca0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027fcc0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027fce0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027fd00: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027fd20: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027fd40: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027fd60: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027fd80: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027fda0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027fdc0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027fde0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027fe00: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027fe20: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027fe40: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027fe60: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027fe80: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027fea0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027fec0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027fee0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027ff00: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027ff20: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027ff40: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027ff60: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027ff80: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027ffa0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027ffc0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0027ffe0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff

@photovirus
Copy link

This comment by @miqmago proved to be immensely helpful.

That openocd fork has full support for flashing cc2538, and config file works as well. The only trouble was to compile openocd on my M1 Macbook, as homebrew has wrong paths for capstone (includes extra nested capstone directory). I fixed it in source files locally (<capstone/capstone.h> → <capstone.h>); kinda ugly, but worked.

Since there's little info on JTAG talking to CC2538, I decided to describe everything I did in detail so other people can find it.

I used a modified @miqmago's config to flash a firmware image, and it worked beautifully. Hardware side, I used a Flipper Zero, which turned out to have a CMSIS-DAP implementation with JTAG support (among other things), so my config looks like this:

adapter driver cmsis-dap
adapter speed 4000

transport select jtag

cmsis_dap_backend usb_bulk

source [find tcl/interface/cmsis-dap.cfg]
source [find tcl/target/cc2538.cfg]

Then connect to ocd...

% src/openocd -f ./flash.cfg -s ./tcl
Open On-Chip Debugger 0.11.0+dev-01935-gd295721ee (2022-12-18-04:20)
Licensed under GNU GPL v2
For bug reports, read
	http://openocd.org/doc/doxygen/bugs.html
Warn : Interface already configured, ignoring
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Info : Using CMSIS-DAPv2 interface with VID:PID=0x0483:0x5740, serial=DAP_Rumo
Info : CMSIS-DAP: SWD  supported
Info : CMSIS-DAP: JTAG supported
Info : CMSIS-DAP: FW Version = 2.0.0
Info : CMSIS-DAP: Serial# = DAP_Rumo
Info : CMSIS-DAP: Interface Initialised (JTAG)
Info : SWCLK/TCK = 1 SWDIO/TMS = 1 TDI = 1 TDO = 0 nTRST = 0 nRESET = 1
Info : CMSIS-DAP: Interface ready
Info : clock speed 100 kHz

With connection set up, I fired up a telnet connection

% telnet localhost 4444
Trying ::1...
telnet: connect to address ::1: Connection refused
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Open On-Chip Debugger
> init
> targets
    TargetName         Type       Endian TapName            State
--  ------------------ ---------- ------ ------------------ ------------
 0* cc2538.cpu         cortex_m   little cc2538.cpu         running
> program ../JH_2538_2592_ZNP_USB_20211222.hex
cmsis-dap JTAG TLR_RESET
cmsis-dap JTAG TLR_RESET
cmsis-dap JTAG TLR_RESET
JTAG tap: cc2538.jrc tap/device found: 0x8b96402f (mfg: 0x017 (Texas Instruments), part: 0xb964, ver: 0x8)
JTAG tap: cc2538.cpu enabled
Only resetting the Cortex-M core, use a reset-init event handler to reset any peripherals or configure hardware srst support.
target halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x0000136c msp: 0x20008000
** Programming Started **
Flash write discontinued at 0x0023c800, next section at 0x0027ffd4
Adding extra erase range, 0x0027f800 .. 0x0027ffd3
** Programming Finished **

That was it, CC2538 flashed with JTAG and working as expected.

@dl8dtl
Copy link

dl8dtl commented Nov 16, 2023

Digging up that old discussion:
I have just migrated the CC2538 flash driver from jim.sh to the review site of the official OpenOCD repository, so it might hopefully get included into the official tree later on. The only changes compared to the jim.sh version are stylistic (OpenOCD's code checks are quite picky), and a small bit of documentation in the .texi file.
If someone wants to add a review:
https://review.openocd.org/c/openocd/+/8019
(You can log in there with your github ID.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment