--- title: ATSAM3X8E bare-metal notes date: 2024-09-16 layout: post --- Bought an Arduino Due to play with ARM Cortex chips. Locked out of the chip for days—no dev tools (Arduino IDE, Microchip Studio) for OpenBSD. Need to find a way to bring up the bare-metal ATSAM3X8E. Three on-chip memories: ROM, flash0, flash1. ARM Cortex-M chips boot into 0x00000. GPNVM bits map one of them to 0x00000: - GPNVM1=0 → ROM (default). - GPNVM1=1 and GPNVM2=0 → flash0. - GPNVM1=1 and GPNVM2=1 → flash1. On power-up, control jumps to ROM. Without a user program, Atmel's SAM-BA bootloader traps execution in ROM. Must remap memory via SWD to force chip to boot from flash, bypassing factory bootloader. Toolchain: ST-LINK/V2 programmer, OpenOCD, ARM GNU Compiler Toolchain. Connect ST-LINK/v2 to Arduino Due's DEBUG port:
Pinout

Wiring

Circuit

Arduino Due

Remap memory using OpenOCD: ``` $ openocd -f openocd-due.cfg $ telnet localhost 4444 > halt > at91sam3 gpnvm show > at91sam3 gpnvm set 1 > at91sam3 gpnvm show ``` Full command list in OpenOCD manual AT91SAM3 (flash driver section). At a minimum, vector table must be initialized with stack pointer and reset vector: ``` __attribute__((noreturn)) void _reset(void) { unsigned long *dst, *src; extern unsigned long _sbss, _ebss; extern unsigned long _sdata, _edata, _sidata; for (dst = &_sbss; dst < &_ebss; dst++) *dst = 0; for (dst = &_sdata, src = &_sidata; dst < &_edata;) *dst++ = *src++; main(); } extern const unsigned int _sp; __attribute__ ((section(".vtor"))) const void* _tab[] = { &_sp, _reset }; ``` Linker script places vector table at start of flash0 and initializes stack pointer to top of RAM (descending stack): ``` MEMORY { rom (rx) : ORIGIN = 0x00080000, LENGTH = 512K ram (rwx) : ORIGIN = 0x20000000, LENGTH = 96K } SECTIONS { .text : { KEEP(*(.vtor)) *(.text*) *(.rodata*) } > rom } _sp = ORIGIN(ram) + LENGTH(ram); ``` Getting linker script right wasn't easy—long hours with the datasheet, OpenOCD manual. David Barrass from OpenBSD and folks at OpenOCD mailing lists (bless them!) helped generously. Build and upload program: ``` $ arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -T script.ld \ -nostartfiles \ -nostdlib \ -o a.elf main.c $ openocd -f openocd-due.cfg -c "program a.elf verify reset exit" ``` Chip unlocked. I'm in. Commit: 3184969.