SWD protocol - talk to BangleJS 2 over cable

Posted on
  • Hello, this is a followup to this post https://forum.espruino.com/conversations/378217/#16732065

    SWD protocol is typically used to debug software running on ARM Cortex-M CPUs however it can be also easily used for just doing direct access to memory (RAM, internal flash).

    Bangle 2 has SWD debug pins routed to USB data pins of charging cable so with some extra software and hardware this can be used for talking to Bangle 2 over cable.

    SWD uses 2 pins similar to I2c or bidirectional SPI and the protocol is relatively simple.
    Best introduction I found is here http://markding.github.io/swd_programing_sram/
    Full docs including PDF download https://developer.arm.com/documentation/ihi0031/a?lang=en

    I wrote initial prototype of basic memory read/write over SWD here
    https://github.com/fanoush/EspruinoBoards/blob/master/STLINKV2/swd.js
    I am using STLink V2 clone dongle running Espruino but it should be usable on any ARM based Espruino device with 2 GPIOs available.

    For now I can power up/down the interface and read/write memory

    basic usage is

    swd_setup(clkPin, dioPin)
    swd_init().toString(16) // should print 2ba01477 for cortex M3/4 targets
    dap_poweron() // powers up MEM-AP
    readmem32(0x10001014) // should print bootloader address of nrf52 in UICR
    

    So far there are some small optimizations for speed - for sending 8 or 32 bits shiftOut is used, for receiving of 32 bits software SPI is used (just clk and miso, spi mode 2 seems to work). Unfortunately the protocol is not aligned to byte boundary due to 3bit ACK response in the middle and parity bit in the end so those extra bits are sent by toggling gpios directly.

    Next step is allocating some memory buffer on target device with some signature header (like Segger RTT does) and searching for it over SWD and passing blocks of data over it in both directions.

    One goal is to use any espruino with USB or serial to act as serial to SWD adapter to have Espruino console (and WebIDE) running over it via WebSerial in Chrome.

  • Thats very neat -will it be fast enough to use for loading code into flash?

  • The swd in nrf52 is designed for up to 8MHz https://devzone.nordicsemi.com/f/nordic-q-a/54961/nrf52840-programming-speed , typically SWD dongles use 1MHz, limit is probably also related to wire length. I did not see issues previously with bangle2/Q3 charging cable and SWD dongles used with openocd running at 1MHz. The overhead of the protocol is 14 extra bits with each 32bit transfer https://github.com/MarkDing/swd_programing_sram#32-successful-transaction-operation , when reading/writing in automatic incremental mode just one packet is needed to send/receive next 32bit value.

    Of course the software must match the speed. Also from initial testing I see the MEM-AP transfer from memory produce some initial timeouts - not sure how many of those there will be when pushing the interface to maximum. When CPU is not stopped the transfer shares the AHB bus with code that is running and needs to use RAM/flash for that , see picture at https://infocenter.nordicsemi.com/topic/com.nordic.infocenter.nrf52832.ps.v1.1/dif.html?cp=4_2_0_15#debugandtrace

    Not sure if any of that answered the question, though ;-)

    Direct writing to (internal) flash over SWD can be either done by toggling flash NVMC registers directly or another way that openocd is using is to upload some flashing code stub to ram then just send data block to ram and let the CPU do the flashing. However I suppose the easiest way is to make espruino console working over SWD and then push data over it.

  • This looks really exciting!

    One goal is to use any espruino with USB or serial to act as serial to SWD adapter to have Espruino console (and WebIDE) running over it via WebSerial in Chrome.

    That would be great! I guess it's even possible that things like ESP8266/ESP32 could expose it over wifi too.

    This opens a bunch of possibilities, and not just for serial... I really liked the idea of being able to control external hardware from the Bangle's pins on the back - but I guess a super cheap micro would be able to handle polling/writing via SWD and then setting up GPIO accordingly.

  • I should add that I think recently some mbed-compatible SWD programmers (inc micro:bit?) started shipping with 'Web USB' compatible firmware. So that could be an option as well to handle the PC->SWD side (although it's not as cool as this).

  • I got back to this and implemented SWDCON console for Espruino devices (should work on any ARM Cortex with SWD). Currently it sits in https://github.com/fanoush/Espruino/tree/f-swdcon and somehow works for me with openocd
    When it is built in and enabled in board file, it can be used like this (see also openocd docs 15.6 Real Time Transfer (RTT)):

    rtt setup 0x20000000 262144 "SEGGER RTT"
    rtt polling_interval 50
    rtt start
    rtt server start 2222 0
    

    then you can telnet to localhost port 2222 press enter and then wake up device if it is sleeping and the console should be switched and work. For telnet command it is better to switch it to character mode via ctrl+] and typing mode character. For better usage with telnet the console would need to implement some telnet protocol handshaking but not sure it is worth it. Also due to this there is some garbage in the console when the mode is switched so just press enter again (and/or ctrl+c).

    To turn it back off execute something like Serial1.setConsole() or for Bangle2 setConsole(null,true) in the SWD console and then something like

    rtt stop server 2222
    rtt stop
    mww 0xE000EDF0 0xA05F0000; nrf52.dap dpreg 4 0 ; shutdown
    

    This is meant to work also with BANGLE 2 devices with broken Bluetooth which are otherwise inaccessible. For those there is some extra code to force the console switch even if it is already forced to null - which is the state when you turn off the programmable checkbox in settings. For now it is not usable with WebIDE as it does not support telnet but when I'll finish the custom SWD/RTT debugger host implemented in espruino javascript then any other espruino device can redirect its console to this and act as a proxy to Bangle2 over two GPIO pins.Then one could install apps also over cable.

  • BTW if you have Bangle 2 with SWD debugger working then a latest test build is here https://github.com/fanoush/Espruino/actions/runs/10298290054/job/28503123641
    https://github.com/fanoush/Espruino/actions/runs/10298290054/artifacts/1789295635
    For windows it works with openocd binary build from https://github.com/openocd-org/openocd/releases/ , either the 0.12.0 or the latest one which has extra parameter for RTT server which can enable telnet character mode automatically as per https://stackoverflow.com/questions/273261/force-telnet-client-into-character-mode , then
    rtt server start 2222 0 \377\375\042\377\373\001 enables it with some extra more garbage initially sent to espruino console

    So to activate it you should switch off programmable checkbox in setting, this should force console to null which has a special override in the SWDCON code. Or you can reboot to recovery menu - this does not force console to anything so the switch works too.

  • This is great, thanks! I'm not getting that much time for work these few weeks with school holidays, but in a month or so I hope to be able to look into this further. On ARM targets this could be a really neat thing to build in.

    I seem to recall at some point you had some reasonably simple code to make Espruino actually communicate with another device using SWD, although I'm not sure if that did RTT? One very cool addition would be if we had a microcontroller that would effectively act as a USB Serial -> RTT bridge...

  • I seem to recall at some point you had some reasonably simple code to make Espruino actually communicate with another device using SWD, although I'm not sure if that did RTT

    Yes, as I have this working now and can test it on something I'll do the RTT part in that. The Inline C prototype is here https://gist.github.com/fanoush/4a5dcf777503461297cedf7e21e3c6b3 but the performance critical code can be possibly moved to this SWDCON library or maybe another SWDHost library

    if we had a microcontroller that would effectively act as a USB Serial -> RTT bridge

    Yes, or even BLE-> RTT bridge. I guess some very cheap easily programmable Espruino board like the ESP32-C3 mini can act as this. I am using STLINK V2 dongles but these needs to be programmed over SWD so are not that easy to make at home for typical Bangle 2 user.

  • On ARM targets this could be a really neat thing to build in.

    It uses static buffers for up/down communications so takes away precious RAM but is easy to change to use some flat buffer variable. On Bangle 2 I imagine another checkbox in setting that could allocate buffer and enable this and then free it when disabled.

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

SWD protocol - talk to BangleJS 2 over cable

Posted by Avatar for fanoush @fanoush

Actions