cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F746 FMC missing bus accesses

Andrew Berry
Associate II
Posted on July 13, 2017 at 00:26

I'm working with an LCD with an ILI9341 controller, and attempting to use the FMC to control it. I've had the LCD working in SPI mode, so I know that my configuration commands are correct. I've checked the timings between the MCU and the LCD and all appears to be in order. I can even get the LCD to display things correctly *when the FMC output is correct*. That last part is proving to be a problem, though. In certain situations where the program writes to the LCD in rapid succession certain writes either don't happen at all or happen in the wrong order.

For example, the below is part of the initialization:

 ILI9341_writeCommand(ILI9341_CMD_PWRCTLB); //0xCF
 ILI9341_writeDataU8(0x00);
 ILI9341_writeDataU8(0xC3);
 ILI9341_writeDataU8(0x30);�?�?�?�?

This should output 0xCF, 0x00, 0xC3, 0x30, but looking at the activity on the bus, I'm only seeing 0xCF, 0xC3, 0x There'es no gap in transmission, it's as if the second write simply doesn't happen! This happens at several places during initialization. But if I step through the program, or add a short spinloop to the write functions, every write happens correctly.So it seems to be a result of how rapidly the program writes to the FMC. If I disable the FMC write FIFO, I get similar behavior, but different writes are skipped, and again, slowing down the accesses seems to make everything work.

Any suggestions? Relevant portions of my program are below. I've looked at what CubeMX provides for using the FMC to drive an LCD (including the

HAL_SRAM_Write_ family of functions)

and haven't seen anything amiss.

FMC setup:

 FMC_Bank1->BTCR[0] =
 FMC_BCR1_WREN |
 FMC_BCR1_WFDIS |
 FMC_BCR1_WREN |
 FMC_BCR1_MBKEN;
 FMC_Bank1->BTCR[1] =
 FMC_BTR1_DATLAT |
 (1<<20) | //clkdiv
 FMC_BTR1_BUSTURN |
 FMC_BTR1_DATAST |
 FMC_BTR1_ADDHLD |
 FMC_BTR1_ADDSET;�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

Write functions (including delay loops):

void ILI9341_writeCommand(uint8_t cmd){
 for (uint16_t i=0; i<10; i++);
 *((__IO uint8_t*)(0x60000000)) = cmd;
}
void ILI9341_writeDataU8(volatile uint8_t data){
 for (uint16_t i=0; i<10; i++);
 *((__IO uint8_t*)(0x60010000)) = data;
}�?�?�?�?�?�?�?�?�?�?�?

#stm32f7 #fmc #stm32f746 #lcd
5 REPLIES 5
Andrew Berry
Associate II
Posted on July 13, 2017 at 14:02

Previously I was calling the above _writeDataU8 function to write buffers to the LCD, so sequential writes where all happening to the same FMC memory address. On a hunch, I revised those to write to sequential addresses as below (the base address has changed because I've moved the LCD controller's D/CX line from A16 to A18 so that it won't get toggled when writing to large areas of the LCD).

void ILI9341_writeDataBuffer(const uint8_t * buffer, uint32_t len){
__IO uint8_t * base = (uint8_t *)0x60040000;
while(len){
*base++ = *buffer++;
len--;
}
}�?�?�?�?�?�?�?

This works fine, even without a delay loop. Is there perhaps some performance optimization in the FMC that allows it to skip a pending write if a new write comes in to the same address?

Kraal
Senior III
Posted on July 13, 2017 at 15:39

Hi !

Depending on the optimization level of the compiler the for loops used as delays will be completely removed. This might be a problem here, maybe ?

If you want to keep this loops, you could add a 'asm volatile ('nop');' in the body of the loop so it is not removed by the compiler.

Posted on July 13, 2017 at 16:19

Thanks for the response.  To clarify, when using the the write functions in my original post, everything works fine with the for loop delays, but does not work without them.  So the loops getting optimized out isn't the issue.

Posted on July 13, 2017 at 16:25

Ah yes, sorry. I misunderstood your post.

Unfortunately I have no idea on how to help you...

Andrew Berry
Associate II
Posted on September 28, 2017 at 22:40

Finally getting back to this part of the project, and I think I've found the problem.  By default, the core treats accesses to the FMC as normal memory, and actual access order is not guaranteed to be the same as in the program sequence.  This behavior wouldn't be a problem with an external memory, because the FMC would be providing the address as well as the data, so the data would still wind up in the correct memory location place.  With an LCD that relies on sequence position to determine where in memory a write lands, however, this is a big problem.  This becomes apparent by drawing an array of different color boxes to the LCD--occasionally there will be a handful of pixels of one color in another color's box.

A related issue is that enabling the data cache can allow writes to the LCD to be cached and never appear at the FMC at all.  For the record, this was not the issue that led to the OP, since at the time I did not have the cache enabled.

The solution to both problems is to configure the M7's MPU to define a memory region encompassing the LCD's address space as 'Device' memory.  Per the ARMv7-M Architecture Reference, the Device memory attribute enforces the following access restrictions (from Section A3.5.5, emphasis mine):

For explicit accesses from the processor to memory marked as Device:

• All accesses occur at their program size.

• The number of accesses is the number specified by the program.

An implementation must not repeat an access to a Device memory location if the program has only one access to

that location. In other words, accesses to Device memory locations are not restartable.

The architecture does not permit speculative accesses to memory marked as Device.

Address locations marked as Device are Non-cacheable. While writes to Device memory can be buffered, writes

can be merged only where the merge maintains:

• The number of accesses.

• The order of the accesses.

• The size of each access.

Multiple accesses to the same address must not change the number of accesses to that address. Coalescing of

accesses is not permitted for accesses to Device memory.

When a Device memory operation has side effects that apply to Normal memory regions, software must use a

Memory Barrier to ensure correct execution. An example is programming the configuration registers of a memory

controller with respect to the memory accesses it controls.

All explicit accesses to Device memory must comply with the ordering requirements of accesses described in

Ordering requirements for memory accesses

on page A3-91

.

The referenced Page A3-91 further indicates that device memory accesses are strictly ordered.

Hopefully this will help if someone else encounters similar issues.