Hardware/EIR/OpenOCD/Optimize

From Nutwiki
Revision as of 10:07, 13 July 2017 by Harald (Talk | contribs) (Created page with "<div id="content"> = OpenOCD for AT91SAM7SE - Part 7 = This is part 7 of our OpenOCD for AT91SAM7SE tutorial. == Optimizing OpenOCD Configurations == Reme...")

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

OpenOCD for AT91SAM7SE - Part 7

This is part 7 of our OpenOCD for AT91SAM7SE tutorial.

Optimizing OpenOCD Configurations

Remember the flashy notes we got from OpenOCD when executing the reset init command?

NOTE! DCC downloads have not been enabled, defaulting to slow memory writes. Type 'help dcc'.
NOTE! Severe performance degradation without working memory enabled.
NOTE! Severe performance degradation without fast memory access enabled. Type 'help fast'.

In this part we will show how to increase the speed of the JTAG communication. Furthermore, we will discuss, how to re-organize our configuration to make it a bit more re-usable.

Work Area

As stated in the previous part, OpenOCD flash drivers may use the JTAG interface to present code and data to the CPU without using any real memory. Code and data is shifted into special JTAG registers located between the core and peripherals, which make the CPU think it got these values from real memory. This is sometimes quite helpful to get a virgin system running small code fragments. But it is also slow, because a large number of low level JTAG command are required. Specifically on low end JTAG adapters like the Turtelizer 2, the USB becomes a real bottleneck.

Luckily, OpenOCD offers a solution, if we can provide some RAM on the target board. In this case, OpenOCD will not have to mimic each code and data memory access via lengthy register shifting, but can upload code and data into the work area and let the CPU access this area directly, without JTAG intervention. A few kilobytes are sufficient, which makes the internal SRAM of the AT91SAM7SE a good candidate.

It's quite obvious, that the related configuration is part of the debug target and, as such, needs to be added to the target create command. It turned out later, that this is somewhat inflexible. While the debug target needs to be declared during the configuration stage and can be declared once only, it is sometimes required to setup the work area after certain hardware initializations took place. In addition, it is often required to select different work areas for different tasks. Note, that the work area occupies memory and may clash with other firmware already running on the target.

OpenOCD allows dynamic configuration of certain debug target parameters via the configure command, which must be prepended by the dotted name of the related debug target. To allow OpenOCD to use the last 8kBytes of internal SRAM as a work area, we define

sam7se512.cpu configure -work-area-phys 0x00206000 -work-area-size 0x4000

You can add this line to openocd.cfg now.

Debug Communication Channel

Even if we have established a work area on the target, filling this with data or code via JTAG shifting is still cumbersome. Some CPUs, including the AT91SAM7SE, provide a UART like JTAG interface named debug communication channel, or just DCC, which is much easier to handle than the JTAG state machine. The following command tells OpenOCD to make use of the DCC:

arm7_9 dcc_downloads enable

Unfortunately, this may not work on targets running at low speed. In our case it will probably not work until we switched the main clock to be fed by the PLL. Do not add this line to openocd.cfg now. We will soon see, where the best place for this configuration is.

Fast Memory Access

Frankly, I have no idea, what the following configuration internally works:

arm7_9 fast_memory_access enable

But it significantly increases the transfer rate between the PC and the target. Again, this may not work at slow CPU clocks and we will soon add it at the right place within openocd.cfg.

Increasing the JTAG Clock

This is not new, we already set the JTAG clock in our current openocd.cfg. However, as soon as we have the CPU running at 48kHz, we should increase the JTAG clock as well. And, we can also all the other optimizations, which are not working reliable at slow clocks. The right place is, you guessed it, the reset-init handler.

# 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
}

Finally we have now a complete OpenOCD configuration for our EIR board:

interface turtle
ft2232_layout turtelizer2
ft2232_device_desc "Turtelizer JTAG/RS232 Adapter"

reset_config srst_only
adapter_khz 8

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

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
}