OpenOCD for AT91SAM7SE - Part 8
This is part 8 of our OpenOCD for AT91SAM7SE tutorial.
OpenOCD Script Conventions
So far we have stored our complete configuration in a local file named openocd.cfg, which is loaded by OpenOCD automatically, if it exists.
In this part we will split this configuration into several files to make it a bit more re-usable. OpenOCD allows to include external configuration files into our local configuration. So we may re-write openocd.cfg to something like
add_script_search_dir [/usr/share/openocd/scripts] source [find interface/turtelizer2.cfg] source [find board/eir.cfg]
where board/eir.cfg further includes the CPU configuration by using
source [find target/at91sam7se512.cfg]
Actually OpenOCD provides a number of prepared configuration scripts, which you may use for your specific configuration. We will also discuss the conventions used in these scripts.
Separating Adapter Configurations
Obviously, it will make a lot of sense to move adapter specific configurations into a separate configuration file. It allows to use the same target board with different JTAG adapters. However, the devil is in the details. Let's take a look to the reset configuration as an example. We defined
reset_config srst_only
which is perfect when using Turtelizer 2 Rev-B with the EIR board, because neither of them provides the TAP reset signal nTRST. However, Turtelizer 2 Rev-C does provide it, and the same is true for Ethernut 5. The following table shows, that the reset configuration can't be clearly assigned to the adapter or the board, because it depends on both.
Turtelizer 2.0B | Turtelizer 2.0C | |
---|---|---|
EIR | srst_only | srst_only |
Ethernut 5 | srst_only | trst_and_srst |
The OpenOCD manual states, that reset_config belongs to the board configuration. That doesn't make much sense either, because in most cases this is CPU specific. In very rare cases the board may not route the nTRST signal to the JTAG connector, although it's available on the CPU. Fact is, that in the official OpenOCD distribution reset_config is provided in about 75 board configurations, but also, against the stated rule, in nearly 50 CPU configurations. This includes the configuration for the AT91SAM7SE, which is even wrongly specified, as far as I can say:
reset_config srst_only srst_pulls_trst ;# This is incorrect, do not use!
As explained, nTRST doesn't matter for the AT91SAM7SE and we can painlessly fulfill the rule, assigning it to the board configuration. So, the following lines are left for our adapter configuration:
interface ft2232 ft2232_layout turtelizer2 ft2232_device_desc "Turtelizer JTAG/RS232 Adapter" ft2232_vid_pid 0x0403 0xbdc8
Again, you may have to replace interface ft2232 by interface turtle when using the Turtelizer support package.
Also note, that the last line, specifying VID and PID, is not really required. When using more than one Turtelizer concurrently on the same PC, you must create a separate configuration file for each of them and additionally declare the unique serial number of the individual adapter in each file.
ft2232_serial <serial number>
Separating CPU and Board Configurations
Without question, separating CPU and board specific configuration has the advantage, that we can re-use CPU configurations for other boards which are based on the same CPU. Again, some configuration items may not be clearly assignable to either the CPU or the board.
Definitely, the reset-init event handler and all the procedures called from within this handler belong to the board configuration. Other board may use
- different crystals (eir_init_clock)
- different or no SDRAM (eir_init_sdram)
- the memory bus pins for GPIO (eir_init_membus)
As discussed above, we will also assign the reset configuration to the board. Here is the resulting file:
reset_config srst_only adapter_khz 8 sam7se512.cpu configure -event reset-init { eir_init } # Initialize the EIR board. # proc eir_init {} { eir_init_clock # Minimum ICE cycle time is 102ns (9800 kHz) adapter_khz 9800 arm7_9 dcc_downloads enable arm7_9 fast_memory_access enable eir_init_membus eir_init_sdram } # Initialize the EIR clocks. # # The board uses an 18.432MHz crystal. # Let the CPU run at 48MHz. # proc eir_init_clock {} { # Enable main oscillator. # # Start-up time of 6 x 8 slow clocks. # mww 0xfffffc20 0x00000601 ;# CKGR_MOR sleep 2 # Configure the PLL. # # 18.432MHz * (72 + 1) / 14 = 96MHz # # Divider 14 (0x0e) # Start-up time of 28 (0x1c) slow clocks # Multiplier 72 (0x48) # mww 0xfffffc2C 0x00481c0e ;# CKGR_PLLR sleep 1 # Select PLL clock and divide it by 2 # # 96MHz / 2 = 48MHz # mww 0xfffffc30 0x00000007 ;# PMC_MCKR sleep 1 # 1 wait for read, 2 waits for write # We have 48 master clocks in 1us mww 0xffffff60 0x00480100 ;# MC_FMR } # Initialize external memory bus. # proc eir_init_membus {} { # Enable address bus (A0, A2-A11, A13-A17) at PIO B mww 0xfffff674 0x0003effd ;# PIOB_BSR mww 0xfffff604 0x0003effd ;# PIOB_PDR # Enable 16 bit data bus at PIO C mww 0xfffff870 0x0000ffff ;# PIOC_ASR mww 0xfffff804 0x0000ffff ;# PIOC_PDR } # Initialize the EIR SDRAM. # # EIR uses Samsung K4S511632D-UC75 SDRAM: # Organization: 32M x 16 # 8k rows, 1k columns # 20ns row precharge time # 45ns min. and 100us max. row active time # # MCK cycle is 20ns when running at 48MHz. # proc eir_init_sdram {} { # Enable SDRAM control at PIO A # mww 0xfffff474 0x3f800000 ;# PIOA_BSR mww 0xfffff404 0x3f800000 ;# PIOA_PDR # Enable SDRAM chip select # mww 0xffffff80 0x00000002 ;# EBI_CSA # Set SDRAM characteristics in configuration register. # At 48MHz 1 cycle is about 21ns. # # 0x00000003 NC: Number of column bits # 0x00000002 10 bits, 1k columns # # 0x0000000C NR: Number of row bits # 0x00000008 13 bits, 8k rows # # 0x00000010 NB: Number of banks # 0x00000010 4 banks # # 0x00000060 CAS: CAS latency # 0x00000040 2 cycles # # 0x00000780 TWR: Write recovery delay # 0x00000100 2 cycles # # 0x00007800 TRC: Row cycle delay # 0x00002000 4 cycles # # 0x00078000 TRP: Row precharge delay # 0x00020000 4 cycles # # 0x00780000 TRCD: Row to column delay # 0x00100000 2 cycles # # 0x07800000 TRAS: Active to precharge delay # 0x01800000 3 cycles # # 0x78000000 TXSR: Exit self refresh to active delay # 0x20000000 4 cycles # mww 0xffffffb8 0x2192215a ;# SDRAMC_CR sleep 10 # Issue 16 bit SDRAM command: NOP # mww 0xffffffb0 0x00000011 ;# SDRAMC_MR mww 0x20000000 0x00000000 # Issue 16 bit SDRAM command: Precharge all # mww 0xffffffb0 0x00000012 ;# SDRAMC_MR mww 0x20000000 0x00000000 # Issue 8 auto-refresh cycles # mww 0xffffffb0 0x00000014 ;# SDRAMC_MR mww 0x20000000 0x00000000 mww 0xffffffb0 0x00000014 ;# SDRAMC_MR mww 0x20000000 0x00000000 mww 0xffffffb0 0x00000014 ;# SDRAMC_MR mww 0x20000000 0x00000000 mww 0xffffffb0 0x00000014 ;# SDRAMC_MR mww 0x20000000 0x00000000 mww 0xffffffb0 0x00000014 ;# SDRAMC_MR mww 0x20000000 0x00000000 mww 0xffffffb0 0x00000014 ;# SDRAMC_MR mww 0x20000000 0x00000000 mww 0xffffffb0 0x00000014 ;# SDRAMC_MR mww 0x20000000 0x00000000 mww 0xffffffb0 0x00000014 ;# SDRAMC_MR mww 0x20000000 0x00000000 # Issue 16 bit SDRAM command: Set mode register # mww 0xffffffb0 0x00000013 ;# SDRAMC_MR mww 0x20000014 0xcafedede # Set refresh rate count ??? # mww 0xffffffb4 0x00000013 ;# SDRAMC_TR # Issue 16 bit SDRAM command: Normal mode # mww 0xffffffb0 0x00000010 ;# SDRAMC_MR mww 0x20000000 0x00000180 }
Configuration of the TAP, the debug target and the internal flash memory are definitely CPU related.
Defining a work area is a problem, though. By using internal RAM, we may assign it to the CPU. However, it depends on the firmware that is running on the board, how much RAM we have available and whether we should assign the lower or the upper part.
While a work area is not mandatory, it is essential for user experience, because it significantly improves the JTAG data transfer. The suggestion is to define it in the CPU configuration. If it interferes with running firmware, it may be overridden in a user configuration file.
This will give us the following CPU configuration for the AT91SAM7SE512:
jtag newtap sam7se512 cpu -irlen 4 -expected-id 0x3f0f0f0f target create sam7se512.cpu arm7tdmi -chain-position sam7se512.cpu sam7se512.cpu configure -work-area-phys 0x00206000 -work-area-size 0x4000 flash bank sam7se512.flash.0 at91sam7 0 0 0 0 sam7se512.cpu 0 0 0 0 0 0 0 18432 flash bank sam7se512.flash.1 at91sam7 0 0 0 0 sam7se512.cpu 1 0 0 0 0 0 0 18432
Defining Tcl Variables
In part 4 of the tutorial it had been pointed out, that using a script language in configuration files allows us to define procedures for event based configurations. Another, more obvious advantage is to be able to define variables. They are not really required, so far we didn't use any.
However, variables will make code easier maintainable. For example, at many places we are referring to the chip name sam7se512. Putting this name into a variable, which is used throughout the configuration instead of the literal name, would make changing it much easier. You may now ask: Why would someone want to do this? Indeed, there are several reasons.
The most likely reason to modify the chip name is a board, which contains two AT91SAM7SE512 chips. If we put
if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME sam7se512 }
into our board configuration file, then the variable _CHIPNAME will be sam7se512 by default. Using _CHIPNAME instead of sam7se512 in the remaining configuration will allow us, to use the same CPU configuration file for both CPUs.
set CHIPNAME sam7se512.0 source [find target/at91sam7se512.cfg] set CHIPNAME sam7se512.1 source [find target/at91sam7se512.cfg]
Side note: Those of you, who are even less familiar with Tcl than I am, may get confused now. Let me explain. CHIPNAME and _CHIPNAME are different variable names. If you want to refer to the contents of a variable, you add a dollar sign in front. For example, $CHIPNAME will be replaced by the contents of the variable CHIPNAME.
Almost all existing scripts use a kind of standard set of variables. Several variables are also explained in the OpenOCD manual. Thus, it is a good idea to follow this convention, even if we didn't need any of them to get our local configuration up and running.
Here we present our final CPU configuration file. You should name it at91sam7se512.cfg and store it in subdirectory target of the OpenOCD installation directory, when running Windows, or /usr/share/openocd/scripts on most Linux PCs. Most probably this file already exists and you should make a backup copy first. Anyway, if you compare the existing file with the one we developed during our tutorial, you won't find many differences. And if you find any, you will be able now to decide, which one is better.
# ATMEL sam7se512 # Example: the "Elektor Internet Radio" - EIR # http://www.ethernut.de/en/hardware/eir/index.html if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME sam7se512 } if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x3f0f0f0f } # JTAG Test Access Point jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID # JTAG Debug Target set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm7tdmi -endian $_ENDIAN -chain-position $_TARGETNAME -variant arm7tdmi # OpenOCD Work Area $_TARGETNAME configure -work-area-phys 0x00200000 -work-area-size 0x4000 -work-area-backup 0 # Flash Memory Banks set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME.0 at91sam7 0 0 0 0 $_TARGETNAME 0 0 0 0 0 0 0 18432 flash bank $_FLASHNAME.1 at91sam7 0 0 0 0 $_TARGETNAME 1 0 0 0 0 0 0 18432
And here we have the final board configuration file for the Elektor Internet Radio. This one should be named eir.cfg and stored in subdirectory boards. Again, keep any exiting file as a backup.
# Elector Internet Radio Board # http://www.ethernut.de/en/hardware/eir/ source [find target/at91sam7se512.cfg] # Target events # $_TARGETNAME configure -event reset-init { eir_init } adapter_khz 200 # Initialize the EIR board. # proc eir_init {} { eir_init_reset eir_init_clock # Minimum ICE cycle time is 102ns (9800 kHz) adapter_khz 5000 arm7_9 dcc_downloads enable ;# Enable faster DCC downloads arm7_9 fast_memory_access enable #jtag_khz 9800 eir_init_sdram # flash probe 0 } # Initialize the EIR reset logic. # proc eir_init_reset {} { # Disable watchdog mww 0xfffffd44 0x00008000 ;# WDT_MR # Enable user reset mww 0xfffffd08 0xa5000001 ;# RSTC_MR } # Initialize the EIR clocks. # # The board uses an 18.432MHz crystal. # Let the CPU run at 48MHz. # proc eir_init_clock {} { # Enable main oscillator. # # Start-up time of 6 x 8 slow clocks. # mww 0xfffffc20 0x00000601 ;# CKGR_MOR sleep 2 # Configure the PLL. # # 18.432MHz * (72 + 1) / 14 = 96MHz # # Divider 14 (0x0e) # Start-up time of 28 (0x1c) slow clocks # Multiplier 72 (0x48) # mww 0xfffffc2C 0x00481c0e ;# CKGR_PLLR sleep 1 # Select PLL clock and divide it by 2 # # 96MHz / 2 = 48MHz # mww 0xfffffc30 0x00000007 ;# PMC_MCKR sleep 1 # 1 wait for read, 2 waits for write # We have 48 master clocks in 1us mww 0xffffff60 0x00480100 ;# MC_FMR } # Initialize the EIR SDRAM. # # EIR uses Samsung K4S511632D-UC75 SDRAM: # Organization: 32M x 16 # 8k rows, 1k columns # 20ns row precharge time # 45ns min. and 100us max. row active time # # MCK cycle is 20ns when running at 48MHz. # proc eir_init_sdram {} { # Enable address and data bus # eir_init_membus # Enable SDRAM control at PIO A # mww 0xfffff474 0x3f800000 ;# PIOA_BSR mww 0xfffff404 0x3f800000 ;# PIOA_PDR # Enable SDRAM chip select # mww 0xffffff80 0x00000002 ;# EBI_CSA # Set SDRAM characteristics in configuration register. # At 48MHz 1 cycle is about 21ns. # # 0x00000003 NC: Number of column bits # 0x00000002 10 bits, 1k columns # # 0x0000000C NR: Number of row bits # 0x00000008 13 bits, 8k rows # # 0x00000010 NB: Number of banks # 0x00000010 4 banks # # 0x00000060 CAS: CAS latency # 0x00000040 2 cycles # # 0x00000780 TWR: Write recovery delay # 0x00000100 2 cycles # # 0x00007800 TRC: Row cycle delay # 0x00002000 4 cycles # # 0x00078000 TRP: Row precharge delay # 0x00020000 4 cycles # # 0x00780000 TRCD: Row to column delay # 0x00100000 2 cycles # # 0x07800000 TRAS: Active to precharge delay # 0x01800000 3 cycles # # 0x78000000 TXSR: Exit self refresh to active delay # 0x20000000 4 cycles # mww 0xffffffb8 0x2192215a ;# SDRAMC_CR sleep 10 # Issue 16 bit SDRAM command: NOP # mww 0xffffffb0 0x00000011 ;# SDRAMC_MR mww 0x20000000 0x00000000 # Issue 16 bit SDRAM command: Precharge all # mww 0xffffffb0 0x00000012 ;# SDRAMC_MR mww 0x20000000 0x00000000 # Issue 8 auto-refresh cycles # mww 0xffffffb0 0x00000014 ;# SDRAMC_MR mww 0x20000000 0x00000000 mww 0xffffffb0 0x00000014 ;# SDRAMC_MR mww 0x20000000 0x00000000 mww 0xffffffb0 0x00000014 ;# SDRAMC_MR mww 0x20000000 0x00000000 mww 0xffffffb0 0x00000014 ;# SDRAMC_MR mww 0x20000000 0x00000000 mww 0xffffffb0 0x00000014 ;# SDRAMC_MR mww 0x20000000 0x00000000 mww 0xffffffb0 0x00000014 ;# SDRAMC_MR mww 0x20000000 0x00000000 mww 0xffffffb0 0x00000014 ;# SDRAMC_MR mww 0x20000000 0x00000000 mww 0xffffffb0 0x00000014 ;# SDRAMC_MR mww 0x20000000 0x00000000 # Issue 16 bit SDRAM command: Set mode register # mww 0xffffffb0 0x00000013 ;# SDRAMC_MR mww 0x20000014 0xcafedede # Set refresh rate count ??? # mww 0xffffffb4 0x00000013 ;# SDRAMC_TR # Issue 16 bit SDRAM command: Normal mode # mww 0xffffffb0 0x00000010 ;# SDRAMC_MR mww 0x20000000 0x00000180 }
Last not least our final configuration for the Turtelizer 2, to be placed in interface/turtelizer2.cfg.
# # egnite Turtelizer 2 # # http://www.ethernut.de/en/hardware/turtelizer/index.html # # Replace with #interface turtle # when using the Turtelizer support package interface ft2232 ft2232_device_desc "Turtelizer JTAG/RS232 Adapter" ft2232_layout turtelizer2 ft2232_vid_pid 0x0403 0xbdc8
The last part will give you a few usage examples. Although it focuses on Nut/OS applications, you may find it generally useful.