Skip to main content
Visitor II
February 15, 2019
Question

Data is written to SDRAM at the correct address and at a wrong address with 32 byte offset simultaneously. What could be the reason for this?

  • February 15, 2019
  • 9 replies
  • 7093 views

Hello,

I have an STM32F746 in an own PCB design. A 128 Mb DRAM IS42S32400F is connected to the FMC pins, similar as on the STM32F746G-DISCO board. I can write and read data but there are errors which occur in a systematic way:

I start writing 16 bit data at address 0xC000 0000.

Data is stored at the the correct address. But, the strange thing is that the same data appears simultaneously at a second location either 32 byte above or below the intended address. How can this happen? How can data be stored at two locations with one write command?

A memory dump screenshot is attached.

I have double-checked all connections and fiddled with timing - but no success.

In my design I didn't care about matched trace lengths. Controller and SDRAM are about 4 cm apart. Could this be a reason?

I can also observe the same problem on an LCD sreen since the SDRAM is also my frame buffer.

The test loop is very simple:

while (1)

   {

       *(uint16_t*) (LCD_FB_START_ADDRESS + 2 + (2 * (y * 800 + x))) = x;

       x++;

       if (x == 800)

       {

           x = 0;

           y++;

           if (y == 480)

               y = 0;

       }

       HAL_Delay(1);

   }

I hope that anyone can give me a hint. I'm new in the STM32.

Regards

