Using OpenOCD
Using OpenOCD
This section presents OpenOCD, a tool used to program eLua on some of its targets. If you'd rather skip the long and boring OpenOCD introduction and skip directly to the OpenOCD script downloads, use the links below.
- Configuration files for STR9-comStick
- Configuration files for STR-E912
- Configuration files for LPC2888
- Configuration files for STR7
About OpenOCD
OpenOCD is an open source tool that can be used to connect to a CPU's JTAG interface. Using OpenOCD and a physical JTAG connection allows you to burn the on-chip flash memory of your CPU (or to load your code directly to RAM), to read the internal CPU memory (Flash/RAM) and to use gdb or other debuggers to debug your code. Needless to say, this is a very handy tool (and especially handy if your CPU happens to be built around an ARM core, since in this case you can be almost certain that it has a JTAG interface that you can use). That said, if your only goal is to burn your firmware, my personal suggestion is to avoid using OpenOCD if possible. It has quite a steep learning curve, because it is a command line tool that uses configuration files with lots of different parameters, and this takes a while to get used to. Worse, I feel that it is not very well docummented. The project's wiki does give a few good pointers about all the configuration parameters, and there are some good OpenOCD tutorials out there, but none of them tells the whole story. And the syntax (and even some commands) seems to change between releases, which makes things even more confusing. This is why I generally choose to use a different firmware burning tool when available, and resort to OpenOCD only for targets that lack a proper firmware burning tool. If you need to debug your code, however, you probably want to use OpenOCD, since the alternatives aren't cheap. To summarize, you can forget about OpenOCD when:
- your CPU manufacturer provides a special tool for firmware burning. This is quite often the case, but more often that not the aforementioned tools work only in Windows.
- you must debug your code, but you have a good intuition about where the problem is located. In this case, simply connecting a LED to a PIO port and turning it on and off from different parts of your code until you figure out exactly what's the problem can work wonders. I can't remember when was the last time I used gdb for debugging, since "LED debugging" was all I needed.
On the other hand, you should probably use OpenOCD when:
- your CPU manufacturer doesn't provide a special tool for firmware burning (or it does, but it's not what you need).
- you're using Linux, MacOS or another OS that is not supported by the firmware burning tool.
- you need to do some serious debugging in order to understand what's wrong with your application.
If you decided that you don't need OpenOCD after all, now it's a good time to navigate away from this page and save yourself from some possible symptoms of headache. If you need OpenOCD, read on, I'll try to make this as painless as possible. However, don't expect this to be a full tutorial on OpenOCD, because it's not; my intention is to give you just enough data to use OpenOCD for burning eLua on your board. Because of this, I won't be covering debugging with OpenOCD here, just firmware burning. And, before we begin, please read and understand the next paragraph.
Disclaimer
Using OpenOCD improperly may force your CPU to behave unexpectedly. While physically damaging your CPU as a result of using OpenOCD is very hard to accomplish, you might end up with a locked chip, or you might erase a memory area that was not supposed to be erased, you might even disable the JTAG interface on your chip (thus rendering it unusable). If you modify the configuration scripts that I'm going to provide, make sure that you know what you're doing. Also, I'm not at all an OpenOCD expert, so my configuration scripts might have errors, even though I tested them. In short, this tutorial comes without any guarantees whatsoever.
Getting OpenOCD
If you're on Windows, the best way to get OpenOCD already compiled and ready to run is to visit the Yagarto home page. They provide a very nice OpenOCD installer, and they seem to keep up with OpenOCD progress (the versions on the Yagarto site are not "bleeding edge", but there are quite fresh nevertheless). If you're on Linux, you can always use apt-get or your distribution-specific package manager:
$ sudo apt-get install openocd
There is a catch here though: the OpenOCD version that I get from apt-get is dated 2007-09-05, while the Yagarto OpenOCD version is from 2008-06-19. Since I'm using OpenOCD from Windows (because Ubuntu 8.04 doesn't seem to handle my USB-to-JTAG adapters very well), my instructions are relevant to the Yagarto version. As mentioned in the introduction, the meaning and parameters of different commands might change between OpenOCD version, so if you want to use the Yagarto version on your non Windows system, you'll have to build it from source (see below).
The main resource on how to build OpenOCD from source is the OpenOCD build page from the OpenOCD wiki. Also, a very good tutorial can be found here. I'm not going to provide step by step build instructions, since the two links that I mentioned cover this very well, and the build process is relatively straightforward. However, since both tutorials describe how to build the bleeding edge version of OpenOCD, you'll need a slight modification do build the Yagarto version instead. The modification is in the SVN checkout step. Replace this step:
$ svn checkout svn://svn.berlios.de/openocd/trunk
with this step ('717' is the SVN revision of the Yagarto OpenOCD build):
$ svn checkout -r 717 svn://svn.berlios.de/openocd/trunk
Follow the rest of the build instructions, and in the end you should have a working OpenOCD.
Supported targets
I couldn't find a good list of the targets that are supported by OpenOCD. So, if you want to check if your particular CPU is supported by OpenOCD, I recommend getting the latest sources (as described in the previous section) and listing the trunk/src/target/target directory:
$ ls trunk/src/target/target
at91eb40a.cfg
at91r40008.cfg
....
str9comstick.cfg
....
If this listing has something that looks like your CPU name, you're lucky. OpenOCD has support for LPC from NXP, AT91SAM cfrom Atmel, STR7/STR9 from ST, and many others.
Using OpenOCD
To use OpenOCD, you'll need:
- the OpenOCD executable, as described above
- a board with a JTAG interface
- a JTAG adapter
In some cases, your CPU board might provide a built in JTAG adapter. For example, my LM3S8962 board provides both an USB-to-JTAG and an USB-to-serial converter built on board, switching between them automagically. The same is true for my STR9-comStick. On the other hand, my SAM7-EX256 board has only a JTAG connector, I need a separate JTAG adapter to connect to it. I'm using ARM-USB-TINY from Olimex, but there are other affordable USB-to-JTAG adapters out there, like the Amontec JTAGKey-Tiny. Not to mention that you can build your own. Although USB is my interface of choice, you'll find JTAG adapters for PC LPT ports too. The good news is that once you buy a JTAG adapter, chances are that it will work with many boards with different CPUs, since the JTAG connector layout is standardized and the JTAG adapters are generally able to work with different voltages.
To actually use OpenOCD, the next thing you'll need is a configuration file. The configuration file is the one that lets OpenOCD know about your setup, such as:
- the kind of JTAG interface that you're using.
- the actual hardware platform you're using (ATM7TDMI, ARM966 and so on).
- the memory configuration of your CPU (flash banks).
- the script used to program the flash memory.
Presenting a list of all the possible configuration options and their meaning is way beside the scope of this document, so I'm not going to do it, I'll give an example instead. I'm going to use parts of my STR9-comStick configuration file (comstick.cfg) adapted from the OpenOCD distribution and from other examples (don't worry, I'll provide full download links for this file later on). First we need to tell OpenOCD that we're using a the STR9-comStick USB-to-JTAG adapter:
interface ft2232
ft2232_device_desc "STR9-comStick A"
ft2232_layout comstick
ft2232_vid_pid 0x0640 0x002C
jtag_speed 4
jtag_nsrst_delay 100
jtag_ntrst_delay 100
Also, OpenOCD needs to know what's our target and its memory layout:
target arm966e little run_and_init 1 arm966e
run_and_halt_time 0 50
working_area 0 0x50000000 32768 nobackup
flash bank str9x 0x00000000 0x00080000 0 0 0
flash bank str9x 0x00080000 0x00008000 0 0 0
This tells OpenOCD that our target is an ARM966-E running in little endian mode, with two flash memory banks, one that starts at 0x0 and it's 0x80000 bytes in size, and another one that starts at 0x80000 and it's 0x8000 bytes in size. Finally, OpenOCD must know what's the name of our script file (this is the file that is used to physically program the CPU memory):
#Script used for FLASH programming
target_script 0 reset str91x_flashprogram.script
The contents of the str91x_flashprogram.script is very target-dependent:
wait_halt
str9x flash_config 0 4 2 0 0x80000
flash protect 0 0 7 off
flash erase_sector 0 0 7
flash write_bank 0 main.bin 0
reset run
sleep 10
shutdown
I'm not even going to attempt to explain this one :) Basically it unprotects the flash, erases it, writes the contents of "main.bin" to flash, and then resets the CPU. If you need to flash a file with a different name, the only thing you need to modify is the "main.bin" in the "flash write_bank" line.
To use all this, you need to tell OpenOCD to use our configuration file:
openocd-ftd2xx -f comstick.cfg
(note: under Windows, the OpenOCD executable name is often "openocd-ftd2xx". Under Linux it's simply "openocd". Replace it with the actualy name with your executable).
That's it for your OpenOCD crash course. I realise that there's much more to learn, so here's a list of links with much better information on the subject:
- OpenOCD quick reference card. (slightly outdated)
- OpenOCD configuration examples from the official OpenOCD wiki.
- An excellent page about using OpenOCD with ARM controllers, with lots of real life examples.
- An interesting topic on the SparkFun forum about STR9 and OpenOCD.
Configuration files for STR9-comStick
Download them below:
For STR9 I'm using the Yagarto OpenOCD build for Windows (repository version 717, as described at the beginning of this tutorial).The comstick.cfg configuration file is for programming the STR9-comStick. comrst.cfg is for resetting it. The comStick has a very interesting habit: after you power it (via USB) it does not start executing the code from the internal flash, you need to execute OpenOCD with the comreset.cfg script to start it. comrst.cfg does exactly what it says: executes a CPU reset (since the board doesn't have a RESET button). This is a very peculiar behavior, and I'm not sure if it's generic or it's only relevant to my particular comStick. I suspect that the CPU RESET line isn't properly handled by the on-board USB-to-JTAG converter, and the only solution I have for this is to execute this script everytime you power the board and everytime you need to do a RESET. To use the programming script, invoke the OpenOCD executable like this:
openocd-ftd2xx -f comstick.cfg
(note: under Windows, the OpenOCD executable name is often "openocd-ftd2xx". Under Linux it's simply "openocd". Replace it with the actualy name with your executable).
Also, be sure to modify str91x_flashprogram.script if your image name is not main.bin
Configuration files for STR-E912 (Olimex)
Download them below:
For the STR-E912 board I'm using the Yagarto OpenOCD build for Windows (repository version 717, as described at the beginning of this tutorial). As this board doesn't have a built-in USB to JTAG adapter, an external one is needed. The one used by the str-e912.cfg script is the ARM-USB-OCD adapter (also from Olimex). The str-e912.cfg configuration file is for programming the board. To use the programming script, invoke the OpenOCD executable like this:
openocd-ftd2xx -f str-e912.cfg
(note: under Windows, the OpenOCD executable name is often "openocd-ftd2xx". Under Linux it's simply "openocd". Replace it with the actualy name with your executable).
Also, be sure to modify str91x_flashprogram.script if your image name is not main.bin
Configuration files for LPC2888
LPC2888 is quite a different animal. I couldn't find any "official" LPC2888 configuration file for OpenOCD, so I had to learn how to write my own. It works, but I suspect it can be improved. This time, the configuration file applies to the latest (SVN) version of OpenOCD, so use this tutorial to understand how to get the latest OpenOCD sources and how to compile them (this section is based on version 922 of the OpenOCD repository). Then use the next file to burn your binary image to the chip:
If your image name is not main.bin edit the file and change the corresponding line (flash write_bank 0 main.bin 0), then invoke openocd like this:
openocd -f lpc2888.cfg
I'm using ARM-USB-TINY from Olimex, but it should be easy to use the script with any other JTAG adapter (don't forget to change the script to match your adapter).
Configuration files for STR711FR2 (STR7 from ST)
Download them below:
For STR7 I'm using the Yagarto OpenOCD build for Windows (repository version 717, as described at the beginning of this tutorial). The str7prg.cfg configuration file is for programming the STR9-comStick. str7rst.cfg is for resetting it (you probably won't need this one). I'm using a STR711FR2 heard board from ScTec to which I attached a few LEDs and a MAX3232 TTL to RS232 converter for the serial communication. The board comes with its own JTAG adapter, but it uses a parallel interface, and since my computer doesn't have one, I used the ARM-USB-TINY from Olimex. To use them, invoke the OpenOCD executable like this:
openocd-ftd2xx -f str7prg.cfg
(note: under Windows, the OpenOCD executable name is often "openocd-ftd2xx". Under Linux it's simply "openocd". Replace it with the actualy name with your executable).
Also, be sure to modify str7_flashprogram.script if your image name is not main.bin