cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F7 Heap on External SDRAM

keaven
Associate II
Posted on May 04, 2016 at 23:29

Hello everyone,

I have managed to configure the FMC to read/write on my external SDRAM. Now, I am trying to put the heap on it. Unfortunately, I am unsuccessful. I look up on the forum and I have did change the startup file to use the same size and use a scatter file for place the heap on it. In the map file , the heap seems well placed. The problem occurs when I am trying to do a malloc(). I get a hard fault. Here is the code I am using...

int main(void)
{
char* p;
static char AddressString[16] = {0};
//Compatibility call currently not required in version 4.75
//Initialize CMSIS-RTOS
osKernelInitialize();
//Enable I-Cache
SCB_EnableICache();
//Enable D-Cache
SCB_EnableDCache();
//Configure the system clock to 216 MHz
SystemClock_Config();
//Reset of all peripherals, initialize the flash interface and the systick
HAL_Init();
//Compatibility call currently not required in version 4.75
//Start CMSIS-RTOS thread execution
osKernelStart();
p = (char*) malloc(0x2000);
sprintf(AddressString, ''%08x'', (uint32_t) p);
free(p);
}
void InitFMC (void)
{
FMC_SDRAM_TimingTypeDef SdramTiming;
FMC_SDRAM_CommandTypeDef Command;
volatile uint32_t timeout = SDRAM_TIMEOUT;
/** Perform the SDRAM2 memory initialization sequence
*/
hsdram2.Instance = FMC_SDRAM_DEVICE;
/* hsdram2.Init */
hsdram2.Init.SDBank = FMC_SDRAM_BANK1;
hsdram2.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_9;
hsdram2.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_13;
hsdram2.Init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_16;
hsdram2.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4;
hsdram2.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_3;
hsdram2.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE;
hsdram2.Init.SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_2;
hsdram2.Init.ReadBurst = FMC_SDRAM_RBURST_DISABLE;
hsdram2.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_2;
/* SdramTiming */
// Timing for 143 Mhz so ok for 108MHz(9.25ns)
SdramTiming.LoadToActiveDelay = 2;
SdramTiming.ExitSelfRefreshDelay = 10;
SdramTiming.SelfRefreshTime = 6;
SdramTiming.RowCycleDelay = 9;
SdramTiming.WriteRecoveryTime = 3;
SdramTiming.RPDelay = 3;
SdramTiming.RCDDelay = 3;
HAL_SDRAM_Init(&hsdram2, &SdramTiming);
/* SDRAM Init sequence */
/* Configure a clock configuration enable command */
Command.CommandMode = FMC_SDRAM_CMD_CLK_ENABLE;
Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
Command.AutoRefreshNumber = 1;
Command.ModeRegisterDefinition = 0;
/* Send command */
HAL_SDRAM_SendCommand(&hsdram2, &Command, SDRAM_TIMEOUT);
//NOP
Command.CommandMode = FMC_SDRAM_CMD_NORMAL_MODE;
Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
Command.AutoRefreshNumber = 1;
Command.ModeRegisterDefinition = 0;
/* Send command */
HAL_SDRAM_SendCommand(&hsdram2, &Command, SDRAM_TIMEOUT);
/* Little delay */
timeout = SDRAM_TIMEOUT * 0xF;
while (timeout--);
/* Configure a PALL (precharge all) command */ 
Command.CommandMode = FMC_SDRAM_CMD_PALL;
Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
Command.AutoRefreshNumber = 2;
Command.ModeRegisterDefinition = 0;
/* Send the command */
HAL_SDRAM_SendCommand(&hsdram2, &Command, SDRAM_TIMEOUT);
/* Configure a Auto-Refresh command */ 
Command.CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE;
Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
Command.AutoRefreshNumber = 8;
Command.ModeRegisterDefinition = 0;
/* Send the command */
HAL_SDRAM_SendCommand(&hsdram2, &Command, SDRAM_TIMEOUT);
/* Configure a load Mode register command */
Command.CommandMode = FMC_SDRAM_CMD_LOAD_MODE;
Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
Command.AutoRefreshNumber = 2;
Command.ModeRegisterDefinition = (uint32_t)0x230;
/* Wait until the SDRAM controller is ready */
/* Send the command */
HAL_SDRAM_SendCommand(&hsdram2, &Command, SDRAM_TIMEOUT);
/* Step 6: Set the refresh rate counter */
/* Set the device refresh rate */
//64ms for 8192 rows = 7.8125 us.
//(7.8125us * 108 MHz ) - 20 = 875
HAL_SDRAM_ProgramRefreshRate(&hsdram2, 0x337);
//SYSCFG->MEMRMP |= 0x00000400;
}
void HAL_MspInit(void)
{
//Initialize Peripherals
InitFMC();
}
void HAL_SDRAM_MspInit(SDRAM_HandleTypeDef* hsdram)
{
GPIO_InitTypeDef GPIO_InitStruct;
__HAL_RCC_FMC_CLK_ENABLE();
/* GPIOC */
__HAL_RCC_GPIOC_CLK_ENABLE();
//PC0:nWE
//PC2:nCS
//PC3:CKE
GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_2 | GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/* GPIOD */
__HAL_RCC_GPIOD_CLK_ENABLE();
//PD0:DQ2
//PD1:DQ3
//PD8:DQ13
//PD9:DQ14
//PD10:DQ15
//PD14:DQ0
//PD15:DQ1
GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_8 | GPIO_PIN_9 |
GPIO_PIN_10 | GPIO_PIN_14 | GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); 
/* GPIOE */
__HAL_RCC_GPIOE_CLK_ENABLE();
//PE0:DQML
//PE1:DQMH
//PE7:DQ4
//PE8:DQ5
//PE9:DQ6
//PE10:DQ7
//PE11:DQ8
//PE12:DQ9
//PE13:DQ10
//PE14:DQ11
//PE15:DQ12
GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | 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_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
/* GPIOF */
__HAL_RCC_GPIOF_CLK_ENABLE();
//PF0:A0
//PF1:A1
//PF2:A2
//PF3:A3
//PF4:A4
//PF5:A5
//PF11:nRAS
//PF12:A6
//PF13:A7
//PF14:A8
//PF15:A9
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_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
/* GPIOG */
__HAL_RCC_GPIOG_CLK_ENABLE();
// PG0:A10
// PG1:A11
// PG2:A12
// PG4:BA0
// PG5:BA1
// PG8:CLK
// PG15:nCAS
GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | 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_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);
}
//In startup.s
; <
h
> Heap Configuration
; <
o
> Heap Size (in Bytes) <
0x0-0xFFFFFFFF:8
>
; </
h
>
Heap_Size EQU 0x02000000
AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem SPACE Heap_Size
__heap_limit
//Scatter file
LR_IROM1 0x08040000 0x000C0000 { ; load region size_region
ER_IROM1 0x08040000 0x000C0000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
}
RW_IRAM1 0x20010000 0x00040000 { ; RW data
.ANY (+RW +ZI)
}
RW_IRAM2 0x20000000 0x00010000 {
CSCH_DTCM_Buffers.o (+ZI +RW)
}
RW_RAM1 0xC0000000 0x02000000 {
*(HEAP)
}
}

