scale scale scale scale |
![]() |
scale scale scale scale |
|
Overview up down top In the following, I will collect some informations about how to deal with ARM µC code developement under linux. The data refers to my particular setup - debian linux testing (2.6.7) - gcc version 4.0.3 - JTAG interface: olimex's ARM-USB-OCD - target µC AT91SAM7X256 on the olimex SAM7-EX256 developement board and is not exhaustive. I try to not just report the used settings, but to explain where they come from. This should allow other users with other setups to set-up their own developement environment. I'm a 'newbie' to ARM developement. See my open questions below - 'guess most experienced ARM developers can answer them in a second. openocd - first contact up down top We have this brand new developement board and jtag connector. Before delving into the (lengthy) compilation of the gnuarm toolchain, we want to compile openocd, establish a first contact to our new toy, and discuss some important lock bit settings. download and install the drivers for the ftdi interface from ftdi. This is what I did: - untared - cp libftd2xx.so.0.4.10 /usr/lib/ - in /usr/lib: ln -s libftd2xx.so.0.4.9 libftd2xx.so - cp static_lib/libftd2xx.a.0.4.10 /usr/lib/ - in /usr/lib: ln -s libftd2xx.a.0.4.10 libftd2xx.a - cp ftd2xx.h /usr/include/ - cp WinTypes.h /usr/include/ - ldconfig openocd allows to use libftdi instead. What's the difference? There are two configure options that enable FT2232C support --enable-ft2232_ftd2xx and --enable-ft2232_libftdi used to choose which library gets used (you can only enable one). Libftdi has the advantage of being free software (a biiiig plus), therefor it's available on 32-bit linux, 64-bit linux, freebsd, ... - FTD2XX is available only on 32-bit linux, iirc. FTD2XX has the advantage of being faster, up to 4 or 5 times as fast as libftdi. dominic Now we are ready for the openocd compilation. Following the description on the homepage we - svn checkout svn://svn.berlios.de/openocd/trunk openocd - cd openocd - ./bootstrap - I needed an extra 'autoconf' to get the configure script - ./configure --enable-parport --enable-ft2232-ftd2xx --enable-amtjtagaccel - using the static library, I needed to recall the linker call in src with -ldl -lpthread - make install installs to /usr/local/bin/ - chmod u+s /usr/local/bin/openocd The last is crucial. Otherwize you'll get a 'failed to open device' as normal user. In order to be able to connect, we need an adequate .cfg file. The actual settings have benn kindly provided by dominic: #daemon configuration telnet_port 4444 gdb_port 3333 #interface interface ft2232 ft2232_device_desc "Olimex OpenOCD JTAG" ft2232_layout olimex-jtag ft2232_vid_pid 0x15ba 0x0003 #ft2232_device_desc "Amontec JTAGkey A" #ft2232_layout jtagkey #ft2232_vid_pid 0x0403 0xcff8 jtag_speed 0 #use combined on interfaces or targets that can't set TRST/SRST separately reset_config srst_only #jtag scan chain #format L IRC IRCM IDCODE (Length, IR Capture, IR Capture Mask, IDCODE) jtag_device 4 0x1 0xf 0xe #target configuration daemon_startup attach #target arm7tdmi (reset mode) (chainpos) (endianness) (variant) target arm7tdmi little run_and_halt 0 arm7tdmi-r4 #run_and_halt_time 0 30 #flash configuration #flash bank (type) (base) (size) (chip_width) (bus_width) #flash bank at91sam7 0 0 0 0 (target#) (base, size, chip and bus_width are read from the target) flash bank at91sam7 0 0 0 0 0 I included some description in mine. We can now connect the openocd server to the developement board: - check the jumpers: TST, JTAGSEL and ERASE open - plug the ARM-USB-OCD to the PC - power up the developement board - connect the jtag cable from the ARM-USB-OCD to the board - start openocd: openocd -f sam7_ft2232_olimex.cfg (use the -d option for further debugging information) talk to the device: - open a new shell - telnet localhost 4444 you should see something like Escape character is '^]'. Open On-Chip Debugger - halt the target: enter halt requesting target halt... Target 0 halted target halted in Thumb state due to debug request, current mode: System cpsr: 0x400000df pc: 0x0000014e - flash probe 0 flash 'at91sam7' found at 0x00100000 - flash info 0 #1: at91sam7 at 0x00100000, size 0x00040000, buswidth 4, chipwidth 0 at91sam7 information: cidr: 0x275b0940, arch: 0x0075, eproc: ARM7TDMI, version:0x000, flashsize: 0x00040000 master clock(estimated): 53248kHz pagesize: 256, lockbits: 16 0x0000, pages in lock region: 64 securitybit: 0, nvmbits: 0x4 - exit Note: If you can not connect to openocd with telnet, start openocd using the -d option. I noticed, that (for my setup) openocd sometimes takes more than 30s to come to a state where it accepts incoming conections. memory mapping and lock bits up down top In order to be able to flash code to the target, it is crucial to have an understandig of it's memory mapping and lock bit settings. Therefore I recommend that you read section 8.4 and 8.5 of atmel's official documentation! On the memory mapping page, we learn, that the bootmemory is located between 0x0000 0000 and 0x000F FFF, followed by the internal flash 0x0010 0000 - 0x001F FFF, followed by the internal sram 0x0020 0000 - 0x002F FFF and the internal rom 0x0030 0000 - 0x003F FFF. Why is this intersting? First, we see that the spacing is huge (1 MBytes). For a specific device, you can use no more than the amount of memory stated by the datasheet. This memory region lies in between the above stated adress and adress+x-kbytes. The point is, that the start adress for the boot,flash etc. sections is the same, independent of the special type of SAM7 controller. There is just more or less not used space in between. The device can boot from internal flash, sram or rom, depending on the below discussed settings. Note: Booting from internal rom starts the SAM-BA. This is a usual pitfall, as program code in flash or sram will not be executed! Let's start with the investigation of the lock, NVM and GNVM bits of the SAM7X (which will tell us how to configure the boot mode and enable the flash to be programmed). The 7X posesses 16 lock bits which 'write protect' the flash (bit set to 1). Each bit controls 16 kbytes of flash. Let's investigate and correct the actual setting using openocd: - fire up openocd and telnet to the server - halt - flash probe 0 - flash info 0 #1: at91sam7 at 0x00100000, size 0x00040000, buswidth 4, chipwidth 0 at91sam7 information: cidr: 0x275b0940, arch: 0x0075, eproc: ARM7TDMI, version:0x000, flashsize: 0x00040000 master clock(estimated): 53248kHz pagesize: 256, lockbits: 16 0x0003, pages in lock region: 64 securitybit: 0, nvmbits: 0x4 The lockbits: 16 0x0003 statement tells us that the lowest two lock bits (bin:011) are set to 1. Therefore 2 x 16 bytes of the flash are write protected. In order to correct this, use - flash protect 0 0 15 off which clears all 16 lock bits. The resulting lockbit statement should look like lockbits: 16 0x0000. The nvmbits: 0x4 statement means that the three nvm bits are set to bin:100. nvmbit 0 (the lsb [the rightmost bit]) and 1 control the brownout detector's behavior (they determine what happens when the supply voltage goes banana; read the manual for more information). nvmbit 2 (the leftmost digit) controls the boot behaviour and therefore is of interst. Set to 1 (as in the above example), it let's the 7X boot from flash/sram. 0 means booting from rom (into SAM-BA). You can change the setting using openocd's command - at91sam7 gpnvm be sure to execute - at91sam7 gpnvm 0 2 set to enable boot from flash/sram. These settings have to be redone in some cases. We will therefore atomate openocd later to in order to auto configuration after flash write. Our target is now configured to boot from flash/sram. By default, it boots from flash. If we execute a so called 'remap' function (in code) during startup, we can switch to sram boot. I will discuss this later (I'll first have to test this.). Now we are ready to flash some code into the target. But before we can do so, we need to work through the gnuarm toolchain preparation. gnuarm toolchain up down top In order to be able to compile code for the ARM target, we need a crosscompiler. I use the gnuarm compiler (just as most non professional ARM developers do). gnuarm does no longer provide binary packages for 32bit system. We therefore compile the toolchain consisting of (the list includes the version numbers I used) - binutils-2.17 - gcc-4.1.1 - newlib-1.14.0 - insight-6.5 ourselves. For this section, I had some kindly support from Dominic Rath (the developer of openocd). He pointed me to some scripts by Tom Walsh. The following compilation instructions are a combination of the original gnuarm instructions (see the bottom of the 'support' site), the above mentioned scripts and some of my own experience. First of all,download and unpack the above mentioned packages from the gnuarm page. (Note: Dominic and Tom reported the need for a patch in the newlib package [they used the original GNU and not hte gnuarm packages]. Using the above mentioned packages, I did not need the patch.) OK then, time to crunch: 1. cd [binutils-build] 2. [binutils-source] ./configure --target=arm-elf --prefix=[toolchain prefix] --enable-interwork --enable-multilib --with-gnu-ld --with-gnu-as [toolchain-prefix] is something like /opt/arm-elf-4.1.1 and determines where the resulting binaries/includes etc. will go. Note here and in the following, ./configure reports some errors about 'gmp.h'. As Matt stated, you can ignore these I think that's a false alarm. If I remember rightly, it's been reported in IRC a number of times too, but the real error that caused ./configure to bail out is actually further on. Try working up from the bottom of config.log to see if that points at where the real problem lies. If you run into problems (as I did here and there), rembember to don't get trapped by the gmp.h problem! 3. make all install 4. export PATH="$PATH:[toolchain-prefix]/bin" 5. cd [gcc-build] 6. [gcc-source]./configure --target=arm-elf --prefix=[toolchain-prefix] --enable-interwork --enable-multilib --enable-languages="c,c++" --with-newlib --with-headers=[newlib-source]/newlib/libc/include --with-gnu-as --with-gnu-ld --disable-shared --disable-libssp It is crucial to use '--disable-shared'. Otherwize you'll get the following error during make all: checking for shared libgcc... configure: error: Link tests are not allowed after GCC_NO_EXECUTABLES. you can find some discussion here I (Dominic and Tom too) had to use '--disable-libssp' to prevent armelf errors during make all. ssp is ram smashing protection. This is an error which should be fixed in 4.1.2. 7. make all-gcc install-gcc 8. cd [newlib-build] 9. [newlib-source]./configure --target=arm-elf --prefix=[toolchain-prefix] --enable-interwork --enable-multilib --disable-newlib-supplied-syscalls --with-gnu-ld --with-gnu-as --disable-newlib-io-float After the Makefile was created, Dominic and Tom applied a patch which added "-DREENTRANT_SYSCALLS_PROVIDED -DINTEGER_ONLY -DPREFER_SIZE_OVER_SPEED -DNO_FLOATING_POINT" to the definition of CFLAGS_FOR_TARGET. This changes the deafult behaviour of the newlib. If you have any comment about this, let me know. 10. make all install 11. cd [gcc-build] 12. make all install 13. cd [gdb-build] 14. [gdb-source]./configure --target=arm-elf --prefix=[toolchain-prefix] --enable-interwork --enable-multilib --with-gnu-ld --with-gnu-as 15. make all install Now you should be able to compile code for ARM µC's: >arm-elf-gcc -mcpu=arm7tdmi -mthumb -O2 -g -c hello_world.c >arm-elf-gcc -mcpu=arm7tdmi -mthumb -o hello_world hello_world.o /opt/arm-elf-4.1.1/arm-elf/lib/thumb/redboot-syscalls.o -lc wondering about the syscalls object? read this. dump/flash SAM7X internal memory up down top If you made it till here, you deserved a little more playing with the SAM7 developement board before setting up the makefiles for compilation. Be sure to use this .cfg file. - openocd -f sam7_ft2232_olimex2.cfg - telnet localhost 4444 - flash probe 0 - flash info 0 (ensure that the lock bits are cleared) - dump the flash: dump binary (file) (address) (size) in our case: dump binary orig.bin 0x00 0x00040000 which means that we dump the complete intenal flash. Now having a copy of the original democode, we can erase the flash just for fun/testing. Note: rewriting the orig.bin after flash erase and reset of the target takes several minutes (abt. 10). This is because we erase the init code which sets the internal master clock to high speed (flash info tells us, that the master clock(estimated) originally was 53289kHz while beeing ~3kHz after erase/reset). One can fix this using openocd's mmw commands. I use them in the openocd automation script sam7_ft2232_olimex_auto.script . Anyhow - after rewriting the original code to flash, everything is as it was. - flash erase 0 0 15 (15 because we have 16 bits [0-15] which control the access to the flash memory) - shutdown the openocd server - reset the target -> the lcd stays black - reconnect openocd to the target - flash probe 0 - flash write 0 orig.bin 0x0 - reset run - shutdown ... and here we go again with the original code. Ok, back to work... let's set up a makefile and compile a simple demo application. makefile setup up down top I like tidy workplaces and therefore use a structure with separate src, include, bin and obj directories. See my makefile for more informations. We will concentrate on the essential parts: - choose to compile debugging or optimized code in line 18. - below, choose if the code should be flased into ram istead of flash (for special debugging reasons). Starting at line 183 choose: - LLIBS, the libs which sould be linked with your code (in our case empty) - OBJ, the objects your code consists of (only the c source) - ASM, the objects which correspond to asm source files - PROJNAME, the prefix of the final binary The rest goes automated. After 'make' or 'make new', you'll find the objects in bin/obj and the binary in bin/. Use a 'make flash' to flash the code to your µC. small example code up down top Find the complede example including make-, source-, header-, linker-, and openocd files here. This is just a small code which initializes the SAM7X on the board to a defined state and blinks the backlight of the lcd. Some more code will follow. After 'make new', 'make flash', your backlight should switch on/off in intervals of abt. 3s. debugging using ddd up down top This is what I did in order to be able to debug the code in system via JTAG: - compile the code with debug option (TDEBUG = true) - start openocd (be sure that it accepts telnet connections) - start ddd: ddd --debugger "arm-elf-gdb" - in the gdb command line (at the bottom) enter: - target remote localhost:3333 - monitor soft_reset_halt - monitor arm7_9 force_hw_bkpts enable - symbol-file bin/obj/main.out - thbreak main here ddd complains about main.c. Ignore this and - use the file - open dialog to open src/main.c - in the gdb command line (at the bottom) enter: - continue - have some fun Note that you can only use two brakpoints with this setup. For more than two, the code needs to be flashed into sram. Then, you can use as much software breakpoints as you like. I usually point the mouse to a certain line in source code, right-click and choose 'continue untile here'. This allows you to take steps to any position, with the need for just one (automatically created and deleted) breakpoint. As this tutorial should help you just to get started, see one of the debugging tutorials available in the net for more informations about software breakpoints. open questions up down top In the following I collect some open question which have to be investigated. Any hint is appreciated. - write some strings onto the color lcd panel (using part of this code by Jimbo) Marden P. Marshall solved this: I posted a question regarding which controller was used with the LCD display that Olimex ships with the board on the Sparkfun support board. Someone came back and thought that it might be a Philips PCF8833. With that new knowledge and a copy of the PCF8833 data sheet in hand, I have been able to get Jimbo's basic pixel level algorithms to work. The only major change from what he was doing was in how the display resolution is set. On the PCF8833, the resolution is set by the COLMOD command (3AH). Follow that command with a data value of 2 puts the display into a 3:3:2 RGB mode that is now compatible with his text writing code. Also be sure to set up the LUT using the RGBSET command. downloads up down top This is a list of all downloadable files:
resources up down top I used the following resources:
hints up down top For interrupt handling, one needs to initialize the interrupt vecors in a special way. For this purpose, I extended my lowlevel init. The examples of Martin Thomas and Atmel's application notes 'Interrupt Management: Auto-vectoring (doc1168.pdf) have been very helpful. |
|||||