AT91SAM7 From scratch Basic from-scratch ARM microcontroller hacking on Atmel AT91SAM7S-EK using OpenOCD (1a8223f28b2a459750b6dd9b867f4cec0c14a515) and Olimex Ltd. OpenOCD JTAG (15ba:0003) To start you need 2 terminals: OOCD: ./openocd.sh GDB: ./gdb.sh Entry: Loading a binary Date: Fri Nov 30 16:32:49 EST 2012 While in general you'd want to use an ELF file and a proper linking step, just to get things started it might be illustrative to run binary assembly code. The SAM7's memory map is: 0x000000 Flash (at boot) or RAM. 0x100000 Flash 0x200000 RAM Loading a binary image to RAM seems to be a bit problematic for GDB, so let's stick to ELF. What is the simplest way to get something into flash? The key ingredient here is the linker script: ld_flash.cmd Entry: Vector setup Date: Fri Nov 30 16:33:01 EST 2012 Next is a proper vector init. What is often found on ARM is the following sequence: ldr pc, [pc, #24] ldr pc, [pc, #24] ldr pc, [pc, #24] ldr pc, [pc, #24] ARM vectors are jump points, not addresses. The code above allows addresses to be stored at an offset of 0x20 bytes (#24 == 0x18: note that PC is always 8 bytes ahead). On IRQ the PC will be loaded from AIC_IVR[2]. The naked and signal attributes can be used to implement vectors in C [3]. [1] http://www.keil.com/forum/16417/ [2] http://www.ethernut.de/en/documents/arm-exceptions.html [3] http://www.freertos.org/implementation/a00013.html Entry: Absolute minimum Date: Sun Dec 2 09:55:41 EST 2012 - No interrupt vectors: only an init vector. - No global C global variable inits - No oscillator setup - Minimal stack setup per mode. Entry: DBGU Date: Sun Dec 2 11:27:15 EST 2012 If I'm correct, the chip starts up at 32kHz, so to get to 9600 baud on DBGU we need to switch on the main oscillator[1]. [1] http://www.triplespark.net/elec/pdev/arm/at91sam7.html [2] http://www.codeforge.com/read/39051/dbgu.c__html Entry: Oscillator Date: Sun Dec 2 18:44:09 EST 2012 To start the oscillator, see here[1]. The AT91SAM7-EK[4] has a 18.432 MHz xtal, which allows perfect data rates for the standard baud rates (18.432MHz / 160 == 115200 Hz). At what clock is the CPU running? And does it matter for the BRGs? From [2]: The AT91SAM7S256 has a 18.432MHz crystal connected to it which allows it to operate at 48MHz. The USB port is usable only when the microcontroller is running at 48MHz. For 48Mhz, the PPL ratios are 73/28 [3] to give 48.055MHz. The PLL needs an external 2nd order filter, so its operation range is actually board-dependent. Probably best to stick to this. However, it's not necessary until USB is used. So what about not enabling PLL? How to configure that? 25.7.4: The Master Clock and the Processor Clock are configurable via the PMC_MCKR register. ( READ THIS SECTION AGAIN WHEN ANYTHING CHANGES! ) Basically, the simplest approach (without PLL) is to set the Master clock to main clock (XTAL or external osc) using PMC_MCKR:CSS=1 and set the processor prescaler to 1 using PMC_MCKR:PRES=0. [1] http://www.triplespark.net/elec/pdev/arm/at91sam7.html [2] http://startingelectronics.com/reviews/evaluation-boards/AT91SAM7S-EK/ [3] http://tech.dir.groups.yahoo.com/group/AT91SAM/message/734 [4] http://www.atmel.com/Images/doc6112.pdf Entry: Toggling pins Date: Mon Dec 3 13:03:47 EST 2012 At 18MHz I see 160ns between toggle instructions, that's 3 cyles. The loop is this: 0x00100094 <+12>: str r0, [r3, #-207] ; 0xcf 0x00100098 <+16>: str r0, [r3, #-203] ; 0xcb 0x0010009c <+20>: b 0x100094 I wonder if this is because Flash wait states are enabled. From example code in [1] I have: // Set Flash Wait sate: 0 wait states. AT91C_BASE_MC->MC_FMR = ((AT91C_MC_FMCN)&(22 <<16)) | AT91C_MC_FWS_0FWS; [1] http://www.triplespark.net/elec/pdev/arm/at91sam7.html Entry: Goals Date: Tue Dec 4 11:44:35 EST 2012 This subproject aims to do the following: - Minimalistic processor startup (no libc) - Evaluation of open source libc (i.e. newlib) - Running libprim core on top of a libc - Running lua + zl primitives on top of a libc Entry: Newlib Date: Tue Dec 4 11:49:50 EST 2012 See at91sam7/newlib/Makefile adapted from basic info in [1], but check [2] later for -DREENTRANT_SYSCALLS_PROVIDED. [1] http://balau82.wordpress.com/2010/12/16/using-newlib-in-arm-bare-metal-programs/ [2] http://www.embedded.com/electronics-blogs/industry-comment/4023922/Embedding-GNU-Newlib-Part-2 Entry: Toolchain Date: Tue Dec 4 13:33:30 EST 2012 It looks like newlib builds a whole lot of targets: tom@zoo:~/libprim/at91sam7/newlib$ find -name libc.a ./newlib-1.18.0/arm-eabi/arm9/newlib/libc.a ./newlib-1.18.0/arm-eabi/arm9/newlib/libc/libc.a ./newlib-1.18.0/arm-eabi/nointerwork/arm9/newlib/libc.a ./newlib-1.18.0/arm-eabi/nointerwork/arm9/newlib/libc/libc.a ./newlib-1.18.0/arm-eabi/nointerwork/arm9e/newlib/libc.a ./newlib-1.18.0/arm-eabi/nointerwork/arm9e/newlib/libc/libc.a ./newlib-1.18.0/arm-eabi/nointerwork/xscale/newlib/libc.a ./newlib-1.18.0/arm-eabi/nointerwork/xscale/newlib/libc/libc.a ./newlib-1.18.0/arm-eabi/nointerwork/newlib/libc.a ./newlib-1.18.0/arm-eabi/nointerwork/newlib/libc/libc.a ./newlib-1.18.0/arm-eabi/arm9e/newlib/libc.a ./newlib-1.18.0/arm-eabi/arm9e/newlib/libc/libc.a ./newlib-1.18.0/arm-eabi/be/nointerwork/xscale/newlib/libc.a ./newlib-1.18.0/arm-eabi/be/nointerwork/xscale/newlib/libc/libc.a ./newlib-1.18.0/arm-eabi/be/nointerwork/newlib/libc.a ./newlib-1.18.0/arm-eabi/be/nointerwork/newlib/libc/libc.a ./newlib-1.18.0/arm-eabi/be/xscale/newlib/libc.a ./newlib-1.18.0/arm-eabi/be/xscale/newlib/libc/libc.a ./newlib-1.18.0/arm-eabi/be/newlib/libc.a ./newlib-1.18.0/arm-eabi/be/newlib/libc/libc.a ./newlib-1.18.0/arm-eabi/xscale/newlib/libc.a ./newlib-1.18.0/arm-eabi/xscale/newlib/libc/libc.a ./newlib-1.18.0/arm-eabi/thumb/arm9/newlib/libc.a ./newlib-1.18.0/arm-eabi/thumb/arm9/newlib/libc/libc.a ./newlib-1.18.0/arm-eabi/thumb/nointerwork/arm9/newlib/libc.a ./newlib-1.18.0/arm-eabi/thumb/nointerwork/arm9/newlib/libc/libc.a ./newlib-1.18.0/arm-eabi/thumb/nointerwork/arm9e/newlib/libc.a ./newlib-1.18.0/arm-eabi/thumb/nointerwork/arm9e/newlib/libc/libc.a ./newlib-1.18.0/arm-eabi/thumb/nointerwork/xscale/newlib/libc.a ./newlib-1.18.0/arm-eabi/thumb/nointerwork/xscale/newlib/libc/libc.a ./newlib-1.18.0/arm-eabi/thumb/nointerwork/newlib/libc.a ./newlib-1.18.0/arm-eabi/thumb/nointerwork/newlib/libc/libc.a ./newlib-1.18.0/arm-eabi/thumb/arm9e/newlib/libc.a ./newlib-1.18.0/arm-eabi/thumb/arm9e/newlib/libc/libc.a ./newlib-1.18.0/arm-eabi/thumb/be/nointerwork/xscale/newlib/libc.a ./newlib-1.18.0/arm-eabi/thumb/be/nointerwork/xscale/newlib/libc/libc.a ./newlib-1.18.0/arm-eabi/thumb/be/nointerwork/newlib/libc.a ./newlib-1.18.0/arm-eabi/thumb/be/nointerwork/newlib/libc/libc.a ./newlib-1.18.0/arm-eabi/thumb/be/xscale/newlib/libc.a ./newlib-1.18.0/arm-eabi/thumb/be/xscale/newlib/libc/libc.a ./newlib-1.18.0/arm-eabi/thumb/be/newlib/libc.a ./newlib-1.18.0/arm-eabi/thumb/be/newlib/libc/libc.a ./newlib-1.18.0/arm-eabi/thumb/xscale/newlib/libc.a ./newlib-1.18.0/arm-eabi/thumb/xscale/newlib/libc/libc.a ./newlib-1.18.0/arm-eabi/thumb/newlib/libc.a ./newlib-1.18.0/arm-eabi/thumb/newlib/libc/libc.a ./newlib-1.18.0/arm-eabi/thumb/thumb2/newlib/libc.a ./newlib-1.18.0/arm-eabi/thumb/thumb2/newlib/libc/libc.a ./newlib-1.18.0/arm-eabi/newlib/libc.a ./newlib-1.18.0/arm-eabi/newlib/libc/libc.a It seems that these actually come from the eCosPro toolchain: tom@zoo:/opt/xc/arm-eabi$ find -name '*libgcc*' ./lib/gcc/arm-eabi/4.3.2/arm9/libgcc.a ./lib/gcc/arm-eabi/4.3.2/nointerwork/arm9/libgcc.a ./lib/gcc/arm-eabi/4.3.2/nointerwork/arm9e/libgcc.a ./lib/gcc/arm-eabi/4.3.2/nointerwork/libgcc.a ./lib/gcc/arm-eabi/4.3.2/nointerwork/xscale/libgcc.a ./lib/gcc/arm-eabi/4.3.2/arm9e/libgcc.a ./lib/gcc/arm-eabi/4.3.2/be/nointerwork/libgcc.a ./lib/gcc/arm-eabi/4.3.2/be/nointerwork/xscale/libgcc.a ./lib/gcc/arm-eabi/4.3.2/be/libgcc.a ./lib/gcc/arm-eabi/4.3.2/be/xscale/libgcc.a ./lib/gcc/arm-eabi/4.3.2/libgcc.a ./lib/gcc/arm-eabi/4.3.2/xscale/libgcc.a ./lib/gcc/arm-eabi/4.3.2/thumb/arm9/libgcc.a ./lib/gcc/arm-eabi/4.3.2/thumb/nointerwork/arm9/libgcc.a ./lib/gcc/arm-eabi/4.3.2/thumb/nointerwork/arm9e/libgcc.a ./lib/gcc/arm-eabi/4.3.2/thumb/nointerwork/libgcc.a ./lib/gcc/arm-eabi/4.3.2/thumb/nointerwork/xscale/libgcc.a ./lib/gcc/arm-eabi/4.3.2/thumb/arm9e/libgcc.a ./lib/gcc/arm-eabi/4.3.2/thumb/be/nointerwork/libgcc.a ./lib/gcc/arm-eabi/4.3.2/thumb/be/nointerwork/xscale/libgcc.a ./lib/gcc/arm-eabi/4.3.2/thumb/be/libgcc.a ./lib/gcc/arm-eabi/4.3.2/thumb/be/xscale/libgcc.a ./lib/gcc/arm-eabi/4.3.2/thumb/libgcc.a ./lib/gcc/arm-eabi/4.3.2/thumb/xscale/libgcc.a ./lib/gcc/arm-eabi/4.3.2/thumb/thumb2/libgcc.a It's probably time to build my own toolchain for a single architecture. Yep, after building the toolchain from scratch, there are 3 variants: tom@zoo:~/libprim/at91sam7/newlib$ find -name libc.a ./newlib-1.20.0/arm-none-eabi/fpu/newlib/libc.a ./newlib-1.20.0/arm-none-eabi/fpu/newlib/libc/libc.a ./newlib-1.20.0/arm-none-eabi/thumb/newlib/libc.a ./newlib-1.20.0/arm-none-eabi/thumb/newlib/libc/libc.a ./newlib-1.20.0/arm-none-eabi/newlib/libc.a ./newlib-1.20.0/arm-none-eabi/newlib/libc/libc.a Entry: building toolchain Date: Tue Dec 4 20:07:02 EST 2012 Starting from here[1], but since 4.7 there is only a single tgz. Then found this[2]. Trouble: checking dynamic linker characteristics... configure: error: Link tests are not allowed after GCC_NO_EXECUTABLES. make: *** [configure-zlib] Error 1 Can be worked around[2] using the gcc configure option: --with-system-zlib make -j doesn't seem to work, but otherwise it works fine. See at91sam7/gnutools/Makefile I can compile the following test file: #include void main(void) { printf("hello\n"); } So what stubs does it use? The other newlib build uses --disable-newlib-supplied-syscalls so one would think that these are Linux syscalls then.. According to [3]: The “--disable-newlib-supplied-syscalls” option is necessary because otherwise Newlib compiles some pre-defined libraries for ARM that are useful in conjunction with debug features such as the RDI monitor. Apparently GDB is RDI aware[4]. ARM Angel debug monitor: [5] Remote Debug Monitor: [6] RDI is deprecated and replaced by RDDI, CADI, AGDI. I wonder if it's possible to build a full GCC with holes in newlib. Maybe better to just build it with standard support, and then disable it using -nostdlib -nostartfiles This comes from libgloss[7]: Gnu Low-level OS support. newlib-1.20.0/libgloss/arm/syscalls.c -> this refers do_AngelSWI, patching into Angel monitor using svc/swi calls. From newlib-1.20.0/newlib/configure.host : # If --disable-newlib-supplied-syscalls is specified, then the end-user # may specify the protocol via gcc spec files supplied by libgloss Spec files are mentioned here[8]. I found these in: Build of --disable-newlib-supplied-syscalls is finished. Indeed it now complains some symbols are not defined: tom@zoo:/tmp$ arm-none-eabi-gcc test.c /opt/xc/gnutools/lib/gcc/arm-none-eabi/4.7.2/../../../../arm-none-eabi/lib/libc.a(lib_a-exit.o): In function `exit': /home/tom/pub/darcs/libprim/at91sam7/gnutools/build/newlib-1.20.0/arm-none-eabi/newlib/libc/stdlib/../../../../../../newlib-1.20.0/newlib/libc/stdlib/exit.c:65: undefined reference to `_exit' /opt/xc/gnutools/lib/gcc/arm-none-eabi/4.7.2/../../../../arm-none-eabi/lib/libc.a(lib_a-sbrkr.o): In function `_sbrk_r': /home/tom/pub/darcs/libprim/at91sam7/gnutools/build/newlib-1.20.0/arm-none-eabi/newlib/libc/reent/../../../../../../newlib-1.20.0/newlib/libc/reent/sbrkr.c:58: undefined reference to `_sbrk' /opt/xc/gnutools/lib/gcc/arm-none-eabi/4.7.2/../../../../arm-none-eabi/lib/libc.a(lib_a-writer.o): In function `_write_r': /home/tom/pub/darcs/libprim/at91sam7/gnutools/build/newlib-1.20.0/arm-none-eabi/newlib/libc/reent/../../../../../../newlib-1.20.0/newlib/libc/reent/writer.c:58: undefined reference to `_write' /opt/xc/gnutools/lib/gcc/arm-none-eabi/4.7.2/../../../../arm-none-eabi/lib/libc.a(lib_a-closer.o): In function `_close_r': /home/tom/pub/darcs/libprim/at91sam7/gnutools/build/newlib-1.20.0/arm-none-eabi/newlib/libc/reent/../../../../../../newlib-1.20.0/newlib/libc/reent/closer.c:53: undefined reference to `_close' /opt/xc/gnutools/lib/gcc/arm-none-eabi/4.7.2/../../../../arm-none-eabi/lib/libc.a(lib_a-fstatr.o): In function `_fstat_r': /home/tom/pub/darcs/libprim/at91sam7/gnutools/build/newlib-1.20.0/arm-none-eabi/newlib/libc/reent/../../../../../../newlib-1.20.0/newlib/libc/reent/fstatr.c:62: undefined reference to `_fstat' /opt/xc/gnutools/lib/gcc/arm-none-eabi/4.7.2/../../../../arm-none-eabi/lib/libc.a(lib_a-isattyr.o): In function `_isatty_r': /home/tom/pub/darcs/libprim/at91sam7/gnutools/build/newlib-1.20.0/arm-none-eabi/newlib/libc/reent/../../../../../../newlib-1.20.0/newlib/libc/reent/isattyr.c:58: undefined reference to `_isatty' /opt/xc/gnutools/lib/gcc/arm-none-eabi/4.7.2/../../../../arm-none-eabi/lib/libc.a(lib_a-lseekr.o): In function `_lseek_r': /home/tom/pub/darcs/libprim/at91sam7/gnutools/build/newlib-1.20.0/arm-none-eabi/newlib/libc/reent/../../../../../../newlib-1.20.0/newlib/libc/reent/lseekr.c:58: undefined reference to `_lseek' /opt/xc/gnutools/lib/gcc/arm-none-eabi/4.7.2/../../../../arm-none-eabi/lib/libc.a(lib_a-readr.o): In function `_read_r': /home/tom/pub/darcs/libprim/at91sam7/gnutools/build/newlib-1.20.0/arm-none-eabi/newlib/libc/reent/../../../../../../newlib-1.20.0/newlib/libc/reent/readr.c:58: undefined reference to `_read' collect2: error: ld returned 1 exit status It does use its own start files. The thing to check is if the standard start files are usable or not. It's in: newlib-1.20.0/libgloss/arm/crt0.S It seems a lot simpler to use -nostdlib and -nostartfiles and do everything explicitly: - linker script - startfile - libc stubs - libc. So I wonder if when building gcc, the whole newlib and pass2 part can just be skipped since it doesn't seem to be really used when using -nostdlib -nostartfiles [1] http://www.kunen.org/uC/gnu_tool.html [2] http://www.infopoort.nl/index.php/Software:ARM_Toolchain [3] http://balau82.wordpress.com/2010/12/16/using-newlib-in-arm-bare-metal-programs/ [4] http://sourceware.org/gdb/onlinedocs/gdb/ARM.html [5] http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0066d/Babdcdih.html [6] http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka8256.html [7] http://ieee.uwaterloo.ca/coldfire/gcc-doc/docs/porting_1.html [8] http://gcc.gnu.org/onlinedocs/gcc-4.7.2/gcc/Spec-Files.html Entry: The ARM architecture is messy Date: Wed Dec 5 00:52:24 EST 2012 So ARM is not a tightly-knit family; it is more like an extended group of hostile ex-spouses and in-laws who have moved to different continents to get away from each other. [1] http://lwn.net/Articles/490457/ Entry: It's working, now what? Date: Wed Dec 5 15:56:54 EST 2012 Let's get a language running. What would it be? I'd like to do a CONS cell-based language, since the GC is so simple and reasonably efficient.