Skip to main content
Piotr S
Associate
April 20, 2018
Solved

STM32H743II FMC + 8080 LCD spurious writes

  • April 20, 2018
  • 6 replies
  • 10263 views
Posted on April 20, 2018 at 11:55

Hello,

I'm interfacingSTM32H743II with 8080 parallel bus LCD. I configured FMC in CubeMX as LCD Interface with 16bit bus and A11 as R/S pin. However I've run into problem with writing commands/data into LCD. A single uint16_t write under 0x68000000 address results in 4 writes to memory, out of which first write is valid data, and rest are 0, as seen on logic analyser snapshot.

0690X0000060AhJQAU.png

Write is performed by following code:

#define COMMAND_POINTER 0x68000000
#define DATA_POINTER 0x68001000
...
static uint16_t * command = (uint16_t *) COMMAND_POINTER;
static uint16_t * data = (uint16_t *) DATA_POINTER;
...
*command = ILI9341_SWRESET; //software reset�?�?�?�?�?�?�?�?�?�?�?

I also tried HAL_SRAM_Write_16b(), but result is the same.

These writes basically compile to strh (Store register halfword) instruction, and executing this single instruction causes 4 write accesses to LCD. After little investigation i noticed, that writes under incremented address, for example 0x68000002 causes valid data only in second write operation, write under 0x68000004 causes valid data only in third write and so on. It's like FMC tries to write whole 64bit memory block at once.

ICache and DCache are disabled, i tried to disable FMC write FIFO, but it doesn't change much. Needless to say this FMC behaviour throws off communication with LCD.

Am I not taking some detail into account? i would like to avoid bitbanging LCD signals or changing HW design.

#stm32h7 #lcd #h7 #fmc
This topic has been closed for replies.
Best answer by Piotr S
Posted on April 20, 2018 at 17:45

I solved this problem by remapping fmc SRAM to 0xC0000000;

HAL_SetFMCMemorySwappingConfig(FMC_SWAPBMAP_SDRAM_SRAM);

Why this works? Memory under 0xC0000000 is accessed as Device memory, as opposed to memory under 

0x60000000

accessed as Normal memory. 'Normal memory allows the load and store of bytes, half-words and words to be arranged by the CPU in an efficient manner (the compiler is not aware of memory region types)'. You can refer to AN4838 and AN4839 for more information.

6 replies

Piotr S
Piotr SAuthorBest answer
Associate
April 20, 2018
Posted on April 20, 2018 at 17:45

I solved this problem by remapping fmc SRAM to 0xC0000000;

HAL_SetFMCMemorySwappingConfig(FMC_SWAPBMAP_SDRAM_SRAM);

Why this works? Memory under 0xC0000000 is accessed as Device memory, as opposed to memory under 

0x60000000

accessed as Normal memory. 'Normal memory allows the load and store of bytes, half-words and words to be arranged by the CPU in an efficient manner (the compiler is not aware of memory region types)'. You can refer to AN4838 and AN4839 for more information.
PSoco.1
Associate II
January 19, 2021

You saved the day... I had the exact same issue. even more I tried the whole morning to use MPU, but I still got issues when running in privileged mode as if it was using the background region... then I started to look in forums...

Andrew Berry
Associate
April 21, 2018
Posted on April 21, 2018 at 09:22

You can also use the MPU to define arbitrary address ranges as device memory (or apply other constraints) on devices that are so equipped.  I'm not sure what it looks like in HAL, but the below is an example of direct configuration of a memory region via the MPU registers.  The full details are in the ARM Cortex-M7 Devices Generic User Guide: 

http://infocenter.arm.com/help/topic/com.arm.doc.dui0646a/BIHJJABA.html

 

MPU->CTRL =

    MPU_CTRL_PRIVDEFENA_Msk | // allow privileged code to use default memory map

    MPU_CTRL_ENABLE_Msk;

MPU->RNR = 1;

MPU->RBAR = FMC_BANK1_SUB3_BASE_addr & MPU_RBAR_ADDR_Msk;

MPU->RASR =

    MPU_RASR_XN_Msk |

    (19<<MPU_RASR_SIZE_Pos) |

    MPU_RASR_B_Msk | //set region to Device

    (3 << MPU_RASR_AP_Pos) | //full read/write access for privileged and unprivileged code

    MPU_RASR_ENABLE_Msk;
