Next: , Previous: OpenOCD Project Setup, Up: Top


7 Config File Guidelines

This chapter is aimed at any user who needs to write a config file, including developers and integrators of OpenOCD and any user who needs to get a new board working smoothly. It provides guidelines for creating those files.

You should find the following directories under $(INSTALLDIR)/scripts:

The openocd.cfg user config file may override features in any of the above files by setting variables before sourcing the target file, or by adding commands specific to their situation.

7.1 Interface Config Files

The user config file should be able to source one of these files with a command like this:

     source [find interface/FOOBAR.cfg]

A preconfigured interface file should exist for every interface in use today, that said, perhaps some interfaces have only been used by the sole developer who created it.

A separate chapter gives information about how to set these up. See Interface - Dongle Configuration. Read the OpenOCD source code if you have a new kind of hardware interface and need to provide a driver for it.

7.2 Board Config Files

The user config file should be able to source one of these files with a command like this:

     source [find board/FOOBAR.cfg]

The point of a board config file is to package everything about a given board that user config files need to know. In summary the board files should contain (if present)

  1. One or more source [target/...cfg] statements
  2. NOR flash configuration (see NOR Configuration)
  3. NAND flash configuration (see NAND Configuration)
  4. Target reset handlers for SDRAM and I/O configuration
  5. JTAG adapter reset configuration (see Reset Configuration)
  6. All things that are not “inside a chip”

Generic things inside target chips belong in target config files, not board config files. So for example a reset-init event handler should know board-specific oscillator and PLL parameters, which it passes to target-specific utility code.

The most complex task of a board config file is creating such a reset-init event handler. Define those handlers last, after you verify the rest of the board configuration works.

7.2.1 Communication Between Config files

In addition to target-specific utility code, another way that board and target config files communicate is by following a convention on how to use certain variables.

The full Tcl/Tk language supports “namespaces”, but JIM-Tcl does not. Thus the rule we follow in OpenOCD is this: Variables that begin with a leading underscore are temporary in nature, and can be modified and used at will within a target configuration file.

Complex board config files can do the things like this, for a board with three chips:

     # Chip #1: PXA270 for network side, big endian
     set CHIPNAME network
     set ENDIAN big
     source [find target/pxa270.cfg]
     # on return: _TARGETNAME = network.cpu
     # other commands can refer to the "network.cpu" target.
     $_TARGETNAME configure .... events for this CPU..
     
     # Chip #2: PXA270 for video side, little endian
     set CHIPNAME video
     set ENDIAN little
     source [find target/pxa270.cfg]
     # on return: _TARGETNAME = video.cpu
     # other commands can refer to the "video.cpu" target.
     $_TARGETNAME configure .... events for this CPU..
     
     # Chip #3: Xilinx FPGA for glue logic
     set CHIPNAME xilinx
     unset ENDIAN
     source [find target/spartan3.cfg]

That example is oversimplified because it doesn't show any flash memory, or the reset-init event handlers to initialize external DRAM or (assuming it needs it) load a configuration into the FPGA. Such features are usually needed for low-level work with many boards, where “low level” implies that the board initialization software may not be working. (That's a common reason to need JTAG tools. Another is to enable working with microcontroller-based systems, which often have no debugging support except a JTAG connector.)

Target config files may also export utility functions to board and user config files. Such functions should use name prefixes, to help avoid naming collisions.

Board files could also accept input variables from user config files. For example, there might be a J4_JUMPER setting used to identify what kind of flash memory a development board is using, or how to set up other clocks and peripherals.

7.2.2 Variable Naming Convention

Most boards have only one instance of a chip. However, it should be easy to create a board with more than one such chip (as shown above). Accordingly, we encourage these conventions for naming variables associated with different target.cfg files, to promote consistency and so that board files can override target defaults.

Inputs to target config files include:

Outputs from target config files include:

7.2.3 The reset-init Event Handler

Board config files run in the OpenOCD configuration stage; they can't use TAPs or targets, since they haven't been fully set up yet. This means you can't write memory or access chip registers; you can't even verify that a flash chip is present. That's done later in event handlers, of which the target reset-init handler is one of the most important.

Except on microcontrollers, the basic job of reset-init event handlers is setting up flash and DRAM, as normally handled by boot loaders. Microcontrollers rarely use boot loaders; they run right out of their on-chip flash and SRAM memory. But they may want to use one of these handlers too, if just for developer convenience.

Note: Because this is so very board-specific, and chip-specific, no examples are included here. Instead, look at the board config files distributed with OpenOCD. If you have a boot loader, its source code may also be useful.

Some of this code could probably be shared between different boards. For example, setting up a DRAM controller often doesn't differ by much except the bus width (16 bits or 32?) and memory timings, so a reusable TCL procedure loaded by the target.cfg file might take those as parameters. Similarly with oscillator, PLL, and clock setup; and disabling the watchdog. Structure the code cleanly, and provide comments to help the next developer doing such work. (You might be that next person trying to reuse init code!)

The last thing normally done in a reset-init handler is probing whatever flash memory was configured. For most chips that needs to be done while the associated target is halted, either because JTAG memory access uses the CPU or to prevent conflicting CPU access.

7.2.4 JTAG Clock Rate

Before your reset-init handler has set up the PLLs and clocking, you may need to use a low JTAG clock rate; then you'd increase it later. (The rule of thumb for ARM-based processors is 1/8 the CPU clock.) If the board supports adaptive clocking, use the jtag_rclk command, in case your board is used with JTAG adapter which also supports it. Otherwise use jtag_khz. Set the slow rate at the beginning of the reset sequence, and the faster rate as soon as the clocks are at full speed.

7.3 Target Config Files