Jan

    This topic has been closed for replies.

    9 replies

    Graduate II
    February 15, 2019

    >>How can this happen?

    One of the address pins is screwed up, ie stuck at one/zero, not connected, not configured, etc.

    Turn off caching while testing.

    Jan1Author
    Visitor II
    February 18, 2019

    Thank you, Clive Two.Zero,

    I checked again the connections and the signals on the 12 address lines. All of them look normal. The error also happens in the same way if I use an other memory section.

    Turning off the cache did not change anything.

    I agree with you that there must be some logical reason (no timing or signal delay problem) since the error is absolutely reproducible. It even looks the same at 50 or 100 MHz clock.

    Data is written at 3 locations simultaneously: at the intended address, 20h above or below and 2000h above. But may be I'm wrong and it is written correctly and read wrongly?

    I'm afraid there is some difference between the MT48LC4M32 of the original application and my IS42S32400F memory. Has anyone used the IS42S32400F with the FMC?

    Regards

    Jan

    Graduate II
    February 18, 2019

    It is more probably read back wrongly.

    Rather than hope someone turns up with the same chip and configuration, perhaps post the pin/peripheral initialization code, and circuit specifics, for review.

    Presumably the DISCO works fine with equivalent configuration.

    Jan1Author
    Visitor II
    February 19, 2019

    Yes, DISCO works fine with the same project, except that SDCKE0/SDNE0 are moved from PH2/PC2 to PH3/PC3.

    This is my setup for FMC and SDRAM:

    /* FMC initialization */
    void FMC_Init(void)
    {
     FMC_SDRAM_TimingTypeDef SdramTiming;
     //Perform the SDRAM1 memory initialization sequence
     hsdram1.Instance = FMC_SDRAM_DEVICE;
     /* hsdram1.Init */
     hsdram1.Init.SDBank = FMC_SDRAM_BANK1;
     hsdram1.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_8;
     hsdram1.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_12;
     hsdram1.Init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_16;
     hsdram1.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4;
     hsdram1.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_3;
     hsdram1.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE;
     hsdram1.Init.SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_2;
     hsdram1.Init.ReadBurst = FMC_SDRAM_RBURST_ENABLE;
     hsdram1.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_0;
     /* SdramTiming */
     SdramTiming.LoadToActiveDelay = 2;
     SdramTiming.ExitSelfRefreshDelay = 7;
     SdramTiming.SelfRefreshTime = 4;
     SdramTiming.RowCycleDelay = 7;
     SdramTiming.WriteRecoveryTime = 3;
     SdramTiming.RPDelay = 2;
     SdramTiming.RCDDelay = 2;
     if (HAL_SDRAM_Init(&hsdram1, &SdramTiming) != HAL_OK)
     {
     Error_Handler( );
     }
    }
    /* SDRAM initialization */
    void SDRAM_Init(uint32_t RefreshCount)
    {
     uint32_t tmpmrd =0;
     /* Step 1: Configure a clock configuration enable command */
     Command.CommandMode = FMC_SDRAM_CMD_CLK_ENABLE;	//CKE
     Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
     Command.AutoRefreshNumber = 1;
     Command.ModeRegisterDefinition = 0;
     HAL_SDRAM_SendCommand(&hsdram1, &Command, SDRAM_TIMEOUT); 	 /* Send the command */
     /* Step 2: Insert 100 us minimum delay */
     /* Inserted delay is equal to 1 ms due to systick time base unit (ms) */
     HAL_Delay(1);
     /* Step 3: Configure a PALL (precharge all) command */
     Command.CommandMode = FMC_SDRAM_CMD_PALL;
     Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
     Command.AutoRefreshNumber = 1;
     Command.ModeRegisterDefinition = 0;
     HAL_SDRAM_SendCommand(&hsdram1, &Command, SDRAM_TIMEOUT); /* Send the command */
     /* Step 4: Configure an Auto Refresh command */
     Command.CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE;
     Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
     Command.AutoRefreshNumber = 8;
     Command.ModeRegisterDefinition = 0;
     HAL_SDRAM_SendCommand(&hsdram1, &Command, SDRAM_TIMEOUT); /* Send the command */
     /* Step 5: Program the external memory mode register */
     tmpmrd = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_1 |
     SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL |
     SDRAM_MODEREG_CAS_LATENCY_2 |
     SDRAM_MODEREG_OPERATING_MODE_STANDARD |
     SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;
     
     Command.CommandMode = FMC_SDRAM_CMD_LOAD_MODE;
     Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
     Command.AutoRefreshNumber = 1;
     Command.ModeRegisterDefinition = tmpmrd;
     HAL_SDRAM_SendCommand(&hsdram1, &Command, SDRAM_TIMEOUT); /* Send the command */
     /* Step 6: Set the refresh rate counter */
     HAL_SDRAM_ProgramRefreshRate(&hsdram1, RefreshCount);	 /* Set the device refresh rate */
    }

    ... and the FMC port settings:

    static void HAL_FMC_MspInit(void)
    {
     GPIO_InitTypeDef GPIO_InitStruct;
     if (FMC_Initialized) {
     return;
     }
     FMC_Initialized = 1;
     __HAL_RCC_FMC_CLK_ENABLE(); /* Peripheral clock enable */
     /** FMC GPIO Configuration 
     PF0 ------> FMC_A0
     PF1 ------> FMC_A1
     PF2 ------> FMC_A2
     PF3 ------> FMC_A3
     PF4 ------> FMC_A4
     PF5 ------> FMC_A5
     PC2 ------> FMC_SDNE0
     PH2 ------> FMC_SDCKE0
     PH5 ------> FMC_SDNWE
     PF11 ------> FMC_SDNRAS
     PF12 ------> FMC_A6
     PF13 ------> FMC_A7
     PF14 ------> FMC_A8
     PF15 ------> FMC_A9
     PG0 ------> FMC_A10
     PG1 ------> FMC_A11
     PE7 ------> FMC_D4
     PE8 ------> FMC_D5
     PE9 ------> FMC_D6
     PE10 ------> FMC_D7
     PE11 ------> FMC_D8
     PE12 ------> FMC_D9
     PE13 ------> FMC_D10
     PE14 ------> FMC_D11
     PE15 ------> FMC_D12
     PD8 ------> FMC_D13
     PD9 ------> FMC_D14
     PD10 ------> FMC_D15
     PD14 ------> FMC_D0
     PD15 ------> FMC_D1
     PG4 ------> FMC_BA0
     PG5 ------> FMC_BA1
     PG8 ------> FMC_SDCLK
     PD0 ------> FMC_D2
     PD1 ------> FMC_D3
     PG15 ------> FMC_SDNCAS
     PE0 ------> FMC_NBL0
     PE1 ------> FMC_NBL1
     */
     GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
     GPIO_InitStruct.Pull = GPIO_NOPULL;
     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
     GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
     HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
     
     GPIO_InitStruct.Pin = GPIO_PIN_2;
     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
     GPIO_InitStruct.Pull = GPIO_NOPULL;
     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
     GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
     HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
     
     GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_5;
     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
     GPIO_InitStruct.Pull = GPIO_NOPULL;
     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
     GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
     HAL_GPIO_Init(GPIOH, &GPIO_InitStruct);
     
     GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_8|GPIO_PIN_15;
     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
     GPIO_InitStruct.Pull = GPIO_NOPULL;
     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
     GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
     HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);
     
     GPIO_InitStruct.Pin = GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15|GPIO_PIN_0|GPIO_PIN_1;
     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
     GPIO_InitStruct.Pull = GPIO_NOPULL;
     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
     GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
     HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
     
     GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_14|GPIO_PIN_15|GPIO_PIN_0|GPIO_PIN_1;
     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
     GPIO_InitStruct.Pull = GPIO_NOPULL;
     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
     GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
     HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
    }

    I have also attached the relevant parts of schematic and PCB.

    Any help would be appreciated.

    Regards

    Jan

    0690X000006DgnKQAS.png0690X000006DgnFQAS.png

    Jan1Author
    Visitor II
    February 27, 2019

    Just to close this topic, I replaced the IS42S32400F by a MT48LC4M32B2P and everything works fine - without knowing why.

    Explorer
    March 12, 2024

    I have found a very similar problem to this, but the duplication was once, 1MB up the SRAM. Stepping through the disassembly, I would see it doing a store to an address 0xC0035B10, but that value would also "get written" to 0xC0135B10.

    I am still debugging it, but I have found that disabling instruction access to a different memory region in the MPU has stopped it happening. Disabling the cache also stopped it happening for me. Unfortunately, no MPU config above.

    It is on an H747 with IS42S32160D. I will also try repeating it on the Disco board to see if it is the same.

    Graduate II
    March 12, 2024

    It's is unlikely to be writing to TWO locations. What's more probable is that it writes to ONE location, and TWO locations decoded to that same location.

    The span here 0x100000 (1MB) suggests internal address bit A20 isn't decoded properly. Perhaps stuck at one, or stuck at zero, or just disconnected completely.

    Check how the FMC is configured, and the pins. Perhaps double check the netlist, and probe continuity on a test PCB

    Explorer
    March 12, 2024

    The fact that I can change 1 bit in the program and the behaviour goes away, I think, suggests that it is not an obvious hardware problem like an address bit being stuck. I can read and write to both locations in the fixed version so the functionality is there.

    Graduate II
    March 12, 2024

    Perhaps you can create a compelling working / failing case so the engineers at ST can understand what's happening, or where the problem is.

    Not sure why the cache should create a wrap-around issue. The 32-byte issue the OP mentioned might relate to the cache line width, but not clear how that would get tagged into two distinct address spaces.

    Graduate II
    May 3, 2024

    As a fundamental, trace length matching is critical to correct SDRAM operation.  The same is true of any high-speed, multi-signal bus (OSPI, QSPI, etc.).

    Visitor II
    May 30, 2024

    I have solved the issue by clearing the entire cache once by using the 

    SCB_CleanDCache() function.