2019-02-15 08:25 AM
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
2019-02-15 09:41 AM
>>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.
2019-02-18 05:59 AM
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
2019-02-18 07:26 AM
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.
2019-02-19 01:06 AM
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
2019-02-26 11:30 PM
Just to close this topic, I replaced the IS42S32400F by a MT48LC4M32B2P and everything works fine - without knowing why.
2024-03-12 07:56 AM
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.
2024-03-12 09:57 AM
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
2024-03-12 01:58 PM
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.
2024-03-12 02:21 PM
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.