Board config files communicate with target config files using naming conventions as described above, and may source one or more target config files like this:

     source [find target/FOOBAR.cfg]

The point of a target config file is to package everything about a given chip that board config files need to know. In summary the target files should contain

  1. Set defaults
  2. Add TAPs to the scan chain
  3. Add CPU targets (includes GDB support)
  4. CPU/Chip/CPU-Core specific features
  5. On-Chip flash

As a rule of thumb, a target file sets up only one chip. For a microcontroller, that will often include a single TAP, which is a CPU needing a GDB target, and its on-chip flash.

More complex chips may include multiple TAPs, and the target config file may need to define them all before OpenOCD can talk to the chip. For example, some phone chips have JTAG scan chains that include an ARM core for operating system use, a DSP, another ARM core embedded in an image processing engine, and other processing engines.

7.3.1 Default Value Boiler Plate Code

All target configuration files should start with code like this, letting board config files express environment-specific differences in how things should be set up.

     # Boards may override chip names, perhaps based on role,
     # but the default should match what the vendor uses
     if { [info exists CHIPNAME] } {
        set  _CHIPNAME $CHIPNAME
     } else {
        set  _CHIPNAME sam7x256
     }
     
     # ONLY use ENDIAN with targets that can change it.
     if { [info exists ENDIAN] } {
        set  _ENDIAN $ENDIAN
     } else {
        set  _ENDIAN little
     }
     
     # TAP identifiers may change as chips mature, for example with
     # new revision fields (the "3" here).  Pick a good default; you
     # can pass several such identifiers to the "jtag newtap" command.
     if { [info exists CPUTAPID ] } {
        set _CPUTAPID $CPUTAPID
     } else {
        set _CPUTAPID 0x3f0f0f0f
     }

Remember: Board config files may include multiple target config files, or the same target file multiple times (changing at least CHIPNAME).

Likewise, the target configuration file should define _TARGETNAME (or _TARGETNAME0 etc) and use it later on when defining debug targets:

     set _TARGETNAME $_CHIPNAME.cpu
     target create $_TARGETNAME arm7tdmi -chain-position $_TARGETNAME

7.3.2 Adding TAPs to the Scan Chain

After the “defaults” are set up, add the TAPs on each chip to the JTAG scan chain. See TAP Declaration, and the naming convention for taps.

In the simplest case the chip has only one TAP, probably for a CPU or FPGA. The config file for the Atmel AT91SAM7X256 looks (in part) like this:

     jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf \
             -expected-id $_CPUTAPID

A board with two such at91sam7 chips would be able to source such a config file twice, with different values for CHIPNAME, so it adds a different TAP each time.

If there are one or more nonzero -expected-id values, OpenOCD attempts to verify the actual tap id against those values. It will issue error messages if there is mismatch, which can help to pinpoint problems in OpenOCD configurations.

     JTAG tap: sam7x256.cpu tap/device found: 0x3f0f0f0f
                     (Manufacturer: 0x787, Part: 0xf0f0, Version: 0x3)
     ERROR: Tap: sam7x256.cpu - Expected id: 0x12345678, Got: 0x3f0f0f0f
     ERROR: expected: mfg: 0x33c, part: 0x2345, ver: 0x1
     ERROR:      got: mfg: 0x787, part: 0xf0f0, ver: 0x3

There are more complex examples too, with chips that have multiple TAPs. Ones worth looking at include:

7.3.3 Add CPU targets

After adding a TAP for a CPU, you should set it up so that GDB and other commands can use it. See CPU Configuration. For the at91sam7 example above, the command can look like this; note that $_ENDIAN is not needed, since OpenOCD defaults to little endian, and this chip doesn't support changing that.

     set _TARGETNAME $_CHIPNAME.cpu
     target create $_TARGETNAME arm7tdmi -chain-position $_TARGETNAME

Work areas are small RAM areas associated with CPU targets. They are used by OpenOCD to speed up downloads, and to download small snippets of code to program flash chips. If the chip includes a form of “on-chip-ram” - and many do - define a work area if you can. Again using the at91sam7 as an example, this can look like:

     $_TARGETNAME configure -work-area-phys 0x00200000 \
                  -work-area-size 0x4000 -work-area-backup 0

7.3.4 Chip Reset Setup

As a rule, you should put the reset_config command into the board file. Most things you think you know about a chip can be tweaked by the board.

Some chips have specific ways the TRST and SRST signals are managed. In the unusual case that these are chip specific and can never be changed by board wiring, they could go here.

Some chips need special attention during reset handling if they're going to be used with JTAG. An example might be needing to send some commands right after the target's TAP has been reset, providing a reset-deassert-post event handler that writes a chip register to report that JTAG debugging is being done.

7.3.5 ARM Core Specific Hacks

If the chip has a DCC, enable it. If the chip is an ARM9 with some special high speed download features - enable it.

If present, the MMU, the MPU and the CACHE should be disabled.

Some ARM cores are equipped with trace support, which permits examination of the instruction and data bus activity. Trace activity is controlled through an “Embedded Trace Module” (ETM) on one of the core's scan chains. The ETM emits voluminous data through a “trace port”. (See ARM Tracing.) If you are using an external trace port, configure it in your board config file. If you are using an on-chip “Embedded Trace Buffer” (ETB), configure it in your target config file.

     etm config $_TARGETNAME 16 normal full etb
     etb config $_TARGETNAME $_CHIPNAME.etb

7.3.6 Internal Flash Configuration

This applies ONLY TO MICROCONTROLLERS that have flash built in.

Never ever in the “target configuration file” define any type of flash that is external to the chip. (For example a BOOT flash on Chip Select 0.) Such flash information goes in a board file - not the TARGET (chip) file.

Examples: