{"id":20995345,"url":"https://github.com/todbot/samd21-programming-notes","last_synced_at":"2025-10-11T22:57:04.092Z","repository":{"id":66886500,"uuid":"112024463","full_name":"todbot/samd21-programming-notes","owner":"todbot","description":"SAMD21 programming notes","archived":false,"fork":false,"pushed_at":"2024-04-06T00:22:12.000Z","size":1662,"stargazers_count":22,"open_issues_count":1,"forks_count":5,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-03-07T02:48:13.409Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/todbot.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2017-11-25T18:09:54.000Z","updated_at":"2024-05-01T03:17:49.000Z","dependencies_parsed_at":"2023-05-12T20:30:45.262Z","dependency_job_id":null,"html_url":"https://github.com/todbot/samd21-programming-notes","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/todbot%2Fsamd21-programming-notes","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/todbot%2Fsamd21-programming-notes/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/todbot%2Fsamd21-programming-notes/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/todbot%2Fsamd21-programming-notes/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/todbot","download_url":"https://codeload.github.com/todbot/samd21-programming-notes/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243410229,"owners_count":20286387,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-19T07:23:09.078Z","updated_at":"2025-10-11T22:56:59.072Z","avatar_url":"https://github.com/todbot.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# SAMD21 Programming Notes\n\nExplorations into how to program SAMD21 chips like those in\n[Trinket M0](https://learn.adafruit.com/adafruit-trinket-m0-circuitpython-arduino/pinouts), \nArduino Zero, etc.\n\nHow to program a SAMD21 (or other ARM chip really) using a variety of methods, \nin order to burn a [UF2 bootloader](https://github.com/Microsoft/uf2-samd21/) \nor my own programs.\n\n\nWays to program a SAMD21 board: (e.g. Trinket M0, QTPy M0, etc)\n\n- Reprogram bootloader using UF2\n- Program with Arduino sketches using uf2\n- Talk to chip w/ GDB using JTAG/SWD programmer (OpenOCD / JLink via commandline, no Atmel Studio)\n- Reprogram bootloader with JTAG/WWD programmer (OpenOCD / JLink via commandline, no Atmel Studio)\n- Program chip with Arduino sketch using JTAG/SWD programmer\n\n\nProgress so far...\n\n### Reprogram bootloader via UF2 - Trinket M0 ###\n\n1. Double-click button on Trinket M0 to get into UF2 bootloader\n  - LED will heartbeat\n  - Trinket M0 shows up as \"TRINKETBOOT\" disk\n2. Create new UF2 bootloader\n  ```\n  git clone https://github.com/Microsoft/uf2-samd21/\n  cd uf2-samd21\n  make BOARD=trinket\n  ```\n\n3. Copy resulting file `update-bootloader.uf2` to disk\n4. Tada, new bootloader installed\n5. Edit file `boards/trinket/board_config.h` to change bootloader id strings\n\n### Program Arduino sketch with UF2 - Trinket M0 ###\n\n1. Create sketch as normal\n2. Open build tmp directory and copy out .bin file\n3. Use uf2-samd21 'bin2uf2.js' script (from 'scripts' in [uf2-samd21 repo](https://github.com/Microsoft/uf2-samd21/))\nto convert to uf2:\n  ```\n  node uf2-samd21/scripts/bin2uf2.js sketch_nov24a.ino.bin sketch_nov24a.uf2\n  ```\n4. Copy uf2 file to TRINKETBOOT and tada programmed!\n5. TODO: Look into what bin2uf2 is doing\n\n### Connecting Jlink JTAG/SWD to Trinket M0 ###\n\n1. Solder pads to SWD \u0026 SWC pins on back of Trinket M0\n2. Connect following pins from JLink to Trinket M0:\n```\n  | black | Jlink Gnd   | Trinket M0 Gnd pin |\n  | red   | Jlink VTref | Trinket M0 3v3 pin |\n  | green | Jlink SWDIO | Trinket M0 SWD solder pad |\n  | blue  | Jlink SWCLK | Trinket M0 SWC solder pad |\n```\n\n3. Power Trinket M0 via USB. Power Jlink via USB.\n\n\"VTref\" is used to detect target power is applied. It is a signal TO the programmer.\n\n\u003cimg src=\"./imgs/jlink-swd-pinout-from-cable.png\" width=\"400\"\u003e\n\n\u003cimg src=\"./imgs/jlink-swd.jpg\" width=\"400\"\u003e\n\n\u003cimg src=\"./imgs/trinketm0-swd.jpg\" width=\"400\"\u003e\n\n\n### Update bootloader via JLink JTAG/SWD w/ uf2-samd21 - Trinket M0 ###\n\n1. Connect Jlink to Trinket M0 as above\n3. Install openocd with `brew install openocd`\n4. Modify `uf2-samd21/scripts/dbgtool.js` to use Jlink instead of EDBG.\n   - Change openocd path to use 0.1.0 or better:\n         let openocdBin = \"/usr/local/bin/openocd\"\n   - Modify `uf2-samd21/scripts/dbgtool.js`:\n         let zeroCfg = '/Users/tod/projects/samd/openocd-scripts/samd21-jlink.cfg'\n 5. Must have new openocd-script [samd21-jlink.cfg](./samd21-jlink.cfg):\n 6. Run \"`make burn`\" in `uf2-samd21`\n 7. Alternatively, run:\n  ```\n  cd uf2-samd21\n  node ./scripts/dbgtool.js fuses\n  node ./scripts/dbgtool.js ./build/trinket/bootloader.bin\n  ```\n\n### Update bootloader via OpenOCD and JLink on commandline - Trinket M0\n\n1. Install `openocd` as above\n2. Get [openocd_jlink_samd21.cfg](./openocd_jlink_samd21.cfg)\n3. Get the `bootloader-trinket_m0-v3.16.0.bin` file from [adafruit/uf2-samdx1](https://github.com/adafruit/uf2-samdx1/releases)\n4. Connect Jlink to Trinket M0 as above\n5. Program on commandline:\n   ```\n   openocd -f ./openocd_jlink_samd21.cfg \\\n      -c \"init; targets; halt; \" \\\n      -c \"at91samd bootloader 0;\" \\\n      -c \"program bootloader-trinket_m0-v3.16.0.bin verify;\" \\\n      -c \"at91samd bootloader 8192; reset; shutdown\" \n    ```\n    \n    **NOTE:** the `at91samd bootloader 0;` disables bootloader protection and \n    allows you to rewrite the bootloader. The `at91samd bootloader 8192;`\n    re-enables bootloader protection.\n    (from this [adfruit forum post](https://forums.adafruit.com/viewtopic.php?t=204268))\n    \n6. Can also erase entire chip  (assuming no bootloader lock):\n   ```\n   openocd -f ./openocd_jlink_samd21.cfg -c \"init; targets; at91samd chip-erase; shutdown\"`\n   ```\n   or in a more general way:\n   ```\n   openocd -f ./openocd_jlink_samd21.cfg -c \"init; targets; flash erase_sector 0 1 last; shutdown\"`\n   ```\n   \n7. Or list which targets are connected:\n   ```\n   openocd -f openocd_jlink_samd21.cfg -c \"init; targets; shutdown\"\n   ```\n\n\n- TODO: Get programming to work for Arduino sketches\n  (specifically, can program but sketch doesn't run)\n\n8. TODO: try:\n\n   `-c \"init; targets; reset halt; program sketch.bin 0x00002000`\n\n### Update bootlaoder via OpenOCD and Atmel ICE on the commandline - Trinket M0\n\n1. Install `openocd` and get `bootloader-xxx.bin` \n2. Get [openocd_atmel-ice_samd21.cfg](./openocd_atmel-ice_samd21.cfg)\n3. Connect Atmel ICE similar to JLink by using adapter like in image below\n4. Program on commandline:\n   ```\n   openocd -f ./openocd_jlink_samd21.cfg \\\n      -c \"init; targets; halt; \" \\\n      -c \"at91samd bootloader 0;\" \\\n      -c \"program bootloader-trinket_m0-v3.16.0.bin verify;\" \\\n      -c \"at91samd bootloader 8192; reset; shutdown\" \n    ```\n    \n    **NOTE:** the `at91samd bootloader 0;` disables bootloader protection and \n    allows you to rewrite the bootloader. The `at91samd bootloader 8192;`\n    re-enables bootloader protection.\n    (from this [adfruit forum post](https://forums.adafruit.com/viewtopic.php?t=204268))\n    \n    \u003cimg src=\"./imgs/trinketm0_atmel-ice.jpg\" width=\"500\"\u003e\n  \n  \n5. You can also choose to install `telnet` and do these commands interactively:\n\n  In one terminal window run `openocd`:\n  ```\n% openocd -f ./openocd_atmel-ice_samd21.cfg \nOpen On-Chip Debugger 0.12.0\nLicensed under GNU GPL v2\nFor bug reports, read\n   http://openocd.org/doc/doxygen/bugs.html\nInfo : auto-selecting first available session transport \"swd\". To override use 'transport select \u003ctransport\u003e'.\nInfo : Listening on port 6666 for tcl connections\nInfo : Listening on port 4444 for telnet connections\nInfo : CMSIS-DAP: SWD supported\nInfo : CMSIS-DAP: JTAG supported\nInfo : CMSIS-DAP: FW Version = 01.00.0021\nInfo : CMSIS-DAP: Serial# = J41800054170\nInfo : CMSIS-DAP: Interface Initialised (SWD)\nInfo : SWCLK/TCK = 1 SWDIO/TMS = 1 TDI = 1 TDO = 1 nTRST = 0 nRESET = 1\nInfo : CMSIS-DAP: Interface ready\nInfo : clock speed 400 kHz\nInfo : SWD DPIDR 0x0bc11477\nInfo : [at91samd21e18.cpu] Cortex-M0+ r0p1 processor detected\nInfo : [at91samd21e18.cpu] target has 4 breakpoints, 2 watchpoints\nInfo : starting gdb server for at91samd21e18.cpu on 3333\nInfo : Listening on port 3333 for gdb connections\n  ```\n\n  And in another terminal window, run `telnet` and then openocd commands:\n\n  ```\n% telnet localhost 4444     \nTrying ::1...\ntelnet: connect to address ::1: Connection refused\nTrying 127.0.0.1...\nConnected to localhost.\nEscape character is '^]'.\nOpen On-Chip Debugger\n\n\u003e targets\n    TargetName         Type       Endian TapName            State       \n--  ------------------ ---------- ------ ------------------ ------------\n 0* at91samd21e18.cpu  cortex_m   little at91samd21e18.cpu  running\n\n\u003e reset halt                                                                 \n[at91samd21e18.cpu] halted due to debug-request, current mode: Thread \nxPSR: 0x21000000 pc: 0x00000264 msp: 0x20002de0\n\n\u003e at91samd bootloader 0\n\n\u003e flash erase_sector 0 1 last                   \nSAMD MCU: SAMD21E18A (256KB Flash, 32KB RAM)\nerased sectors 1 through 1023 on flash bank 0 in 6.106292s\n\n\u003e program bootloader-trinket_m0-v3.16.0.bin verify \n[at91samd21e18.cpu] halted due to debug-request, current mode: Thread \nxPSR: 0x21000000 pc: 0x00000264 msp: 0x20002de0\n** Programming Started **\n** Programming Finished **\n** Verify Started **\n** Verified OK **\n\n\u003e at91samd bootloader 8192\n\n\u003e reset\n\u003e shutdown\n  ```\n\n### Update bootlaoder via OpenOCD and STLink v2 - Trinket M0\n\n1. Install `openocd` and get `bootloader-xxx.bin` \n2. Get [openocd_stlink_samd21.cfg](./openocd_stlink_samd21.cfg)\n3. Connect Trinket M0 to STLink using only: GND, SWDIO, SWCLK, as in image below\n \n4. Program on commandline:\n   ```\n   openocd -f ./openocd_atmel-ice_samd21.cfg \\\n      -c \"init; targets; halt; program bootloader-trinket_m0-v3.16.0.bin verify reset; shutdown\"\n    ```\n  \u003cimg src=\"./imgs/trinketm0_stlink.jpg\" width=\"500\"\u003e\n\n5. Or interactively:\n\n  ```\n% telnet localhost 4444\nTrying ::1...\ntelnet: connect to address ::1: Connection refused\nTrying 127.0.0.1...\nConnected to localhost.\nEscape character is '^]'.\nOpen On-Chip Debugger\n\n\u003e reset halt                  \n[at91samd21g18a.cpu] halted due to debug-request, current mode: Thread \nxPSR: 0x61000000 pc: 0x00000264 msp: 0x20002de0\n\u003e targets                                                                    \n    TargetName         Type       Endian TapName            State       \n--  ------------------ ---------- ------ ------------------ ------------\n 0* at91samd21g18a.cpu hla_target little at91samd21g18a.cpu halted\n\n\u003e flash erase_sector 0 1 last                                                \nSAMD MCU: SAMD21E18A (256KB Flash, 32KB RAM)\nerased sectors 1 through 1023 on flash bank 0 in 5.069648s\n\n\u003e program /Users/tod/Downloads/bootloader-trinket_m0-v3.16.0.bin verify reset\n[at91samd21g18a.cpu] halted due to debug-request, current mode: Thread \nxPSR: 0x61000000 pc: 0x00000264 msp: 0x20002de0\n** Programming Started **\n** Programming Finished **\n** Verify Started **\n** Verified OK **\n** Resetting Target **\n  ```\n\n\n\n\n### Useful links: ###\n- https://learn.adafruit.com/adafruit-feather-m0-express-designed-for-circuit-python-circuitpython/uf2-bootloader-details\n- https://learn.adafruit.com/debugging-the-samd21-with-gdb/setup\n- https://learn.adafruit.com/proper-step-debugging-atsamd21-arduino-zero-m0/lets-go\n- http://www.instructables.com/id/ATSAMD21g18-Bootloader-With-J-link-Debugger/\n- https://github.com/geomatsi/stm32-tests/blob/master/boards/stm32f103-mini/scripts/openocd-jlink-swd.cfg\n- https://learn.adafruit.com/programming-microcontrollers-using-openocd-on-raspberry-pi/wiring-and-test\n- https://omzlo.com/articles/programming-the-samd21-using-atmel-ice-with-openocd-(updated)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftodbot%2Fsamd21-programming-notes","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftodbot%2Fsamd21-programming-notes","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftodbot%2Fsamd21-programming-notes/lists"}