2021-11-25 03:07 AM
I am attempting to interface my STM32H753 based system to a Micron MT48H32M16LFB4 512Mbit SDRAM chip through the FMC at 100MHz. The chip seems to work - but not completely according to my expectations.
I have managed to write and read data to and from 32 bit aligned addresses in 8 and 16 bit chunks using the HAL_SDRAM_Write_x and HAL_SDRAM_Read_x, checking the data afterwards *seems* to show that this works.
As tested with the following routine:
uint32_t *ramPtr = (uint32_t *)0xC0000000;
uint8_t data = 0xAA;
uint8_t result = 0;
for(uint32_t idx = 0; SDRAM_TEST_SIZE > idx; idx++)
{
HAL_SDRAM_Write_8b(_hsdram, ramPtr, &data, sizeof(data));
HAL_SDRAM_Read_8b(_hsdram, ramPtr, &result, sizeof(result));
assert_param(result == data);
/* reset the test and move on to the next mem address */
result = 0;
ramPtr++;
}
However if I attempt to access the ram chip as 32-bit writes and reads, on unaligned addresses, the data gets corrupted:
e.g. Tested with the same routine as before, only data and result are uint32_t and the 32b variants of the r/w functions are used.
data = 0xdeadbeef
result = 0xbeefbe00
Accessing the sdram chip directly, not through the HAL functions seems to not work either:
__attribute__((section(".sdram"))) static volatile uint32_t sdramTestArray[SDRAM_TEST_SIZE];
sdramTestArray[idx] = data;
assert_param(sdramTestArray[idx] == data);
I have configured my sdram through CubeMX with the following settings:
hsdram1.Instance = FMC_SDRAM_DEVICE;
/* hsdram1.Init */
hsdram1.Init.SDBank = FMC_SDRAM_BANK1;
hsdram1.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_10;
hsdram1.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_13;
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 = 4;
SdramTiming.ExitSelfRefreshDelay = 14;
SdramTiming.SelfRefreshTime = 8;
SdramTiming.RowCycleDelay = 8;
SdramTiming.WriteRecoveryTime = 8;
SdramTiming.RPDelay = 3;
SdramTiming.RCDDelay = 3;
And added the following sdram initialization code:
/* enable the sdram clock */
cmd.CommandMode = FMC_SDRAM_CMD_CLK_ENABLE;
cmd.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
cmd.AutoRefreshNumber = 2;
cmd.ModeRegisterDefinition = SDRAM_MODEREG_BURST_LENGTH_1 | SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL | SDRAM_MODEREG_CAS_LATENCY_3 | SDRAM_MODEREG_OPERATING_MODE_STANDARD | SDRAM_MODEREG_WRITEBURST_MODE_PROGRAMMED;
HAL_SDRAM_SendCommand(hsdram, &cmd, SDRAM_TIMEOUT);
/* wait for the clock to stabilize */
HAL_Delay(CLOCK_INIT_DELAY);
/* send a precharge command to all banks */
cmd.CommandMode = FMC_SDRAM_CMD_PALL;
cmd.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
HAL_SDRAM_SendCommand(hsdram, &cmd, SDRAM_TIMEOUT);
/* perform two auto refresh cycles */
cmd.CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE;
cmd.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
HAL_SDRAM_SendCommand(hsdram, &cmd, SDRAM_TIMEOUT);
/* configure the mode registers */
cmd.CommandMode = FMC_SDRAM_CMD_LOAD_MODE;
cmd.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
HAL_SDRAM_SendCommand(hsdram, &cmd, SDRAM_TIMEOUT);
/* set the refresh rate */
HAL_SDRAM_ProgramRefreshRate(hsdram, (((REFRESH_PERIOD_US * SDRAM_FREQUENCY_MHZ) / SDRAM_NUM_ROWS) - 21));
I have defined the sdram in my linker description as follows:
MEMORY
{
.
.
SDRAM (rw) : ORIGIN = 0xC0000000, LENGTH = 64M
.
.
}
SECTIONS
{
.
.
.sdram_section (NOLOAD):
{
. = ALIGN(4);
__SDARAM_START__ = .;
*(.sdram)
*(.sdram*)
. = ALIGN(4);
__SDRAM_END__ = .;
} >SDRAM
.
.
}
I am unsure on how to proceed debuggging my memory issues; so far, I have taken the following steps in an attempt to fix them:
- double-check the hardware definitions in my CubeMX project
- double- and triple-check the timing settings (based on 100MHz operation)
- increased timings to be well over the minimum required times for my sdram chip
- tried various addressing row/column settings, none of which helped
At this point I have the following questions:
- Are there any obvious faults in the explanation and code snippets above?
- Am I right in thinking the sdram should be accessible in the same way as any other memory address? i.e. just put variables and assign values?
- What other steps can be taken in debugging/fixing these memory corruptions?
2021-11-25 05:08 AM
What if it is the hardware?
Check schematic and pin configuration.
Check the byte lane stuff
2021-11-25 05:44 AM
I have checked the schematic again, but could not find any faults there. All data, address and control signals are connected to the correct MCU pins.
As for pin configuration, I Ieft all IO configured as standard for the peripheral; Alternate function Push Pull without pullup/pulldown and the Very high option selected for maximum output speed.
The byte lane signals FMC_NBL0 and FMC_NBL1 are connected to LDQM and UDQM respectively. I could not find it explicitly stated in the stm datasheet/reference manual which byte lane signal controls the upper or lower byte, but it seems logical that NBL0 controls the lower byte.
2021-11-25 06:48 AM
> - Are there any obvious faults in the explanation and code snippets above?
Not that I saw. I did not check timing values.
> - Am I right in thinking the sdram should be accessible in the same way as any other memory address? i.e. just put variables and assign values?
Once configured, yes. You can view the HAL source to see it's not doing anything else important:
> - What other steps can be taken in debugging/fixing these memory corruptions?
Decrease clock speed to 10 MHz and see if it fixes it or produces identical results.
2021-11-25 06:52 AM
Thanks. I will try decreasing the clock speed.
Edit;
Running the module at 10MHz works fine, no more issues.
I guess I'll be revisiting the timing requirements and max speed specs once more.
Thanks again.