OpenOCD for programming nRF51822 via nothing but wires and a Raspberry Pi

nRF51822 BoardThe Hardware here is simple and cheap, it can be done with any Pi, though I used a Pi Zero.  For me, it was free because I had the Pi Zero and the wire.

The default pins are:

Ground                        to Ground
3.3V power              to 3.3V power
Pi header pin 22  to swclk
Pi header pin 18   to swdio

At the time this was written, OpenOCD didn’t have bcm2835gpio in the main release so we git clone it.
The debugger/programmer install is:

cd ~/Downloads
sudo bash
apt-get install libtool libusb-dev libusb-1.0 autoconf automake texinfo
git clone git:// openocd-code
cd openocd-code/
./configure --enable-sysfsgpio --enable-bcm2835gpio
make install

The raspberrypi-native.cfg didn’t have SWD support, so add them from raspberrypi2-native.cfg.  I needed to comment out:

#bcm2835gpio_jtag_nums 11 25 10 9

and to add:

# Each of the SWD lines need a gpio number set: swclk swdio
# Header pin numbers: 22 18
bcm2835gpio_swd_nums 25 24

The peripheral base address is different on some Pi models.  You can check yours by grabbing the middle 8 digits from:

hexdump -s4 -n4 -e '"0x" 4/1 "%02X""\n"" "' /proc/device-tree/soc/ranges

Edit it with:

vi /usr/local/share/openocd/scripts/interface/raspberrypi-native.cfg

Check to be sure your default speed is 700Mhz, or adjust bcm2835gpio_speed_coeffs:

cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq

To run openocd:

openocd -f interface/raspberrypi-native.cfg -c "transport select swd; set WORKAREASIZE 0" -f target/nrf51.cfg

If it worked correctly, the last line should read (nothing before this indicates you successfully connected):

Info : nrf51.cpu: hardware has 4 breakpoints, 2 watchpoints

To connect from your development platform:

telnet pi0 4444

To burn the code, we need two files, in my case both are on a different machine (host) so I use sshfs to mount that.

mkdir ~/host
sshfs user@host:/ ~/host

Since the path is rather long, I break it in two and store into variables. This is the proximity example from the SDK:

set BASEPATH ~/host/home/user/Downloads/nRF5_SDK_11.0.0_89a8197
set SOFTDEV $BASEPATH/components/softdevice/s130/hex/s130_nrf51_2.0.0_softdevice.hex
set HEXFILE $BASEPATH/examples/ble_peripheral/ble_app_proximity/pca10028/s130/armgcc/_build/nrf51422_xxac_s130.hex
#halt, erase, write softdevice and binary, verify both, run it.
halt; nrf51 mass_erase; sleep 500; flash write_image $SOFTDEV 0; flash write_image $HEXFILE 0; verify_image $SOFTDEV 0; verify_image $HEXFILE 0; reset run

At this point, your sniffer or phone or whatever should see the Nordic_Prox device.


