栈和堆,以STM32为例说明

本文介绍了变量的存储类型(静态和动态)、栈和堆的区别,重点讲解了栈如何存放局部变量和函数参数,以及堆用于动态内存分配的机制。同时提到了STM32开发中涉及的相关资源文件和库。

请添加图片描述


1. 前言

我们先温习一下变量的基础知识,啥是全局变量,啥是局部变量,这里就不赘述了。
变量的存储方式有:静态存储和动态存储。
静态存储方式:指在程序运行期间由系统分配固定的存储空间方式。
动态存储方式:在程序运行期间根据需要进行动态的分配存储空间方式。
全局变量存储在静态存储区中;动态存储区可以存放函数形式参数、局部变量、函数调用时的现场保护和返回地址等。


2. 栈

栈主要用于存放局部变量,函数形参等,属于编译器自动分配和释放的内存,栈的大小不能超过内部 SRAM 的大小。

3. 堆


堆主要用于动态内存的分配,像 malloc()、calloc()和 realloc()等函数申请的内存就在堆上面。堆中的内存一般由程序员分配和释放,若程序员不释放,程序结束时可能由操作系统回收。


参考

【1】正点原子,STM32 启动文件浅析.pdf
【2】正点原子,MAP 文件浅析.pdf
【3】[野火]STM32 HAL库开发实战指南

