2020-07-23 04:44 PM
I am trying to set up FMC to work with external RAM. The code compiles and works with KEIL, but I am trying to make it work with STM32CubeIDE. The code compiles and runs, but the RAM is not initialized. I copied all of the code, including the .ioc file, and used it but it won't enable the RAM.
I have a temporary license for KEIL and I have confirmed that the memory and the code work by compiling and debugging in KEIL and accessing the RAM in the code and in the debugger.
Any thoughts or ideas? I need this external ram so I can continue to port TouchGFX to my board for a research project.
Thanks
Solved! Go to Solution.
2020-07-25 08:25 AM
I thought that the same code would work, too. I'll do some more debugging and make sure that CubeMX didn't change anything when it imported the project.
2020-07-25 11:14 AM
I'm using the Waveshare board with STM32CubeIDE. I'll attach the various bits of relevant code. Willl take more than 1 post due to size limits on the forum
IN main.c start the clocks including the FMC clock
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
/** Supply configuration update enable
*/
HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY);
/** Configure the main internal regulator output voltage
*/
if(HAL_GetREVID()==0x1003)__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
else __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE0);
while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}
/** Configure LSE Drive Capability
*/
__HAL_RCC_BKPRAM_CLK_ENABLE();
HAL_PWREx_EnableBkUpReg();
HAL_PWR_EnableBkUpAccess();
/** Macro to configure the PLL clock source
*/
__HAL_RCC_PLL_PLLSOURCE_CONFIG(RCC_PLLSOURCE_HSE);
/** Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI48|RCC_OSCILLATORTYPE_HSI
|RCC_OSCILLATORTYPE_HSE|RCC_OSCILLATORTYPE_LSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON ;
RCC_OscInitStruct.LSEState = RCC_LSE_ON;
RCC_OscInitStruct.HSIState = RCC_HSI_DIV1;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.HSI48State = RCC_HSI48_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 1;
RCC_OscInitStruct.PLL.PLLN = (MAINCLOCKSPEED>>2);
RCC_OscInitStruct.PLL.PLLP = 2;
RCC_OscInitStruct.PLL.PLLQ = 20;
RCC_OscInitStruct.PLL.PLLR = 2;
RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_3;
RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
RCC_OscInitStruct.PLL.PLLFRACN = 0;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
SystemError=1;Error_Handler();
}
/** Initializes the CPU, AHB and APB busses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2
|RCC_CLOCKTYPE_D3PCLK1|RCC_CLOCKTYPE_D1PCLK1;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, (HAL_GetREVID()==0x1003 ? FLASH_LATENCY_2:FLASH_LATENCY_4)) != HAL_OK)
{
SystemError=1;Error_Handler();
}
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RTC|RCC_PERIPHCLK_LTDC
|RCC_PERIPHCLK_USART2|RCC_PERIPHCLK_UART4
|RCC_PERIPHCLK_USART1|RCC_PERIPHCLK_RNG
|RCC_PERIPHCLK_SPI3|RCC_PERIPHCLK_SPI1
|RCC_PERIPHCLK_SPI2|RCC_PERIPHCLK_I2C2
|RCC_PERIPHCLK_ADC|RCC_PERIPHCLK_I2C1
|RCC_PERIPHCLK_I2C4|RCC_PERIPHCLK_USB
|RCC_PERIPHCLK_FMC;
PeriphClkInitStruct.PLL2.PLL2M = 1;
if(HAL_GetREVID()==0x1003){
PeriphClkInitStruct.PLL2.PLL2N = 100;
PeriphClkInitStruct.PLL2.PLL2P = 16;
PeriphClkInitStruct.PLL2.PLL2Q = 16;
PeriphClkInitStruct.PLL2.PLL2R = 4;
} else {
PeriphClkInitStruct.PLL2.PLL2N = 120;
PeriphClkInitStruct.PLL2.PLL2P = 20;
PeriphClkInitStruct.PLL2.PLL2Q = 20;
PeriphClkInitStruct.PLL2.PLL2R = 5;
}
PeriphClkInitStruct.PLL2.PLL2RGE = RCC_PLL2VCIRANGE_3;
PeriphClkInitStruct.PLL2.PLL2VCOSEL = RCC_PLL2VCOWIDE;
PeriphClkInitStruct.PLL2.PLL2FRACN = 0;
PeriphClkInitStruct.PLL3.PLL3M = 1;
if(HAL_GetREVID()==0x1003){
PeriphClkInitStruct.PLL3.PLL3N = 100;
PeriphClkInitStruct.PLL3.PLL3P = 20;
PeriphClkInitStruct.PLL3.PLL3Q = 20;
PeriphClkInitStruct.PLL3.PLL3R = 20;
} else {
PeriphClkInitStruct.PLL3.PLL3N = 120;
PeriphClkInitStruct.PLL3.PLL3P = 24;
PeriphClkInitStruct.PLL3.PLL3Q = 24;
PeriphClkInitStruct.PLL3.PLL3R = 24;
}
PeriphClkInitStruct.PLL3.PLL3RGE = RCC_PLL3VCIRANGE_3;
PeriphClkInitStruct.PLL3.PLL3VCOSEL = RCC_PLL3VCOWIDE;
PeriphClkInitStruct.PLL3.PLL3FRACN = 0;
PeriphClkInitStruct.FmcClockSelection = RCC_FMCCLKSOURCE_PLL2;
PeriphClkInitStruct.Spi123ClockSelection = RCC_SPI123CLKSOURCE_PLL2;
PeriphClkInitStruct.Usart234578ClockSelection = RCC_USART234578CLKSOURCE_PLL2;
PeriphClkInitStruct.Usart16ClockSelection = RCC_USART16CLKSOURCE_PLL2;
PeriphClkInitStruct.RngClockSelection = RCC_RNGCLKSOURCE_HSI48;
PeriphClkInitStruct.I2c123ClockSelection = RCC_I2C123CLKSOURCE_HSI;
PeriphClkInitStruct.UsbClockSelection = (HAL_GetREVID()==0x1003 ? RCC_USBCLKSOURCE_HSI48:RCC_USBCLKSOURCE_PLL);
PeriphClkInitStruct.I2c4ClockSelection = RCC_I2C4CLKSOURCE_HSI;
PeriphClkInitStruct.AdcClockSelection = RCC_ADCCLKSOURCE_PLL2;
PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
{
SystemError=1;Error_Handler();
}
HAL_RCC_MCOConfig(RCC_MCO1, RCC_MCO1SOURCE_HSI, RCC_MCODIV_1);
/** Enable USB Voltage detector
*/
HAL_PWREx_EnableUSBVoltageDetector();
}
2020-07-25 11:14 AM
Setup FMC and SDRAM
void RAMSETUP(void){
/*##-1- Configure the SDRAM device #########################################*/
/* SDRAM device configuration */
hsdram.Instance = FMC_SDRAM_DEVICE;
/* Timing configuration for 100Mhz as SDRAM clock frequency (System clock is up to 200Mhz) */
SDRAM_Timing.LoadToActiveDelay = 2;
SDRAM_Timing.ExitSelfRefreshDelay = 7;
SDRAM_Timing.SelfRefreshTime = 4;
SDRAM_Timing.RowCycleDelay = 7;
SDRAM_Timing.WriteRecoveryTime = 2;
SDRAM_Timing.RPDelay = 2;
SDRAM_Timing.RCDDelay = 2;
hsdram.Init.SDBank = FMC_SDRAM_BANK2;
hsdram.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_8;
hsdram.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_12;
hsdram.Init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_16;
hsdram.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4;
hsdram.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_3;
hsdram.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE;
hsdram.Init.SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_2;
hsdram.Init.ReadBurst = FMC_SDRAM_RBURST_ENABLE;
hsdram.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_1;
/* Initialize the SDRAM controller */
if(HAL_SDRAM_Init(&hsdram, &SDRAM_Timing) != HAL_OK)
{
/* Initialization Error */
SystemError=1;Error_Handler();
}
/* Program the SDRAM external device */
SDRAM_Initialization_Sequence(&hsdram, &command);
}
2020-07-25 11:16 AM
Configure the pins
static uint32_t FMC_Initialized = 0;
static void HAL_FMC_MspInit(void){
/* USER CODE BEGIN FMC_MspInit 0 */
/* USER CODE END FMC_MspInit 0 */
GPIO_InitTypeDef GPIO_InitStruct ={0};
if (FMC_Initialized) {
return;
}
FMC_Initialized = 1;
/* Peripheral clock enable */
__HAL_RCC_FMC_CLK_ENABLE();
/** FMC GPIO Configuration
PF0 ------> FMC_A0
PF1 ------> FMC_A1
PF2 ------> FMC_A2
PF3 ------> FMC_A3
PF4 ------> FMC_A4
PF5 ------> FMC_A5
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
PH6 ------> FMC_SDNE1
PH7 ------> FMC_SDCKE1
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_5|GPIO_PIN_6|GPIO_PIN_7;
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);
/* USER CODE BEGIN FMC_MspInit 1 */
/* USER CODE END FMC_MspInit 1 */
}
void HAL_SDRAM_MspInit(SDRAM_HandleTypeDef* hsdram){
/* USER CODE BEGIN SDRAM_MspInit 0 */
/* USER CODE END SDRAM_MspInit 0 */
HAL_FMC_MspInit();
/* USER CODE BEGIN SDRAM_MspInit 1 */
/* USER CODE END SDRAM_MspInit 1 */
}
2020-07-25 11:19 AM
Main code startup
SystemClock_Config();
RAMSETUP();
FMC_Bank1_R->BTCR[1] = 0x000030D2;
HAL_SetFMCMemorySwappingConfig(FMC_SWAPBMAP_SDRAMB2);
2020-07-25 11:23 AM
Set up refresh
static void SDRAM_Initialization_Sequence(SDRAM_HandleTypeDef *hsdram, FMC_SDRAM_CommandTypeDef *Command)
{
__IO uint32_t tmpmrd =0;
/* Step 1: Configure a clock configuration enable command */
Command->CommandMode = FMC_SDRAM_CMD_CLK_ENABLE;
Command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK2;;
Command->AutoRefreshNumber = 1;
Command->ModeRegisterDefinition = 0;
/* Send the command */
HAL_SDRAM_SendCommand(hsdram, Command, SDRAM_TIMEOUT);
/* 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_BANK2;
Command->AutoRefreshNumber = 1;
Command->ModeRegisterDefinition = 0;
/* Send the command */
HAL_SDRAM_SendCommand(hsdram, Command, SDRAM_TIMEOUT);
/* Step 4 : Configure a Auto-Refresh command */
Command->CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE;
Command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK2;
Command->AutoRefreshNumber = 8;
Command->ModeRegisterDefinition = 0;
/* Send the command */
HAL_SDRAM_SendCommand(hsdram, Command, SDRAM_TIMEOUT);
/* 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_3 |
SDRAM_MODEREG_OPERATING_MODE_STANDARD |
SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;
Command->CommandMode = FMC_SDRAM_CMD_LOAD_MODE;
Command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK2;
Command->AutoRefreshNumber = 1;
Command->ModeRegisterDefinition = tmpmrd;
/* Send the command */
HAL_SDRAM_SendCommand(hsdram, Command, SDRAM_TIMEOUT);
/* Step 6: Set the refresh rate counter */
/* Set the device refresh rate */
HAL_SDRAM_ProgramRefreshRate(hsdram, REFRESH_COUNT);
}
2020-07-25 01:01 PM
Can you attach your .ioc file? It looks like most of this code is autogenerated by CubeMX. I'm trying to figure out which settings to change so I don't have to go in and change the files manually each time.
2020-07-25 01:33 PM
Where are you getting the variable command?
2020-07-25 01:52 PM
OK - this all works... wow. Thank you so much!
I just have to find a way to keep CubeMX from overwriting the code each time I rebuild so I can add the call to SDRAM_Initialization_Sequence.