Associate III
September 10, 2020

Hello,

Thanks for your code.

Are you sure of the value 19 (which corresponds to a region of 1MB)? Isn't it 0x19 rather which corresponds to a region of 64MB?

cf stm32h7xx_hal.c :

#define  MPU_REGION_SIZE_64MB   ((uint8_t)0x19)

Jean-Louis

CDew.1
Associate III
February 20, 2020

@Piotr S​ Thanks for writing up your solution, it worked for me too.

DBurr
Senior
February 20, 2020

Can you tell me how to do this memory swap between SRAM and SDRAM so that SRAM is at 0xc0000000? It doesn't look like this function "HAL_SetFMCMemorySwappingConfig(FMC_SWAPBMAP_SDRAM_SRAM);" is available in the current HAL.

CDew.1
Associate III
February 21, 2020

In short, it works for me.

I'm using CubeIDE Version: 1.2.1

Build: 5190_20200115_1224 (UTC)

and the NUCLEO-H743ZI2 board for project generation.

The HAL function is at line 1042 of my_project/Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal.c

/**
 * @brief Set the FMC Memory Mapping Swapping config.
 * @param BankMapConfig: Defines the FMC Bank mapping configuration. This parameter can be
 FMC_SWAPBMAP_DISABLE, FMC_SWAPBMAP_SDRAM_SRAM, FMC_SWAPBMAP_SDRAMB2
 * @retval HAL state
 */
void HAL_SetFMCMemorySwappingConfig(uint32_t BankMapConfig)
{
 /* Check the parameter */
 assert_param(IS_FMC_SWAPBMAP_MODE(BankMapConfig));
 MODIFY_REG(FMC_Bank1_R->BTCR[0], FMC_BCR1_BMAP, BankMapConfig);
}

In full:

In the CubeMX project generator, I navigated to:

Pinout & Configuration

-> Categories

-> Connectivity

-> FMC

-> NOR Flash/PSRAM/SRAM/ROM/LCD1 (upper pane)

-> Configuration (lower pane)

-> Bank Mapping

-> Mapping parameters

-> FMC bank mapping

and changed the selected item from "Default mapping" to "NOR/PSRAM bank and SDRAM bank...".

I had to alter my code to replace 0x6000 0000 with 0xc000 0000.

The (new) generated code is:

/* FMC initialization function */
static void MX_FMC_Init(void)
{
 
 /* USER CODE BEGIN FMC_Init 0 */
 
 /* USER CODE END FMC_Init 0 */
 
 FMC_NORSRAM_TimingTypeDef Timing = {0};
 FMC_NORSRAM_TimingTypeDef ExtTiming = {0};
 
 /* USER CODE BEGIN FMC_Init 1 */
 
 /* USER CODE END FMC_Init 1 */
 
 /** Perform the SRAM1 memory initialization sequence
 */
 hsram1.Instance = FMC_NORSRAM_DEVICE;
 hsram1.Extended = FMC_NORSRAM_EXTENDED_DEVICE;
 /* hsram1.Init */
 hsram1.Init.NSBank = FMC_NORSRAM_BANK2;
 hsram1.Init.DataAddressMux = FMC_DATA_ADDRESS_MUX_DISABLE;
 hsram1.Init.MemoryType = FMC_MEMORY_TYPE_SRAM;
 hsram1.Init.MemoryDataWidth = FMC_NORSRAM_MEM_BUS_WIDTH_16;
 hsram1.Init.BurstAccessMode = FMC_BURST_ACCESS_MODE_DISABLE;
 hsram1.Init.WaitSignalPolarity = FMC_WAIT_SIGNAL_POLARITY_LOW;
 hsram1.Init.WaitSignalActive = FMC_WAIT_TIMING_BEFORE_WS;
 hsram1.Init.WriteOperation = FMC_WRITE_OPERATION_ENABLE;
 hsram1.Init.WaitSignal = FMC_WAIT_SIGNAL_DISABLE;
 hsram1.Init.ExtendedMode = FMC_EXTENDED_MODE_ENABLE;
 hsram1.Init.AsynchronousWait = FMC_ASYNCHRONOUS_WAIT_DISABLE;
 hsram1.Init.WriteBurst = FMC_WRITE_BURST_DISABLE;
 hsram1.Init.ContinuousClock = FMC_CONTINUOUS_CLOCK_SYNC_ONLY;
 hsram1.Init.WriteFifo = FMC_WRITE_FIFO_DISABLE;
 hsram1.Init.PageSize = FMC_PAGE_SIZE_NONE;
 /* Timing */
 Timing.AddressSetupTime = 3;
 Timing.AddressHoldTime = 15;
 Timing.DataSetupTime = 4;
 Timing.BusTurnAroundDuration = 1;
 Timing.CLKDivision = 16;
 Timing.DataLatency = 17;
 Timing.AccessMode = FMC_ACCESS_MODE_A;
 /* ExtTiming */
 ExtTiming.AddressSetupTime = 3;
 ExtTiming.AddressHoldTime = 15;
 ExtTiming.DataSetupTime = 4;
 ExtTiming.BusTurnAroundDuration = 1;
 ExtTiming.CLKDivision = 16;
 ExtTiming.DataLatency = 17;
 ExtTiming.AccessMode = FMC_ACCESS_MODE_A;
 
 if (HAL_SRAM_Init(&hsram1, &Timing, &ExtTiming) != HAL_OK)
 {
 Error_Handler( );
 }
 
 HAL_SetFMCMemorySwappingConfig(FMC_SWAPBMAP_SDRAM_SRAM);
 
 /* USER CODE BEGIN FMC_Init 2 */
 
 /* USER CODE END FMC_Init 2 */
}