<think>好的,我现在需要帮助用户解决如何在STM32中将SDRAM配置为内存的问题。首先,我需要回顾用户提供的引用内容之前的对话,确保正确理解需求。用户提到想了解配置方法、初始化过程以及内存分配函数。之前的回答已经涉及了内存分配函数分块式管理,但这次重点是SDRAM作为内存。 首先,根据引用[1],STM32在启动时,SystemInit函数执行时需要使用内部RAM,因为外部SDRAM还未初始化。因此,配置到SDRAM需要确保在初始化SDRAM之后才能使用。CubeMX生成的代码可能已经提供了接口,需要检查启动流程,将SDRAM初始化提前到SystemInit中,或者在main函数之前完成。 引用[2]提到SDRAM所在的External device区不支持XIP,但通过配置SYSCFG_MEMRMP寄存器可以交换地址映射,使得SDRAM支持代码执行。不过用户的问题是关于内存,所以可能需要将空间设置在SDRAM区域,并处理初始化顺序的问题。 引用[3]展示了如何在代码中使用SDRAM,如定义数组读写测试。用户需要的是将内存分配到SDRAM,可能需要修改链接脚本,指定的起始结束地址为SDRAM的地址范围。 引用[4]提供了SDRAM初始化相关的模式寄存器配置,这可能涉及FMC的设置初始化流程中的命令,比如预充电、自动刷新加载模式寄存器等步骤。 接下来需要综合这些信息,分步骤说明配置方法。首先,硬件初始化方面,使用CubeMX配置FMC接口,设置正确的时序参数。然后修改链接脚本,将的地址指向SDRAM区域,但要注意启动阶段使用内部RAM的问题,可能需要分阶段初始化。 初始化流程方面,在SystemInit函数中尽早初始化SDRAM,或者在启动文件的Reset_Handler中调用SDRAM初始化函数,确保在__main之前完成。因为__main会初始化,如果在SDRAM中,但此时SDRAM未初始化,会导致错误。 内存分配函数部分,可能需要自定义的分配函数,或者调整标准库的设置。在链接脚本中定义的大小位置后,mallocfree会自动使用该区域。但用户可能还需要处理多内存池的情况,比如同时使用内部外部内存,这时需要自定义分配函数来选择内存池。 另外,需要考虑地址对齐性能优化。SDRAM的访问速度可能较慢,特别是如果时钟配置不正确,会影响性能。此外,内存碎片的问题也需要处理,可能需要使用块分配或内存池管理来减少碎片。 用户可能遇到的问题包括HardFault,这可能是因为在SDRAM未初始化时就使用了内存。需要确保初始化顺序正确,并且启动阶段的关键函数(如SystemInit)使用内部RAM。此外,链接脚本的修改是否正确,的地址是否在SDRAM的有效范围内也是关键点。 最后,验证步骤需要包括读写测试压力测试,确保SDRAM的稳定性分配函数的正确性。可能还需要调试内存泄漏碎片问题,使用日志记录分配释放的情况。 总结来说,配置SDRAM作为内存需要硬件初始化、链接脚本修改、启动流程调整、分配函数管理以及验证测试。需要特别注意初始化顺序内存区域的正确配置,避免运行时错误。</think>### STM32配置SDRAM为内存的完整实现指南 --- #### 一、硬件层配置(基于STM32CubeMX) 1. **FMC/SDRAM接口初始化** - 在CubeMX中启用FMC控制器,选择SDRAM类型(如IS42S16400J) - 配置时序参数(参考SDRAM芯片手册): ```c /* 示STM32H750配置 */ hsdram1.Instance = FMC_SDRAM_DEVICE; 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; // 根据芯片要求设置[^4] ``` 2. **地址映射优化**(引用[2]修正) ```c // 在SystemInit中配置SYSCFG_MEMRMP寄存器 SYSCFG->MEMRMP |= SYSCFG_MEMRMP_SWP_FMC_0; // 交换SDRAM与NAND地址映射 ``` --- #### 二、链接脚本修改(GCC/Keil/IAR) 1. **定义SDRAM内存区域**(以STM32H750为) ```ld MEMORY { RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K /* 内部SRAM */ SDRAM (xrw) : ORIGIN = 0xC0000000, LENGTH = 8M /* SDRAM起始地址 */ } /* 将空间分配到SDRAM */ _estack = ORIGIN(RAM) + LENGTH(RAM); /* 仍使用内部RAM */ _Heap_Size = 0x20000; /* 128KB空间 */ .heap : { . = ALIGN(8); __heap_start__ = .; . += _Heap_Size; __heap_end__ = .; } >SDRAM ``` --- #### 三、初始化流程优化(关键步骤) 1. **启动阶段SDRAM初始化**(引用[1]修正) ```assembly ; 在startup_stm32h750xx.s的Reset_Handler中插入初始化 Reset_Handler: ldr sp, =_estack bl SystemInit bl SDRAM_Init ; 新增SDRAM初始化调用 bl __main ``` 2. **SDRAM初始化序列实现**(引用[4]扩展) ```c void SDRAM_Init(SDRAM_HandleTypeDef *hsdram) { FMC_SDRAM_CommandTypeDef cmd; /* 1. 发送时钟配置使能命令 */ cmd.CommandMode = FMC_SDRAM_CMD_CLK_ENABLE; HAL_SDRAM_SendCommand(hsdram, &cmd, 0xFFFF); /* 2. 延时1ms(需实现HAL_Delay前使用内部时钟) */ HAL_Delay(1); /* 3. 预充电所有存储区 */ cmd.CommandMode = FMC_SDRAM_CMD_PALL; HAL_SDRAM_SendCommand(hsdram, &cmd, 0xFFFF); /* 4. 自动刷新(至少8次) */ cmd.CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE; for(int i=0; i<8; i++) HAL_SDRAM_SendCommand(hsdram, &cmd, 0xFFFF); /* 5. 加载模式寄存器 */ cmd.CommandMode = FMC_SDRAM_CMD_LOAD_MODE; cmd.ModeRegisterValue = SDRAM_MODEREG_BURST_LENGTH_1 | SDRAM_MODEREG_CAS_LATENCY_3 | SDRAM_MODEREG_WRITEBURST_MODE_SINGLE; // [^4] HAL_SDRAM_SendCommand(hsdram, &cmd, 0xFFFF); /* 6. 设置刷新速率(64ms/8192行=7.8us) */ HAL_SDRAM_ProgramRefreshRate(hsdram, 64000000/8192); } ``` --- #### 四、内存分配函数适配 1. **使用标准库自动管理** 通过链接脚本配置后,`malloc()`/`free()`将自动使用SDRAM空间: ```c uint32_t *buf = (uint32_t*)malloc(1024); // 从SDRAM分配 ``` 2. **多内存池管理(可选)** ```c // 定义内部外部内存分配接口 void* internal_alloc(size_t size) { static uint8_t internal_heap[INTERNAL_HEAP_SIZE]; // 实现内部内存管理... } void* sdram_alloc(size_t size) { return malloc(size); // 使用链接脚本配置的SDRAM } ``` --- #### 五、验证与调试 1. **基础测试代码** ```c void sdram_test(void) { uint32_t *test_ptr = (uint32_t*)malloc(1024*1024); // 申请1MB if(test_ptr) { test_ptr[0] = 0x12345678; // 写入测试 if(test_ptr[0] == 0x12345678) { printf("SDRAM R/W OK\r\n"); } free(test_ptr); } else { printf("SDRAM alloc failed!\r\n"); } } ``` 2. **性能优化技巧** - 启用FMC的写缓冲区(引用[2]): ```c hsdram1.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE; hsdram1.Init.SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_2; // 90MHz时钟[^4] ``` - 使用内存对齐访问: ```c uint32_t *aligned_buf = __attribute__((aligned(32))) malloc(1024); ``` --- ### 常见问题解决方案 1. **HardFault问题** - **原因**:SDRAM初始化前访问内存 - **解决**:检查启动文件初始化顺序,确保SDRAM初始化在`__main`之前完成[^1] 2. **数据写入失败** - **原因**:时序配置错误或刷新周期不当 - **解决**:使用逻辑分析仪捕获FMC时序,验证与SDRAM芯片规格匹配[^3] --- ### 配置流程图解 ```plaintext 启动流程 ├─ 1. 执行Reset_Handler (汇编) │ ├─ 设置指针到内部RAM │ ├─ 调用SystemInit(内部RAM运行) │ └─ 调用SDRAM_Init(关键步骤!) ├─ 2. __main初始化(SDRAM区域) └─ 3. 进入main函数 ``` ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

智驾

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值