Thank you! #stm32f7 #heap #sdram
6 REPLIES 6
Posted on May 05, 2016 at 00:22

By the time you get to main() the linker's run time code should already have access to the SDRAM, so the mechanics here seem broken.

Have you actually stepped into the allocator code?

Have you tried clearing the heap's memory arena? ie memset() it all to zero

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
keaven
Associate II
Posted on May 05, 2016 at 15:51

It is why the keil library put the initialization into the startup_stm32f745xx.s file.  I will try to with the initialization there instead through HAL_Init().

No I didn't check out the allocator.  I did not try to zero everything also but tried a malloc().

Thank you suggestion .

Keaven

Posted on May 05, 2016 at 17:40

Normally yes, the address/memory bus hard should be setup by code in startup.s, or called into, in the CMSIS case SystemInit() in system.c

It should then call __main which after it's done initializing the statics, calls your main() function.

The .MAP file should be indicative of where the linker has placed everything.

When things Hard Fault it's important to go look at exactly what the chip is objecting too, as it will give you more specific understanding of what is wrong.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
keaven
Associate II
Posted on May 05, 2016 at 20:40

I have modified the startup_stm32f745xx.c file to initialized my SDRAM there. I can access my SDRAM with a pointer mapped this address. I did a scatter file to split my SDRAM into 2 segments so I can use one for the HEAP. My map file shows that I move correctly my HEAP into this segment.

