Commit 0c242305 authored by Erik Strand's avatar Erik Strand
Browse files

Reorganize and add content for wildcard week

parents 551d5d95 4c703c82
*.swp
*.swo
*.elf
.DS_Store
......@@ -4,6 +4,7 @@ The ATSAMD51 is an ARM Cortex-M4F microcontroller manufactured by Microchip (Atm
As of Oct 13 2019, -> CBA :heart: D51 <-
## Circuits using the D51
![feather m4 pic](https://cdn-shop.adafruit.com/970x728/3857-00.jpg)
......@@ -12,125 +13,38 @@ As of Oct 13 2019, -> CBA :heart: D51 <-
![module pic](https://gitlab.cba.mit.edu/squidworks/moduleboard-atsamd51/raw/master/moduleboard-atsamd51/2019-10-13_module-fab.jpg)
[squidworks module](https://gitlab.cba.mit.edu/squidworks/moduleboard-atsamd51/)
## Toolchains
### Adafruit Bootloader / Platformio (or Arduino Compatible)
## Bare(ish) Metal Toolchains
[OpenOCD](blink-openocd)
Since [Adafruit](https://learn.adafruit.com/adafruit-feather-m4-express-atsamd51) has adopted the SAMD51, it is well supported by the open source community, and we can borrow their development tools.
**fair warning**
>Use of the arduino bootloader *does* assume that your circuit has a USB port available, as well as a 32.678kHz clock on the RTC Xout / Xin pins. During cycles, the bootloader (assuming it is on a Feather M4) will toggle 'D13' (PA23) as well as send Neopixel Data to (?).
## Bootloader Based Toolchains
To get started, find the latest build of the [adafruit bootloader] and download that (probably a `.bin` or `.elf` or `.hex` file).
Since [Adafruit](https://learn.adafruit.com/adafruit-feather-m4-express-atsamd51) has adopted the
SAMD51, it is well supported by the open source community, and we can borrow their development
tools. For instructions on how to burn your board with a bootloader, see the
[bootloader](bootloader) directory.
We need to write this file into the micro's memory. I have been using the `Serial Wire Debug` interface, which is enabled by default on the D51 hardware (but JTAG is also available, but requires an enable pin pulled low somewhere *I think*). `SWCLK is on PA30` and `SWDIO is on PA31`.
Once you've got a bootloader on your board, you have a lot of options for programming it.
To speak SWD, I just use the Atmel-Ice programmer, and Atmel Studio 7 (a windows application, sorry). Any programmer that speaks SWD should be capable of doing this. In Atmel Studio, go to `Tools -> Device Programming`, and select the Atmel-Ice Tool, the ATSAMD51xxxx device you'd like to program (the bootloader is written for the ATSAMD51J19A), and the SWD interface. You should be able to read the device signature. If this works, your SWD connection is all super-gucci (as they say). You can navigate to `Memories` - and write that bootloader in. OK. The device should now enumerate over USB as an Adafruit Feather M4 / FeatherBoot (or something similar).
### Platformio
To write code and load it, I use [PlatformIO](https://platformio.org/platformio-ide), which is an open source 'IOT' (embedded) programming tool written as a package for either [atom](https://atom.io/) code-editor, or [vscode](https://code.visualstudio.com/). See their doc for setting up a new project for the D51 / Feather M4.
To write code and load it, Jake uses [PlatformIO](https://platformio.org/platformio-ide), which is an open source 'IOT' (embedded) programming tool written as a package for either [atom](https://atom.io/) code-editor, or [vscode](https://code.visualstudio.com/). See their doc for setting up a new project for the D51 / Feather M4.
### Arduino IDE
We're not going to beat Adafruit's documentation on setting up the Arduino IDE, so just take a
gander over
[here](https://learn.adafruit.com/adafruit-feather-m4-express-atsamd51/using-with-arduino-ide). It's
their bootloader, after all. An example sketch lives in the [blink-arduino](blink-arduino)
directory.
### Real Registers in an Arduino World
One of the troubles with Arduino is that people forget that it is just a big C++ library. This means that everything under the sun (that compiles) is legal here. *That* means that we can use Arduino as a crutch, but write really nice Special Function Register code inside of the same executable. Great!
Indeed, in the PlatformIO environment, we even have wonderful autocomplete handles on the D51's core register map. For some examples of this kind of manipulation, check out the `hunks` in the [ponyo](https://gitlab.cba.mit.edu/squidworks/ponyo) project.
### Bare Metal development
Okay, bare-ish metal development. If you want to work with the SAMD51 using the command line, a text editor, Makefiles, and a few open-source tools, it's possible to do so with a bit of setup. You should use Linux to do this work; your mileage may vary on other operating systems.
Credit to Alex Kaspar for sorting through openocd setup in 2018. These instructions build on that work.
First, install [openocd](http://openocd.org/getting-openocd/). Until recently, this tool didn't officially support the SAMD51 series, requiring the use of a [patch](http://openocd.zylin.com/#/c/4272/) and manual compilation to work with the chipset. According to the patch notes, the patch was merged in early 2019 so the standard installation should work fine. Put the program in directory such as ~/openocd. If you're building from source, navigate to this directory and run:
```
./bootstrap
./configure --enable-cmsis-dap
make
make install
```
Second, install a handful of other helpful tools. Depending on your other work you may already have many of these on your machine:
```
sudo apt install autoconf build-essential cmake gdb-arm-none-eabi libtool libtool-bin libhidapi-dev libusb-dev libusb-1.0-0-dev pkg-config
```
Third, clone this repo. Navigate to the `baremetal` directory and run `make`. You should see something like this result:
```
zach@crudite:~/Documents/atsamd51/baremetal$ make
Building file: main.c
ARM/GNU C Compiler
"arm-none-eabi-gcc" -x c -DDEBUG -Os -ffunction-sections -g3 -Wall -c -std=gnu99 -mthumb -mabi=aapcs-linux -mlong-calls -mcpu=cortex-m4 -mfloat-abi=softfp -mfpu=fpv4-sp-d16 -DSAMD51 -D__SAMD51J19A__ -I"samd51" -I"samd51/CMSIS/Include" -I"samd51/include" -I"samd51/startup" \
-MD -MP -MF "main.d" -MT"main.d" -MT"main.o" -o "main.o" "main.c"
Finished building: main.c
Building file: samd51/startup/system_samd51.c
ARM/GNU C Compiler
"arm-none-eabi-gcc" -x c -DDEBUG -Os -ffunction-sections -g3 -Wall -c -std=gnu99 -mthumb -mabi=aapcs-linux -mlong-calls -mcpu=cortex-m4 -mfloat-abi=softfp -mfpu=fpv4-sp-d16 -DSAMD51 -D__SAMD51J19A__ -I"samd51" -I"samd51/CMSIS/Include" -I"samd51/include" -I"samd51/startup" \
-MD -MP -MF "samd51/startup/system_samd51.d" -MT"samd51/startup/system_samd51.d" -MT"samd51/startup/system_samd51.o" -o "samd51/startup/system_samd51.o" "samd51/startup/system_samd51.c"
Finished building: samd51/startup/system_samd51.c
Building file: samd51/startup/startup_samd51.c
ARM/GNU C Compiler
"arm-none-eabi-gcc" -x c -DDEBUG -Os -ffunction-sections -g3 -Wall -c -std=gnu99 -mthumb -mabi=aapcs-linux -mlong-calls -mcpu=cortex-m4 -mfloat-abi=softfp -mfpu=fpv4-sp-d16 -DSAMD51 -D__SAMD51J19A__ -I"samd51" -I"samd51/CMSIS/Include" -I"samd51/include" -I"samd51/startup" \
-MD -MP -MF "samd51/startup/startup_samd51.d" -MT"samd51/startup/startup_samd51.d" -MT"samd51/startup/startup_samd51.o" -o "samd51/startup/startup_samd51.o" "samd51/startup/startup_samd51.c"
Finished building: samd51/startup/startup_samd51.c
Building target: main.elf
Invoking: ARM/GNU Linker
"arm-none-eabi-gcc" -o main.elf main.o samd51/startup/system_samd51.o samd51/startup/startup_samd51.o -Wl,--start-group -lm -Wl,--end-group -mthumb -mabi=aapcs-linux -mlong-calls -mcpu=cortex-m4 -mfloat-abi=softfp -mfpu=fpv4-sp-d16 -DSAMD51 \
-Wl,-Map="main.map" --specs=nano.specs -Wl,--gc-sections \
\
\
-T"samd51/startup/samd51j19a_flash.ld" \
-L"samd51/startup"
/usr/bin/../lib/gcc/arm-none-eabi/7.3.1/../../../../arm-none-eabi/bin/ld: warning: main.o uses 32-bit enums yet the output is to use variable-size enums; use of enum values across objects may fail
/usr/bin/../lib/gcc/arm-none-eabi/7.3.1/../../../../arm-none-eabi/bin/ld: warning: samd51/startup/system_samd51.o uses 32-bit enums yet the output is to use variable-size enums; use of enum values across objects may fail
/usr/bin/../lib/gcc/arm-none-eabi/7.3.1/../../../../arm-none-eabi/bin/ld: warning: samd51/startup/startup_samd51.o uses 32-bit enums yet the output is to use variable-size enums; use of enum values across objects may fail
Finished building target: main.elf
"arm-none-eabi-objcopy" -O binary "main.elf" "main.bin"
"arm-none-eabi-objcopy" -O ihex -R .eeprom -R .fuse -R .lock -R .signature \
"main.elf" "main.hex"
"arm-none-eabi-objcopy" -j .eeprom --set-section-flags=.eeprom=alloc,load --change-section-lma \
.eeprom=0 --no-change-warnings -O binary "main.elf" \
"main.eep" || exit 0
"arm-none-eabi-objdump" -h -S "main.elf" > "main.lss"
"arm-none-eabi-size" "main.elf"
text data bss dec hex filename
968 0 49184 50152 c3e8 main.elf
Deleting intermediate files...
rm -f main.o samd51/startup/system_samd51.o samd51/startup/startup_samd51.o
rm -f main.d samd51/startup/system_samd51.d samd51/startup/startup_samd51.d
rm -f main.a main.hex main.bin \
main.lss main.eep main.map \
main.srec
```
Errors are not uncommon and are usually related to the directory structure of the Makefile. However, this repo includes all of the required SAMD51 libraries (from Atmel/Microchip's ASF4 framework, as shared by [Adafruit](https://github.com/adafruit/asf4)), so if you grabbed the entire repo you should be fine. Post an issue if it doesn't work. Note one modification to the Makefile is that it deletes all the intermediate files (.o, .eep, etc) after producing the .elf file. If you want them, remove the lines in the Makefile after the phrase 'Deleting intermediate files...'.
Fourth, after you have your .elf file (in this case `main.elf`), connect your target board to power and an Atmel ICE programmer (make sure you use the correct pinout and the SAM port!) and run `openocd`. You should see the following:
```
zach@crudite:~/Documents/atsamd51/baremetal$ openocd
Open On-Chip Debugger 0.10.0+dev-00409-g1ae106de-dirty (2019-10-14-20:41)
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
none separate
adapter speed: 400 kHz
cortex_m reset_config sysresetreq
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Info : CMSIS-DAP: SWD Supported
Info : CMSIS-DAP: JTAG Supported
Info : CMSIS-DAP: Interface Initialised (SWD)
Info : CMSIS-DAP: FW Version = 1.0
Info : SWCLK/TCK = 1 SWDIO/TMS = 1 TDI = 1 TDO = 1 nTRST = 0 nRESET = 1
Info : CMSIS-DAP: Interface ready
Info : clock speed 400 kHz
Info : SWD DPIDR 0x2ba01477
Info : at91samd51j18.cpu: hardware has 6 breakpoints, 4 watchpoints
Info : Listening on port 3333 for gdb connections
```
If you see `Error: unable to open CMSIS-DAP device 0x3eb:0x2141`, it probably means openocd needs root privileges to access the programmer. You could run `sudo openocd`, but a better solution is to follow the instructions [here](https://forgge.github.io/theCore/guides/running-openocd-without-sudo.html) to create a new rule. Don't forget to restart `udev` after doing this with `sudo udevadm trigger`.
Fifth, now that openocd is running, open a second terminal window and type `arm-none-eabi-gdb main.elf`. When gdb opens, type `tar ext :3333` (a shortcut for `target extended-remote :3333`), then `load`. This should flash the microcontroller with the new code, at which point you can exit gdb with `quit` and `y`. In the openocd window, close the connection with `Ctrl-C`. If you're flashing one of Jake's [moduleboards](https://gitlab.cba.mit.edu/squidworks/moduleboard-atsamd51/tree/master), the red and green LEDs should alternate fast enough to create a line of dashes when you wave the board around:
![example-blinks](baremetal/example-blinks.jpg)
#include "sam.h"
int main (void) {
int i;
REG_PORT_DIR0 |= (1<<17);
REG_PORT_DIR0 |= (1<<19);
while(1) {
REG_PORT_OUTSET0 |= (1<<17);
REG_PORT_OUTCLR0 |= (1<<19);
for (i=0;i<10000;i++) {
__asm("nop");
}
REG_PORT_OUTCLR0 |= (1<<17);
REG_PORT_OUTSET0 |= (1<<19);
for (i=0;i<10000;i++) {
__asm("nop");
}
}
}
# Programming with the Arduino IDE
This doc assumes you've already burned an Arduino compatible bootloader on your board, and set up
the Arduino IDE to talk to it. If you still need to do this, check out the README one level up.
After that, just select the right settings in the Arduino IDE tools menu and you're good to go:
- Board: Adafruit Feather M4 Express (SAMD51)
- Port: depends on your OS, but it should say Adafruit Feather M4 Express (SAMD51) somewhere
- Programmer: USBtinyISP
The other settings are up to you. Defaults are fine.
![Arduino IDE](img/arduino_ide.jpg)
Note that this blinky sketch is fancy, and prints "hello world" over USB serial. To see it, you can
use the Arduino IDE's serial monitor. Getting this to work would be a lot more difficult without the
Arduino libraries.
#define RED_LED 25
#define GREEN_LED 9
void setup() {
pinMode(RED_LED, OUTPUT);
pinMode(GREEN_LED, OUTPUT);
// This turns off the LEDs.
digitalWrite(RED_LED, HIGH);
digitalWrite(GREEN_LED, HIGH);
Serial.begin(9600);
}
void loop() {
digitalWrite(RED_LED, LOW);
digitalWrite(GREEN_LED, LOW);
Serial.println("hello world");
delay(500);
digitalWrite(RED_LED, HIGH);
digitalWrite(GREEN_LED, HIGH);
delay(500);
}
# Bare Metal Development
This is a minimalist blink program. No bootloader, and no IDE to build things for us. Just the
command line, a text editor, Makefiles, and a few open-source tools. You should use Linux to do this
work; your mileage may vary on other operating systems.
This example assumes you're using a
[squidworks module](https://gitlab.cba.mit.edu/squidworks/moduleboard-atsamd51/), but if you're
using something else you'll just need to update which pins your LEDs are on.
## Setup
We'll use OpenOCD to program our board. Relevant docs live
[here](https://gitlab.cba.mit.edu/pub/hello-world/tools/tree/master/openocd).
## Building
Once that's done, clone this repo. Fire up your terminal, navigate to this directory, and run
`make`. You should see something like this result:
```
zach@crudite:~/Documents/atsamd51/baremetal$ make
Building file: main.c
ARM/GNU C Compiler
"arm-none-eabi-gcc" -x c -DDEBUG -Os -ffunction-sections -g3 -Wall -c -std=gnu99 -mthumb -mabi=aapcs-linux -mlong-calls -mcpu=cortex-m4 -mfloat-abi=softfp -mfpu=fpv4-sp-d16 -DSAMD51 -D__SAMD51J19A__ -I"samd51" -I"samd51/CMSIS/Include" -I"samd51/include" -I"samd51/startup" \
-MD -MP -MF "main.d" -MT"main.d" -MT"main.o" -o "main.o" "main.c"
Finished building: main.c
Building file: samd51/startup/system_samd51.c
ARM/GNU C Compiler
"arm-none-eabi-gcc" -x c -DDEBUG -Os -ffunction-sections -g3 -Wall -c -std=gnu99 -mthumb -mabi=aapcs-linux -mlong-calls -mcpu=cortex-m4 -mfloat-abi=softfp -mfpu=fpv4-sp-d16 -DSAMD51 -D__SAMD51J19A__ -I"samd51" -I"samd51/CMSIS/Include" -I"samd51/include" -I"samd51/startup" \
-MD -MP -MF "samd51/startup/system_samd51.d" -MT"samd51/startup/system_samd51.d" -MT"samd51/startup/system_samd51.o" -o "samd51/startup/system_samd51.o" "samd51/startup/system_samd51.c"
Finished building: samd51/startup/system_samd51.c
Building file: samd51/startup/startup_samd51.c
ARM/GNU C Compiler
"arm-none-eabi-gcc" -x c -DDEBUG -Os -ffunction-sections -g3 -Wall -c -std=gnu99 -mthumb -mabi=aapcs-linux -mlong-calls -mcpu=cortex-m4 -mfloat-abi=softfp -mfpu=fpv4-sp-d16 -DSAMD51 -D__SAMD51J19A__ -I"samd51" -I"samd51/CMSIS/Include" -I"samd51/include" -I"samd51/startup" \
-MD -MP -MF "samd51/startup/startup_samd51.d" -MT"samd51/startup/startup_samd51.d" -MT"samd51/startup/startup_samd51.o" -o "samd51/startup/startup_samd51.o" "samd51/startup/startup_samd51.c"
Finished building: samd51/startup/startup_samd51.c
Building target: main.elf
Invoking: ARM/GNU Linker
"arm-none-eabi-gcc" -o main.elf main.o samd51/startup/system_samd51.o samd51/startup/startup_samd51.o -Wl,--start-group -lm -Wl,--end-group -mthumb -mabi=aapcs-linux -mlong-calls -mcpu=cortex-m4 -mfloat-abi=softfp -mfpu=fpv4-sp-d16 -DSAMD51 \
-Wl,-Map="main.map" --specs=nano.specs -Wl,--gc-sections \
\
\
-T"samd51/startup/samd51j19a_flash.ld" \
-L"samd51/startup"
/usr/bin/../lib/gcc/arm-none-eabi/7.3.1/../../../../arm-none-eabi/bin/ld: warning: main.o uses 32-bit enums yet the output is to use variable-size enums; use of enum values across objects may fail
/usr/bin/../lib/gcc/arm-none-eabi/7.3.1/../../../../arm-none-eabi/bin/ld: warning: samd51/startup/system_samd51.o uses 32-bit enums yet the output is to use variable-size enums; use of enum values across objects may fail
/usr/bin/../lib/gcc/arm-none-eabi/7.3.1/../../../../arm-none-eabi/bin/ld: warning: samd51/startup/startup_samd51.o uses 32-bit enums yet the output is to use variable-size enums; use of enum values across objects may fail
Finished building target: main.elf
"arm-none-eabi-objcopy" -O binary "main.elf" "main.bin"
"arm-none-eabi-objcopy" -O ihex -R .eeprom -R .fuse -R .lock -R .signature \
"main.elf" "main.hex"
"arm-none-eabi-objcopy" -j .eeprom --set-section-flags=.eeprom=alloc,load --change-section-lma \
.eeprom=0 --no-change-warnings -O binary "main.elf" \
"main.eep" || exit 0
"arm-none-eabi-objdump" -h -S "main.elf" > "main.lss"
"arm-none-eabi-size" "main.elf"
text data bss dec hex filename
968 0 49184 50152 c3e8 main.elf
Deleting intermediate files...
rm -f main.o samd51/startup/system_samd51.o samd51/startup/startup_samd51.o
rm -f main.d samd51/startup/system_samd51.d samd51/startup/startup_samd51.d
rm -f main.a main.hex main.bin \
main.lss main.eep main.map \
main.srec
```
Errors are not uncommon and are usually related to the directory structure of the Makefile. However,
this repo includes all of the required SAMD51 libraries (from Atmel/Microchip's ASF4 framework, as
shared by [Adafruit](https://github.com/adafruit/asf4)), so if you grabbed the entire repo you
should be fine. Post an issue if it doesn't work. Note one modification to the Makefile is that it
deletes all the intermediate files (.o, .eep, etc) after producing the .elf file. If you want them,
remove the lines in the Makefile after the phrase 'Deleting intermediate files...'.
Also note that the final `.elf` file is included in this repo. So if you're having trouble building
you can still test programming.
## Programming
Fourth, after you have your .elf file (in this case `main.elf`), connect an Atmel ICE programmer to
your SAMD51 board and power it up. Note: make sure you use the correct pinout and the SAM port! Then
run `openocd`. You should see the following:
```
zach@crudite:~/Documents/atsamd51/baremetal$ openocd
Open On-Chip Debugger 0.10.0+dev-00409-g1ae106de-dirty (2019-10-14-20:41)
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
none separate
adapter speed: 400 kHz
cortex_m reset_config sysresetreq
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Info : CMSIS-DAP: SWD Supported
Info : CMSIS-DAP: JTAG Supported
Info : CMSIS-DAP: Interface Initialised (SWD)
Info : CMSIS-DAP: FW Version = 1.0
Info : SWCLK/TCK = 1 SWDIO/TMS = 1 TDI = 1 TDO = 1 nTRST = 0 nRESET = 1
Info : CMSIS-DAP: Interface ready
Info : clock speed 400 kHz
Info : SWD DPIDR 0x2ba01477
Info : at91samd51j18.cpu: hardware has 6 breakpoints, 4 watchpoints
Info : Listening on port 3333 for gdb connections
```
If you see `Error: unable to open CMSIS-DAP device 0x3eb:0x2141`, it probably means openocd needs
root privileges to access the programmer. You could run `sudo openocd`, but a better solution is to
follow the instructions
[here](https://forgge.github.io/theCore/guides/running-openocd-without-sudo.html) to create a new
rule. Don't forget to restart `udev` after doing this with `sudo udevadm trigger`.
Fifth, now that openocd is running, open a second terminal window and type `gdb-multiarch main.elf`
(if you're using an older gdb version, it's `arm-none-eabi-gdb main.elf`). When gdb opens, type `tar
ext :3333` (a shortcut for `target extended-remote :3333`), then `load`. This should flash the
microcontroller with the new code, at which point you can exit gdb with `quit` and `y`. In the
openocd window, close the connection with `Ctrl-C`. If you're flashing one of Jake's
[moduleboards](https://gitlab.cba.mit.edu/squidworks/moduleboard-atsamd51/tree/master), the red and
green LEDs should blink.
#include "sam.h"
int main (void) {
int i;
// on a squidworks module board, the red LED is 17, and the green is 19
REG_PORT_DIR0 = (1u << 17) | (1u << 19);
// setting these high turns the LEDs off
REG_PORT_OUTSET0 = (1u << 17) | (1u << 19);
while(1) {
REG_PORT_OUTSET0 = (1u << 17) | (1u << 19);
for (i=0; i<1000000; i++) {
__asm("nop");
}
REG_PORT_OUTCLR0 = (1u << 17) | (1u << 19);
for (i=0; i<1000000; i++) {
__asm("nop");
}
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment