Burning Zero bootloader with Beaglebone as SWD programmer

 

OpenOCD has support for bitbanging the jtag or swd protocol over gpio’s. So if you have a board that can run OpenOCD and on which you have access to gpio’s, you can use that as a jtag or swd programmer. The following describes how to use a beaglebone for this purpose but any board with 3V3 gpio’s (e.g. raspberry pie) will do…

bb-m0-z

I followed these instructions to set up the beaglebone. I opted for the debian file system.

Following list of things to install before building OpenOCD will probably save you from having to iteratively install packages untill OpenOCD builds. Of coarse the exact list will change if the initial content of the debian file system changes:

apt-get install autoconf libtool make pkg-config 

Get the OpenOCD sources:

git clone git://git.code.sf.net/p/openocd/code openocd-code

Build openOCD:

cd openocd-code
./bootstrap
./configure --enable-sysfsgpio
make 
make install

openocd is now installed in /usr/local/bin and the scripts it uses are in /usr/local/share/openocd/scripts.

We need an extra config file to describe the beaglebone programmer. I added it here: /usr/local/share/openocd/scripts/interface/bb.cfg. The choice of the gpio’s is up to you, I picked gpio 38 (i.e. gpio1[6], pin header P8_03) and 39 (i.e. gpio1[7], pin header P8_04) as swd_io and swd_sck respectively, so bb.cfg looks like this:

#
# Config for beaglebone interface
#
# This is best used with a fast enough buffer but also
# is suitable for direct connection if the target voltage
# matches bone's 3.3V
#
# Do not forget the GND connection.
#

interface sysfsgpio

# minimal swd setup
sysfsgpio_swdio_num     38
sysfsgpio_swclk_num     39

# (Did not manage to make srst work:)
# sysfsgpio_srst_num      45

Store dot-cc’s bootloader (samd21_sam_ba.bin) in a directory of your choice on the beaglebone.

In that dir, create a openocd.cfg file. OpenOCD will read this file to know what it has to do, and how. In our case the file instructs OpenOCD to use the beaglebone as interface (programmer) and tells it we’re programming a samd21 chip.

source [find interface/bb.cfg]
transport select swd

set CHIPNAME at91samd21g18
source [find target/at91samdXX.cfg]

# did not yet manage to make a working setup using srst
#reset_config srst_only
reset_config  srst_nogate

adapter_nsrst_delay 100
adapter_nsrst_assert_width 100

init
targets
reset halt

If you invoke openocd in this directory, you should see following output.

# openocd
Open On-Chip Debugger 0.10.0-dev-00040-gd52070c (2015-10-11-18:21)
Licensed under GNU GPL v2
For bug reports, read
        http://openocd.org/doc/doxygen/bugs.html
SysfsGPIO num: swdio = 38
SysfsGPIO num: swclk = 39
SysfsGPIO num: srst = 45
adapter speed: 500 kHz
adapter_nsrst_delay: 100
cortex_m reset_config sysresetreq
none separate
adapter_nsrst_delay: 100
adapter_nsrst_assert_width: 100
Info : SysfsGPIO JTAG/SWD bitbang driver
Info : SWD only mode enabled (specify tck, tms, tdi and tdo gpios to add JTAG mode)
Info : This adapter doesn't support configurable speed
Info : SWD IDCODE 0x0bc11477
Info : at91samd21g18.cpu: hardware has 4 breakpoints, 2 watchpoints
    TargetName         Type       Endian TapName            State       
--  ------------------ ---------- ------ ------------------ ------------
 0* at91samd21g18.cpu  cortex_m   little at91samd21g18.cpu  running
target state: halted
target halted due to debug-request, current mode: Thread 
xPSR: 0x21000000 pc: 0x000028f4 msp: 0x20002c00

OpenOCD is now constantly polling the device and it is ready to accept new instructions from us via telnet or gdb. You could log into openocd using telnet from your pc (or from the bone) and inspect memory, run code, start debugging…