//Extracted from .MAP file
STACK 0x20010f98 Section 1024 startup_stm32f745xx.o(STACK)
Stack_Mem 0x20010f98 Data 1024 startup_stm32f745xx.o(STACK)
__initial_sp 0x20011398 Data 0 startup_stm32f745xx.o(STACK)
HEAP 0xc0000000 Section 16777216 startup_stm32f745xx.o(HEAP)
Heap_Mem 0xc0000000 Data 16777216 startup_stm32f745xx.o(HEAP)
//Scatter File
LR_IROM1 0x08040000 0x000C0000 { ; load region size_region
 ER_IROM1 0x08040000 0x000C0000 { ; load address = execution address
 *.o (RESET, +First)
 *(InRoot$$Sections)
 .ANY (+RO)
 }
 RW_IRAM1 0x20010000 0x00040000 { ; RW data
 .ANY (+RW +ZI)
 }
 RW_IRAM2 0x20000000 0x00010000 {
 CSCH_DTCM_Buffers.o (+ZI +RW)
 }
 RW_RAM1 0xC0000000 UNINIT 0x01800000 {
 *(HEAP)
 }
 RW_RAM2 0xC1800000 UNINIT 0x00800000 {
 CSCH_SDRAM_Buffers.o (+ZI +RW)
 }
}
 
 

My SDRAM is connected to bank 1 so 0xC000 0000 memory address. The problem I have now is I get a preciserr harware fault when I am doing a malloc() at the address0x764496EE which isn't my SDRAM address. This is reserved for NOR/SRAM/PSRAM. A memset((void*) 0xC0000000, 0x00, 512) works without problem. I dont understand this behavior. Clive1, you have a suggestion? Regards,
keaven
Associate II
Posted on May 05, 2016 at 21:20

Finally, found the problem... It was in my scatter file. It seems that the order the memory segments are defined is important. Below are my 2 scatter files: first is the non-working one and the second the working one.

Thank you for your help.

//Non-Working
LR_IROM1 0x08040000 0x000C0000 { ; load region size_region
ER_IROM1 0x08040000 0x000C0000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
}
RW_IRAM1 0x20010000 0x00040000 { ; RW data
.ANY (+RW +ZI)
}
RW_IRAM2 0x20000000 0x00010000 {
CSCH_DTCM_Buffers.o (+ZI +RW)
}
RW_RAM1 0xC0000000 UNINIT 0x01800000 {
*(HEAP)
}
RW_RAM2 0xC1800000 UNINIT 0x00800000 {
CSCH_SDRAM_Buffers.o (+ZI +RW)
}
}
//Working
LR_IROM1 0x08040000 0x000C0000 { ; load region size_region
ER_IROM1 0x08040000 0x000C0000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
}
RW_RAM1 0xC0000000 UNINIT 0x01800000 {
*(HEAP)
}
RW_RAM2 0xC1800000 UNINIT 0x00800000 {
CSCH_SDRAM_Buffers.o (+ZI +RW)
}
RW_IRAM1 0x20010000 0x00040000 { ; RW data
.ANY (+RW +ZI)
}
RW_IRAM2 0x20000000 0x00010000 {
CSCH_DTCM_Buffers.o (+ZI +RW)
}
}

Willem La Grange
Associate II
Posted on August 10, 2017 at 13:02

Which compiler are you using?

I personally think what you are trying to do is pretty dangerous. (Using external memory for your HEAP??)

The problems are going to occur in your production of the design. You can potentially do more harm than good because you will get your processor into unknown states if you have hardware production errors and no means to identify the problem. You can, of course, have two firmware programming and testing processes to eliminate production problems, but that really adds on to your production costs.

I don't know your compiler, but I think you should just check your malloc.h or stdlib.h file for your heap limitations if you are getting hardfualt errors.

Also, is your FMC initialized BEFORE your initialize your heap? I don't think that is so. In my view, you initialized the kernel before HAL_Init() - Just something to check also,,.