This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TMS570LC4357: EMIF asynchronous memory's read and write sequence

Part Number: TMS570LC4357
Other Parts Discussed in Thread: HALCOGEN

Hi,

I'm currently working with the EMIF of the TMS570LC4357 MCU. I'm interfacing an external FPGA which exposes a bank of registers that are in turn mapped onto the Async1 address range of the EMIF block (0x60000000~0x64000000). The FPGA performs a set of operations towards different peripherals based on specific commands and data that are passed to it through the exposed registers and it in fact acts as an asynchronous memory for what may concern the EMIF. All the FPGA registers are 16 bit width, thus each R/W access through the EMIF is 2-byte based.

Current settings of the MCU's EMIF are:

PLL = 300 MHz

VCLK3 = 150 MHz (EMIF_CLK)

EMIF read setup/strobe/hold = 14 /48 / 2 (ECLK)

EMIF write setup / strobe / hold = 14 / 14 / 2 (ECLK)

EMIF turnaround = 1 (ECLK)

So far everything works as expected, nevertheless during a recent test I found the following issue. The FPGA is connected, among other devices, to a NAND Flash: a specific register, the command register, (@ 0x60800000) is reserved to receive the command for the NAND Flash (write a page, read a page and so on) while another one, the status register, (@ 0x60800002) is used to check if the FPGA's Flash controller is either busy or idle. In particular, sending the "write page" command (writing 0x8000 to 0x60800000) will immediately trigger the FPGA state machine which goes into the busy state and will set the busy bit of the status register (I should read 0x0001 from 0x60800002). For this reason, after setting the "write page" command, I read the status register and wait for it to become idle again (back to 0x0000). The first step is to set the address of the NAND Flash page I want to write, so that I use another pair of FPGA registers for this purpose ("low address" and "high address") at 0x60800004 and 0x60800006. So the C code is as follows:

*((volatile uint16_t *) 0x6080004) = BUILD_LOW_ADDRESS(block, page, column);
*((volatile uint16_t *) 0x6080006) = BUILD_HIGH_ADDRESS(block, page, column);
*((volatile uint16_t *) 0x6080000) = 0x8000U;
while (*((volatile uint16_t *)0x60800002) != 0) {

     // Handle a timeout
}

I also paste in the following the Assembly code snippet of the sequence I wrote for this operation:

// Various arithmetic operations to build the low address value
ldr           r2, [pc, #156]       ;                          <--- Load into R2 the low address register's address (0x608000024is written in the .text section at this offset)
strh        r3, [r2, #0]                                       <--- Write the low address register
// Various arithmetic operations to build the high address value
ldr           r3, [pc, #160]                                  <--- Load into R3 the high address register's address (0x60800006 is written in the .text section at this offset)
strh        r4, [r3, #0]                                     <--- Write the high address register
mov.w  r2, #32768                ; 0x8000           <--- Write the "write page" command to R2
mov.w  r3, #1619001344      ; 0x60800000   <--- Write the command register's address to R3
strh      r2, [r3, #0]                                          <--- Store the command into the command register
ldr        r2, [pc, #132]                                     <--- Load the status register's address into R2 (0x60800002 is written in the .text section at this offset)
ldrh      r3, [r2, #0]                                          <--- Read the status register's content

Nevertheless, I've noticed that, no matter what, there's no way I could see the "busy" state of the status register and every time the FPGA looked like idle, so that I proceed with the Flash programming but it unavoidably fails. So I tried to look at the busy bit transitions with the oscilloscope and I found the following:

It looks like the EMIF hardware swaps the order of the code flow by reading first the status register and then writing the command register. According to the TMS570LC43x Technical Reference Manual, section 21.2.13, an asynchronous read's priority is higher than the corresponding write and I was wondering if, since the hardware "may think" that there cannot be any data hazard in the two R/W instructions (the access is two byte so that there's no overlap and they involve different "SRAM-like" addresses), this kind of event may indeed happen. 

Adding an artificial delay between writing the command register and reading the status register will instead make the sequence go as expected:

Is this behavior normal?

Thanks in advance for any suppport.

  • Daniele Romano1 said:
    It looks like the EMIF hardware swaps the order of the code flow by reading first the status register and then writing the command register.

    It could be the Cortex-R5 re-ordering loads and stores to different addresses.

    In HALCoGen what is the "Region Type" set to in the MPU configuration for the EMIF address range?

  • Hello Daniele,

    1. The maximum EMIF clock supported by TMS570LC4357 is 100MHz

    2. Please change the MPU region type (for example, strongly-ordered) for EMIF async1 memory region. 

  • Dear QJ Wang,

    Thank you very much for the quick reply.

    QJ Wang said:

    1. The maximum EMIF clock supported by TMS570LC4357 is 100MHz

    This is a very useful information. I though that, according to SPNS195C (Rev. June 2016), page 115, this limit was only for synchronous memory, while I could set the divider to 1 for HCLK (currently 150 MHz) to derive VCLK3 and having both at the same frequency.

    QJ Wang said:

    2. Please change the MPU region type (for example, strongly-ordered) for EMIF async1 memory region. 

    Indeed I didn't setup the MPU at all for the TMS. This is for sure the cause of the unexpected behavior, thank you very much. I'll follow your instructions.

  • Dear Chester,

    Thank you very much for the reply. It is probably due to the missing configuration of the MPU which uses the default setup with as shared memory for the Async1 region.