If on the other hand you are just interested in burning the bootloader, you could add following line at the end of openocd.cfg and start openocd again.

at91samd bootloader 0; program samd21_sam_ba.bin verify reset; shutdown

OpenOCD should now produce following extra report about the flashing operation.

** Programming Started **
auto erase enabled
Info : SAMD MCU: SAMD21G18A (256KB Flash, 32KB RAM)
wrote 16384 bytes from file samd21_sam_ba.bin in 4.120137s (3.883 KiB/s)
** Programming Finished **
** Verify Started **
verified 6328 bytes in 0.575388s (10.740 KiB/s)
** Verified OK **
** Resetting Target **
shutdown command invoked

The M0 is now ready to receive sketches from the dot-cc IDE.
Remark: if you previously made the modification to the dot-cc lnker script from my previous post, don’t forget to undo this change.

In case you want to restore the dot-org bootloader, use this line as last line in openocd.cfg instead:

at91samd bootloader 0; program Bootloader_D21_M0_150515.hex verify reset; shutdown

23 thoughts on “Burning Zero bootloader with Beaglebone as SWD programmer

  1. A.Feichtner

    Thank you for this great tutorial. I followed you’re instructions but was using a bananapi pro board running archlinux.
    I used physical pins 37 (bcm gpio 26) and 38 (bcm gpio 20). Interface script looks like this:
    #[snip]
    interface sysfsgpio
    # minimal swd setup
    sysfsgpio_swdio_num 26
    sysfsgpio_swclk_num 20
    #[end]

    Reply
  2. C. Cross

    Hi Peter,

    Thanks as well for these instructions; it gives me hope that I won’t need to lay down an Atmel embedded debugger to flash the bootloader from my BBB.

    I’m having some issues, however, in that I have followed your guide precisely, but I’m not able to successfully “examine” the board from OpenOCD, so all subsequent functions fail as well. My setup is nearly identical to yours, the only difference being that I am using a Beaglebone Black instead of the original Beaglebone. I have tried several different pins, but to no avail. Is there something in your setup that I might be missing, such as manually handling the chip reset lines from the BBB, since OpenOCD doesn’t seem to be able to? I also did a comparison between the output from an atmel ice programmer (successful) and my unsuccessful bitbanging with a logic analyzer, and the output looks completely different. I also tried running openocd with nice –20 and just about everything killed on the BBB, no difference.

    Any guidance on what might be the issue? If needed, I can send my logic analyzer captures or other information.

    Much appreciated,
    Charles

    Reply
  3. petervho Post author

    On the BBB, many of the pins on header P8 are already used by the BBB board itself for the eMMC or the lcd (hdmi). Carefully select the gpio’s for openocd. If you would pick such a conflict pin, you will probably damage your BBB. So carefully read the section “BeagleBoneBlack Cape Compatibility” in the user manual. On header P8: pin 7 (gpio 66) as swdio and pin 8 (gpio 67) as swclk are OK. I gave it a quick try with these pins on BBB, and it worked.

    Reply
    1. C. Cross

      Hmm. I tried those exact pins, making sure no other drivers were using them, and my logic analyzer output looks a bit more sane now, but I’m still seeing the same openocd errors. Here are all of the details:

      uname -a: Linux openrov 4.1.8-ti-r18 #1 SMP PREEMPT Sat Sep 26 02:16:14 UTC 2015 armv7l GNU/Linux
      bb.cfg – Same as yours, except pins 66 and 67
      openocd.cfg – Same

      Logic Analyzer output: http://i.imgur.com/Jml6Til.png
      OpenOCD output: https://drive.google.com/a/openrov.com/file/d/0B4H3ENbMbJSPRDlDMWlHek5GTnc/view?usp=sharing
      Pingroup and Pins output: https://drive.google.com/a/openrov.com/file/d/0B4H3ENbMbJSPVU02d2d1eXZKY3M/view?usp=sharing

      I’ve tried on both an Arduino Zero Pro and a custom SAMD21 board, both of which are able to be programmed successfully using the ICE programmer. In both cases, the boards were properly powered and grounded.

      A bit stumped at this point; any more ideas? Thanks again for your help!

      Reply
  4. petervho Post author

    I did a git pull in my OpenOCD repo in order to have the most recent version. Guess what, I now have the same problem: the very first swd transaction fails like this:
    Debug: 243 152 bitbang.c:449 bitbang_swd_read_reg(): JUNK DP read reg 0 = ffffffff
    .
    Odd enough the problem persists if I go revert to my previous version using git reset –hard dfc6658. …

    Forget what I wrote above: it was a manipulation error: the M0’s USB cable was not connected, so I was trying without the target powered.

    I have now the same version as yours (git commit dfc6658), and it works fine on BBB.

    So the difference must be the target. You probably already triple checked wiring and power… Just spawning some ideas: for the Pro: I wonder whether the edbg chip nicely tristates the swd signals when it is or should be idle? (For my M0, it is simple: the swd headers are connected only to the samd). Do you have another target to test with? a due (never tried that myself though…)? incidently an stm32f4 discovery board? (those are easy to disconnect from their on board programmer…)

    Reply
  5. petervho Post author

    In case you want to try with an arduino due as target (this would rule out something is driving the swd pins against the bbb), I have checked that this works with the bbb setup.
    Here is an openocd.cfg that flashes a blink sketch (compiled with the ide) to the arduino due:

    source [find interface/bbb.cfg]
    transport select swd
    
    set CHIPNAME at91sam3X8E
    
    source [find target/at91sam3XXX.cfg]
    set _FLASHNAME $_CHIPNAME.flash
    flash bank $_FLASHNAME at91sam3 0x0080000 0 1 1 $_TARGETNAME
    
    #reset_config srst_only
    reset_config  srst_nogate
    adapter_nsrst_delay 100
    adapter_nsrst_assert_width 100
    
    init
    targets
    reset halt
    program Blink.ino.bin verify reset exit 0x0080000
    
    Reply
    1. C. Cross

      Good news, I was able to successfully flash the SAMD21 from pins 66 and 67 on my BBB by rolling back to d52070c like you mentioned. I’ve been touching base with Paul Fertser, who originally wrote the SWD GPIO interface, on the OpenOCD IRC and plan to provide him with a bisect when I get some free time and figure out where things went south. Your help has been invaluable in working through this, so thanks much! Will post an update here when normal functionality is restored, or we get to the bottom of what might be wrong with configuration changes, if the issue lies there.

      Reply
      1. C. Cross

        Also, my working configuration:

        bbb.cfg
        ——————–
        interface sysfsgpio
        sysfsgpio_swdio_num 66
        sysfsgpio_swclk_num 67

        openocd.cfg
        ——————–
        source [find interface/bbb.cfg]
        transport select swd
        source [find board/atmel_samd21_xplained_pro.cfg]

        reset_config srst_nogate
        adapter_nsrst_delay 100
        adapter_nsrst_assert_width 100

        init
        targets
        reset halt
        program samba.hex
        reset

  6. petervho Post author

    Good to hear it works. However I don’t think there is a regression: programming failed with the newer version because I made a manipulation error: the target was not powered. That is why it persisted when I reverted. I have edited my reply above. Sorry for the confusion. I think in your setup, something works intermittently and that coincidently it started to work after reverting. Could that be the case?

    Reply
    1. supaidakisu

      You were correct in that it was an intermittent issue, haha. Turns out I had a floating Reset pin, which worked some days and didn’t work other days. Learned this when I ported all of the flashing scripts to the Raspi2 and it exhibited some of the same issues, even with its bcm2385gpio driver. Got both working with the master branch now!

      Reply
  7. Pingback: Programming Microcontrollers using OpenOCD on a Raspberry Pi – Your Smart IOT

  8. SivaSubrahmanyam Nallamalli

    I am getting fallowing error after using openocd as per mentioned configuration. target board was nrf51822 chip with arm-cortex m0.
    Error: Could not initialize the debug port
    TargetName Type Endian TapName State
    — —————— ———- —— —————— ————
    0* nrf51.cpu cortex_m little nrf51.cpu unknown
    Error: Could not initialize the debug port

    interface/bb.cfg.
    interface sysfsgpio
    # minimal swd setup
    sysfsgpio_swdio_num 49
    sysfsgpio_swclk_num 117
    # (Did not manage to make srst work:)

    openocd.cfg
    # This is for BEAGLE BOARD running GPIO as an SWD to a Nordic Semiconductor nRF51 chip
    source [find interface/bb.cfg]
    transport select swd

    #set CHIPNAME nrf51822
    source [find target/nrf51.cfg]

    #reset_config srst_only
    reset_config srst_nogate

    adapter_nsrst_delay 100
    adapter_nsrst_assert_width 100

    init
    targets
    reset
    halt

    Reply
    1. Christopher Arena

      I came across the “soft_reset_halt” command. Where you might use “reset halt” try that. I was able to reset and halt my target, allowing the loading to work.

      Chris

      Reply
    2. petervho Post author

      In your script, ‘reset halt’ is one command so it should be on one line.

      I mean time I bought an nrf51822 dev board as I want to try out the m0 based nrf myself. So far I just tried a blink example. I could flash it by adding following lines to the openocd.cfg:
      flash write_image erase main.hex
      verify_image main.hex
      reset run
      shutdown

      Reply
  9. Christopher Arena

    What about nrst? why isn’t that working in the sysfs gpio? I’m having that problem. The clock and data are working but I need the reset to be able to debug.
    In my logic pro output, it looks like the reset signal is in input mode at about 2.4 Vdc. If I manipulate that bit myself, I can reset the target.
    Thanks!
    Chris

    Reply
  10. Bernd K

    You did a great job with this tutorial. Thanks a lot.

    I managed to burn the samd21_sam_ba.bin bootloader withou trouble and it works. I am using a Raspberry Pi2 and reduced adapter speed to 100 kHz to prevent wiering faults.

    But I was not able to get back to the M0 bootloader. To me it looks like openocd is interpreting the hex-file not correct. Any hints?
    Trying to burn Bootloader_D21_M0_150515.hex I get the following output from openocd:

    open On-Chip Debugger
    > targets
    TargetName Type Endian TapName State
    — —————— ———- —— —————— ————
    0* at91samd21g18.cpu cortex_m little at91samd21g18.cpu halted
    > at91samd bootloader 0
    > program Bootloader_D21_M0_150515.hex verify
    SWD DPIDR 0x0bc11477
    target halted due to debug-request, current mode: Thread
    xPSR: 0x01000000 pc: 0x000001a0 msp: 0x20007fdc
    ** Programming Started **
    auto erase enabled
    SAMD MCU: SAMD21G18A (256KB Flash, 32KB RAM)
    no flash bank found for address 40000
    wrote 262144 bytes from file Bootloader_D21_M0_150515.hex in 36.618279s (6.991 KiB/s)
    ** Programming Finished **
    ** Verify Started **
    at91samd21g18.cpu — clearing lockup after double fault
    error executing cortex_m crc algorithm
    SWD DPIDR 0x0bc11477
    Failed to read memory at 0x00040000
    embedded:startup.tcl:476: Error: ** Verify Failed **
    in procedure ‘program’
    in procedure ‘program_error’ called at file “embedded:startup.tcl”, line 520
    at file “embedded:startup.tcl”, line 476
    >

    Reply
  11. petervho Post author

    That is weird indeed. Apparently openocd fills the whole 256KB flash. Is the hex file intact?
    You could convert the hex into a bin file and program that. I tend to use the objcopy that comes with arduino to do this:
    arm-none-eabi-objcopy -I ihex -O binary Bootloader_D21_M0_150515.hex Bootloader_D21_M0_150515.bin

    Reply
    1. Bernd K

      Thnaks a lot! The .hex file was wrong. I made a fault downloading it from github. Sorry, I did not check that.
      Every thing works fine.

      Reply
  12. adev

    Hi Peter,

    Thank you for this excellent tutorial. I am currently working with a setup of BBB Wireless and Arduino M0 where I would like to be able to deploy OTA updates to the SAMD21 bootloader / sketches via the BBBW. Insofar, I have been able to achieve the OTA bootloader via openocd as you explained, only with the d52070c commit of the master branch of openocd on the standard debian distro of BBBW (similar issues C. Cross posted for his case – d52070c solved the problem for me as well).

    However, I have problems when I try to upload sketches. It seems that uploading sketches compromises the bootloader (by erasure) or is just misplaced in memory. To upload a sketch I have been looking at the ArduinoCore-samd file https://github.com/arduino/ArduinoCore-samd/blob/master/platform.txt (line 157) to get the offset.

    Here it is my openocd_sketch_upload.cfg:
    source [find interface/bbb.cfg]
    transport select swd
    set CHIPNAME at91samd21g18
    set ENDIAN little
    source [find target/at91samdXX.cfg]
    reset_config srst_nogate
    adapter_nsrst_delay 100
    adapter_nsrst_assert_width 100
    init
    targets
    reset halt
    program Blink_Export.ino.arduino_zero.bin verify reset exit 0x2000

    and here is the output:
    debian@beaglebone:~/tests/arduino_sketch_test$ sudo openocd -f arduino_zero_sketch_upload.cfg -d2
    Open On-Chip Debugger 0.10.0-dev-00040-gd52070c (2017-06-05-01:15)
    Licensed under GNU GPL v2
    For bug reports, read
    http://openocd.org/doc/doxygen/bugs.html
    debug_level: 2
    SysfsGPIO num: swdio = 66
    SysfsGPIO num: swclk = 67
    adapter speed: 500 kHz
    adapter_nsrst_delay: 100
    cortex_m reset_config sysresetreq
    none separate
    adapter_nsrst_delay: 100
    adapter_nsrst_assert_width: 100
    Info : SysfsGPIO JTAG/SWD bitbang driver
    Info : SWD only mode enabled (specify tck, tms, tdi and tdo gpios to add JTAG mode)
    Warn : gpio 67 is already exported
    Warn : gpio 66 is already exported
    Info : This adapter doesn’t support configurable speed
    Info : SWD IDCODE 0x0bc11477
    Info : at91samd21g18.cpu: hardware has 4 breakpoints, 2 watchpoints
    TargetName Type Endian TapName State
    — —————— ———- —— —————— ————
    0* at91samd21g18.cpu cortex_m little at91samd21g18.cpu running
    target state: halted
    target halted due to debug-request, current mode: Thread
    xPSR: 0x01000000 pc: 0x00000614 msp: 0x20007ffc
    target state: halted
    target halted due to debug-request, current mode: Thread
    xPSR: 0x01000000 pc: 0x00000614 msp: 0x20007ffc
    ** Programming Started **
    auto erase enabled
    Info : SAMD MCU: SAMD21G18A (256KB Flash, 32KB RAM)
    Warn : Adding extra erase range, 00000000 to 0x00001fff
    wrote 24576 bytes from file Blink_Export.ino.arduino_zero.bin in 8.606619s (2.789 KiB/s)
    ** Programming Finished **
    ** Verify Started **
    verified 9704 bytes in 0.855542s (11.077 KiB/s)
    ** Verified OK **
    ** Resetting Target **
    shutdown command invoked

    Have you tried to upload a sketch in this way (I saw your suggestion for Due) for M0 ? I am stuck at this point.

    Best,
    Andrei

    Reply
  13. petervho Post author

    Andrei,

    It looks like your boot loader is ‘auto erased’:
    ** Programming Started **
    auto erase enabled

    The command ‘at91samd bootloader 0’ in my openocd.cfg to burn the bootloader script removes bootloader protection.
    Try to put it back in after you program the bootloader, so adapt the bootloader burning script like this:

    at91samd bootloader 0
    program samd21_sam_ba verify
    at91samd bootloader 8192
    reset
    shutdown

    This protects the first 0x2000 (8192) bytes of the flash.
    Can’t try it out soon myself though…

    Interesting project. Btw what is the ‘OTA bootloader’? Is it the regular arduino at91samd bootloader? (so the ota mains you go over the air between a pc and the bbb and go wired between the latter and the m0?)

    Peter

    Reply
    1. adev

      Hi Peter,

      Thanks a lot for the prompt reply and sorry for my delay, I was travelling and could not try out your suggested fix.

      Bottom line it did not work with the openocd version I was running with as I was always receiving the following NVM lock error and the entire data at the beginning of the section was erased and thus the bootloader corrupted.

      ** Programming Started **
      auto erase enabled
      Info : SAMD MCU: SAMD21G18A (256KB Flash, 32KB RAM)
      Warn : Adding extra erase range, 00000000 to 0x00001fff
      Error: SAMD: NVM lock error
      Error: Failed to erase row containing 00002000

      Playing around with the commands I saw that the entire flash partition at the beginning was seen as a huge block in comparison to the size of the bootloader. Splitting it such that one could write the sketch at the right position was leading to erasing the entire memory partition and thus the bootloader itself, hence the initial error.

      I knew that the Arduino CC community has its own port of openocd, and look into the diffs of the port (still running on 0.9.0, but that is irrelevant as far as at91samd flasher driver is concerned) wrt the master. There are 2 fundamental commits which fix this problem.

      https://github.com/arduino/OpenOCD/commit/d6cb4bf833a32b87896f1745c01bba594d1cec26 (most important)
      https://github.com/arduino/OpenOCD/commit/76b0521e59cb535bbdf36ccf328412ccdd933a20 (second one)

      Hence, I just built the openocd arduino branch (https://github.com/arduino/OpenOCD/tree/arduino) on the BBBW and retried with the original cfgs I had and it worked without any problem. Afterwards, I included your changes, since they made sense related to the bootloader protection, and also cleaned the sketch uploader.

      Here are the final versions for the interested ones:

      arduino_mzero_bootloader.cfg:
      source [find interface/bbb.cfg]
      transport select swd
      set CHIPNAME at91samd21g18
      source [find target/at91samdXX.cfg]
      reset_config srst_nogate
      adapter_nsrst_delay 100
      adapter_nsrst_assert_width 100
      init
      targets
      reset halt
      at91samd bootloader 0
      program samd21_sam_ba.bin verify
      at91samd bootloader 8192
      reset
      shutdown

      arduino_mzero_sketch_uploader.cfg:
      source [find interface/bbb.cfg]
      transport select swd
      set CHIPNAME at91samd21g18
      set ENDIAN little
      source [find target/at91samdXX.cfg]
      reset_config srst_nogate
      adapter_nsrst_delay 100
      adapter_nsrst_assert_width 100
      program Blink_Export.arduino_zero.bin verify reset 0x2000
      shutdown

      Your understanding of my OTA approach is correct. This deployment will be used on some edge devices of a low power sensor network, where distributed algorithms could be deployed (running on BBBW).

      Best and thanks,
      Andrei

      Reply
      1. petervho Post author

        That is a really interesting insight. Thanks.
        I wonder why this patch was not upstreamed. Maybe the arduino devs did simply have no time to deal with it. Or maybe the solution is not (yet) completely worked out to be genericly applicable, outside the arduino ide…

Leave a comment