11 thoughts on “OpenOCD for programming nRF51822 via nothing but wires and a Raspberry Pi

  1. Hi,

    I’m trying to program a nRF51822 board following this tutorial using OpenOCD in a Raspberry PI.

    I have been able to burn the compilated ble_app_proximity example code (in .hex format) that the SDK contains, and in that case the nRF51822 is detected correctly by the nRF Connect iOS app. However, if I compile the main.c code contained in the same example of the SDK with Segger Embedded Studio, and I burn the .hex output in the same way that I did before, the burn is successful, but nothing is detected by the nRF Connect iOS app. I have also tried following your tutorial “INSTALLING GCC-ARM FOR USE WITH NORDIC NRF8122 NRF5_SDK_11.0.0_89A8197” but I have the same result. Do you know what could be wrong?

    Thanks in advance !


    1. It’s purely a guess but sounds like maybe you have either set up the wrong address, or didn’t include both your code and the softdevice library code. I’ve never tried Segger, so I’m probably not the right place for help with that.


      1. Thanks so much for your response. Now, instead of using Segger I’m using gcc, as you explain in a related post. However, the result is the same. I also think that it could be a problem with the address, did you change them in the linker script when compiling it with gcc?

        I’ve tried changing this:

        FLASH (rx) : ORIGIN = 0x1C000, LENGTH = 0x25000
        RAM (rwx) : ORIGIN = 0x20002080, LENGTH = 0x5f80

        To this:

        SOFTD (rx) : ORIGIN = 0x00000000, LENGTH = 0x1C000
        FLASH (rx) : ORIGIN = 0x0001C000, LENGTH = 0x24000
        RAM (rwx) : ORIGIN = 0x20002800, LENGTH = 0x5f80

        However, the problem persists. As I told, if I burn the compilated .hex file together with the completed soft device s130, both included in the SDK, it works. But if instead of the compilated .hex file contained in the SDK, I burn the .hex file that I get after compiling with gcc, together with the same soft device, it doesn’t. I guess the problem is with the address, but I can’t figure out how to solve it.

        Thank you very much !


        1. Sergio, once the pre-built .hex file from the demonstration is complete, you’ve pretty much left the territory of this blog. Your question over on devzone is a more appropriate location to discuss getting a good .hex to be burned.


  2. It works great! Thanks for the tut.

    My only question: is it possible to log firmware output the same way as RTT J-link doing? I tried to use GDB over OpenOCD for this but without any success.


    1. Yes, GDB can do debug prints like Segger’s RTT can. That’s not really a transport feature but a debugger feature. The option I use for GDB to connect to OpenOCD is -target-select remote pi:3333


    1. The default base address provided in the openocd config files is for the pi B or B+, make sure you set it to 0x3F000000 when using a pi 2B. If the base address is right, having the errors will be required to diagnose this.


      1. root@raspberrypi:/home/pi/Downloads/openocd-code# cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq
        root@raspberrypi:/home/pi/Downloads/openocd-code# hexdump -s4 -n4 -e ‘”0x” 4/1 “%02X””\n”” “‘ /proc/device-tree/soc/ranges
        root@raspberrypi:/home/pi/Downloads/openocd-code#openocd -f interface/raspberrypi2-native.cfg -c “transport select swd; set WORKAREASIZE 0” -f target/nrf51.cfg
        Open On-Chip Debugger 0.10.0
        Licensed under GNU GPL v2
        For bug reports, read
        BCM2835 GPIO nums: swclk = 25, swdio = 24
        BCM2835 GPIO config: srst = 18
        srst_only separate srst_gates_jtag srst_push_pull connect_deassert_srst
        cortex_m reset_config sysresetreq
        adapter speed: 1000 kHz
        Info : BCM2835 GPIO JTAG/SWD bitbang driver
        Info : SWD only mode enabled (specify tck, tms, tdi and tdo gpios to add JTAG mode)
        Info : clock speed 1001 kHz
        in procedure ‘init’
        in procedure ‘ocd_bouncer’

        here is the error the base adress seeems to be alright


  3. Licensed under GNU GPL v2
    For bug reports, read
    BCM2835 GPIO nums: swclk = 25, swdio = 24
    cortex_m reset_config sysresetreq
    adapter speed: 1000 kHz
    Info : BCM2835 GPIO JTAG/SWD bitbang driver
    Info : SWD only mode enabled (specify tck, tms, tdi and tdo gpios to add JTAG mode)
    Info : clock speed 1006 kHz
    Info : SWD DPIDR 0x00142cc4
    Error: Could not initialize the debug port
    The error generated. Could you asses the problem?


    1. I’m not seeing the cause of problem. I have used a Pi 2B and did not experience this issue, but we are using different config files, I start with interface/raspberrypi-native.cfg and adjust as in the main text above. My suggestion is to go to freenode IRC channel #openocd and ask there. Have a pastebin ready with your raspberrypi2-native.cfg, nrf51.cfg, and the above errors starting with your command line and including any commands you issue prior to the error.


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s