Where the important line is:

HAL_SetFMCMemorySwappingConfig(FMC_SWAPBMAP_SDRAM_SRAM);

I have tested that this generates a sane waveform (in my logic analyser) with only one write instead of four, but the timings may not suit your screen.

waclawek.jan
Super User
May 6, 2020

IMO changing this area to Device just covers some other adverse mechanism. While the processor is allowed to rearrange accesses in Normal area in order to optimize, it's not OK to write outright incorrect data! (multiple*reads* would still be OK).

JW

CDew.1
Associate III
May 6, 2020

From what I understand, all the writes are correct. The CPU is assuming that the device, to which its writing, has address lines A2..A1.

These four 16-bit writes, of which only the first contains the "correct" data, represent the writing of one 64-bit cacheline to RAM.

If this had been addressable memory, the address lines A2..A1 would have gone through the values 00, 01, 10, and 11, writing to 4 separate 16-bit words.

(I don't know whether those address lines are, or can be, brought out to pins, but they are not on the logic analyser output.)

It's not unreasonable that the CPU must be told that this particular address range does not contain normally-addressable memory, but instead contains 16-bit IO registers with semantics which differ from those of memory.

waclawek.jan
Super User
May 6, 2020

I beg to disagree.

Even in "normal" memory, if the processor writes only 16 bits (i.e. 2 bytes or one halfword), and the memory system actually writes 8 bytes, it means, the RAM content is corrupted.

JW

CDew.1
Associate III
May 6, 2020

You may well be right, I'm not an expert on the STM32.

My guess at what is going on (for RAM, not IO) is that CPU believes that the cacheline already has the correct and current contents of the higher three halfwords.

So when it writes to RAM in this manner, there is no corruption. Multiple writes of the same values to the same addresses have no effect on RAM, but they do have an effect on IO. Hence the behaviour changes when you tell the CPU that the region is not RAM.

I expect that you wouldn't see this behaviour on an STM32 without a data cache (or with it turned off).

If I were interfacing a 1Mbit x16 SRAM via the FSMC/FMC, this 4-halfword write pattern would not be a problem, and the use of the CPU data cache for my SRAM would help its performance.

waclawek.jan
Super User
May 6, 2020

Well, I don't know what was your particular setup, but the opening post says:

> ICache and DCache are disabled

I could understand the AXI logic still attempting to write 64 bits for Normal area (memory), provided that it first *reads* the whole 64 bits, too, before the wirite.

I don't have an 'F7/H7 at hand; if anybody could try this, I'd like to hear the results.

JW