OpenOCD for AT91SAM7SE - Part 5
This is part 5 of our OpenOCD for AT91SAM7SE tutorial.
Using SDRAM
Compared to other ARM7TDMI embedded boards, the EIR provides a lot of RAM, 64 MBytes. This makes developing new applications quite convenient. Actually the author often uses the EIR to create and debug new Nut/OS applications for other boards. There is enough room to add all kind of test routines, extended debug output etc. Later, this extra code can be removed to squeeze the code into flash and RAM memory of the final target. Other advantages are, that uploading code into RAM is much faster than flashing and that you can set any number of breakpoints hassle-free.
Memory Bus Initialization
In the previous part we learned, how to access the 32 kBytes of static RAM, using OpenOCD's mww command. This SRAM is built into the AT91SAM7SE microcontroller chip. The large SDRAM, that we want to access now, is located in an external chip. Thus, we need to enable the external memory bus of the microcontroller first. This is done by enabling the related peripheral function of the memory bus pins. Again, we use memory write word commands to set the right I/O registers. You may check the data sheet for more details.
# 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 }
After calling this routine, we should be able to access the SDRAM chip, which is required for the next step.
SDRAM Initialization
While SRAM is ready-to-use immediately after power-up, SDRAM requires a special initialization sequence. When booting the AT91SAM7SE from flash, this is typically done in the runtime initialization part of the application. If we want to upload code via JTAG directly into SDRAM, then OpenOCD must take over this part.
It's not easy, to get SDRAM timing right. A lot of data sheet reading and some calculations had to be done. To explain all the details would require a tutorial on its own. For now, just put the code below into your openocd.cfg. We have added many comments to the code, in case you are interested in the details.
# 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 }
This procedure requires, that the main clock is running at 48MHz and that the memory bus had been enabled. This must be taken into account when adding a call to it in our reset handler:
# Initialize the EIR board. # proc eir_init {} { eir_init_clock eir_init_membus eir_init_sdram }
As soon as you have added the two procedures eir_init_membus and eir_init_sdram, then the command reset init, if entered in a OpenOCD Telnet session, should enable OpenOCD to execute code in SDRAM.
OK, it's not that easy. Many applications will have been created to run in flash memory, which is located at memory address 0. At least a different linker script is needed for code running in SDRAM located at memory address 0x20000000. When using interrupts, the ARM7 CPU expects its exception vectors starting at address 0. So we'd need a new runtime initialization, which remaps the internal SRAM to address 0 and copies the exception vectors from the SDRAM image to this location. However, this tutorial is about setting up OpenOCD only.
While SDRAM is nice for code development and debugging, the final system will need code running in flash. The next part will show how to use OpenOCD for flashing code into the AT91SAM7SE.