Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
memheap
STM32F407 添加外部 SRAM
发布于 2019-08-12 22:21:46 浏览:5666
订阅该版
[tocm] _本帖最后由 wuhanstudio 于 2019-8-12 22:36 编辑_ # 为什么要添加外部 SRAM 最近准备在 RT-Thread 上加载一些机器学习模型,通常做目标检测 (object detection) 标准模型 (Yolov3, SSD) 一般在 200MB-300MB,精简版 (tiny-yolov3, tiny ssd) 也在 20MB-30MB,一些特别精简的模型 (SqueezeDet) 可以只有 4MB,但是 STM32 的 SRAM 都是按照 KB 来计算的,所以要加载模型无法避免地要用到外部 SRAM,于是决定在 STM32F407ZGT6 上面外扩一个 SRAM。 ## SRAM 种类 板子上的 SRAM 是 IS62WV51216 (1MB),虽然很明显就算外扩了这个 1MB 的内存,也是没办法完整加载模型的,但是最后还是试了一下,因为以前没有尝试过外扩 SRAM,刚好也试一试做个总结。 其实如果要加载大模型,应当用 SDRAM (Synchronous Dynamic Random Access Memory) 而不是 SRAM (Static Random Access Memory),这两者的区别在于静态随机存储器 (SRAM) 是使用具有记忆功能的触发器 (Flip-Flop),它物理材料是比较占用空间的晶体管 (Transistor),而动态随机存储器 (SDRAM) 则是用的电容 (Capacitor),于是相同大小的物理空间,如果 SDRAM 可以存储几个 GB 的数据,那么 SRAM 只能保存几十 MB 的数据。因此相同存储容量 SRAM 芯片尺寸就会比 SDRAM 大很多,电脑的大内存也是 DDR SDRAM。 但是 SRAM 也有好处,因为它用的是晶体管 (Transistor),所以只要上电了它的数据就可以自动保存;如果是 SDRAM 的话,因为它用的是电容 (Capacitor),电量就会逐渐衰减导致数据丢失,因此需要反复刷新充电。这样的结果就是 SRAM 操作起来非常容易,不需要像 SDRAM 那样需要有同步时钟反复刷新。另一方便,晶体管 (Transistor) 的开断速度通常要远快于电容 (Capacitor) 的充电速度,所以 SRAM 的速度也会比 SDRAM 快很多。 总结一下,就是 SRAM 速度快,容量小,操作简单;SDRAM 速度相对慢,容量大,需要反复刷新。 [http://www.differencebetween.net/object/difference-between-sram-and-sdram/](http://www.differencebetween.net/object/difference-between-sram-and-sdram/) ## RT-Thread 外置 SRAM 要在 RT-Thread 上使用外置的 SRAM,可以利用 STM32 的 FSMC,首先利用 CubeMX 根据自己的 SRAM 时序配置,并点击 Generate Code 生成代码: [/size] [attach]10084[/attach] 然后在自己 bsp 下添加 sram 的驱动,例如在 `F:\rt-thread\bsp\stm32\stm32f407-atk-explorer\board\ports` 里添加 drv_sram.c ```c #include
#include
#include
#ifdef BSP_USING_SRAM #include
#define DRV_DEBUG #define LOG_TAG "drv.sram" #include
static SRAM_HandleTypeDef hsram; static FMC_NORSRAM_TimingTypeDef SRAM_Timing; #ifdef RT_USING_MEMHEAP_AS_HEAP static struct rt_memheap system_heap; #endif static int SRAM_Init(void) { int result = RT_EOK; /* SRAM device configuration */ hsram.Instance = FMC_NORSRAM_DEVICE; hsram.Extended = FMC_NORSRAM_EXTENDED_DEVICE; /* SRAM device configuration */ SRAM_Timing.AddressSetupTime = ADDRESSSETUPTIME; SRAM_Timing.AddressHoldTime = ADDRESSHOLDTIME; /* Min value, Don't care on SRAM Access mode A */ SRAM_Timing.DataSetupTime = DATASETUPTIME; // SRAM_Timing.DataHoldTime = DATAHOLDTIME; SRAM_Timing.BusTurnAroundDuration = BUSTURNAROUNDDURATION; SRAM_Timing.CLKDivision = CLKDIVISION; /* Min value, Don't care on SRAM Access mode A */ SRAM_Timing.DataLatency = DATALATENCY; /* Min value, Don't care on SRAM Access mode A */ SRAM_Timing.AccessMode = ACCESSMODE; hsram.Init.NSBank = FSMC_NORSRAM_BANK3; hsram.Init.DataAddressMux = FSMC_DATA_ADDRESS_MUX_DISABLE; hsram.Init.MemoryType = FSMC_MEMORY_TYPE_SRAM; #if SRAM_DATA_WIDTH == 8 hsram.Init.MemoryDataWidth = FMC_NORSRAM_MEM_BUS_WIDTH_8; #elif SRAM_DATA_WIDTH == 16 hsram.Init.MemoryDataWidth = FMC_NORSRAM_MEM_BUS_WIDTH_16; #else hsram.Init.MemoryDataWidth = FMC_NORSRAM_MEM_BUS_WIDTH_32; #endif hsram.Init.BurstAccessMode = FSMC_BURST_ACCESS_MODE_DISABLE; hsram.Init.WriteOperation = FSMC_WRITE_OPERATION_ENABLE; hsram.Init.WaitSignal = FSMC_WAIT_SIGNAL_DISABLE; hsram.Init.WaitSignalActive = FSMC_WAIT_TIMING_BEFORE_WS; hsram.Init.WaitSignalPolarity = FSMC_WAIT_SIGNAL_POLARITY_LOW; hsram.Init.ExtendedMode = FSMC_EXTENDED_MODE_DISABLE; hsram.Init.AsynchronousWait = FSMC_ASYNCHRONOUS_WAIT_DISABLE; hsram.Init.WriteBurst = FSMC_WRITE_BURST_DISABLE; hsram.Init.ContinuousClock = FSMC_CONTINUOUS_CLOCK_SYNC_ONLY; // hsram.Init.WriteFifo = FSMC_WRITE_FIFO_DISABLE; // hsram.Init.NBLSetupTime = 0; hsram.Init.PageSize = FSMC_PAGE_SIZE_NONE; /* Initialize the SRAM controller */ if (HAL_SRAM_Init(&hsram, &SRAM_Timing, &SRAM_Timing) != HAL_OK) { LOG_E("SRAM init failed!"); result = -RT_ERROR; } else { LOG_D("sram init success, mapped at 0x%X, size is %d bytes, data width is %d", SRAM_BANK_ADDR, SRAM_SIZE, SRAM_DATA_WIDTH); #ifdef RT_USING_MEMHEAP_AS_HEAP /* If RT_USING_MEMHEAP_AS_HEAP is enabled, SRAM is initialized to the heap */ rt_memheap_init(&system_heap, "sram", (void *)SRAM_BANK_ADDR, SRAM_SIZE); #endif } return result; } INIT_DEVICE_EXPORT(SRAM_Init); #ifdef DRV_DEBUG #ifdef FINSH_USING_MSH int sram_test(void) { int i = 0; uint32_t start_time = 0, time_cast = 0; #if SRAM_DATA_WIDTH == 8 char data_width = 1; uint8_t data = 0; uint8_t *ptr = (uint8_t *)SRAM_BANK_ADDR; #elif SRAM_DATA_WIDTH == 16 char data_width = 2; uint16_t data = 0; uint16_t *ptr = (uint16_t *)SRAM_BANK_ADDR; #else char data_width = 4; uint32_t data = 0; uint32_t *ptr = (uint32_t *)SRAM_BANK_ADDR; #endif /* write data */ LOG_D("Writing the %ld bytes data, waiting....", SRAM_SIZE); start_time = rt_tick_get(); for (i = 0; i < SRAM_SIZE / data_width; i++) { #if SRAM_DATA_WIDTH == 8 ((__IO uint8_t *)ptr) = (uint8_t)0x55; #elif SRAM_DATA_WIDTH == 16 ((__IO uint16_t *)ptr) = (uint16_t)0x5555; #else ((__IO uint32_t *)ptr) = (uint32_t)0x55555555; #endif } time_cast = rt_tick_get() - start_time; LOG_D("Write data success, total time: %d.%03dS.", time_cast / RT_TICK_PER_SECOND, time_cast % RT_TICK_PER_SECOND / ((RT_TICK_PER_SECOND * 1 + 999) / 1000)); /* read data */ LOG_D("start Reading and verifying data, waiting...."); for (i = 0; i < SRAM_SIZE / data_width; i++) { #if SRAM_DATA_WIDTH == 8 data = ((__IO uint8_t *)ptr); if (data != 0x55) { LOG_E("SRAM test failed at %d!", i); continue; } #elif SRAM_DATA_WIDTH == 16 data = ((__IO uint16_t *)ptr); if (data != 0x5555) { LOG_E("SRAM test failed at %d!", i); continue; } #else data = ((__IO uint32_t *)ptr); if (data != 0x55555555) { LOG_E("SRAM test failed at %d!", i); continue; } #endif } if (i >= SRAM_SIZE / data_width) { LOG_D("SRAM test end!"); } return RT_EOK; } MSH_CMD_EXPORT(sram_test, sram test); #endif /* FINSH_USING_MSH */ #endif /* DRV_DEBUG */ #endif /* BSP_USING_SRAM */ ``` ## 以及对应的配置文件 sram_port.h ``` #ifndef __SDRAM_PORT_H__ #define __SDRAM_PORT_H__ /* parameters for sdram peripheral */ /* Bank1 */ #define SRAM_TARGET_BANK 3 /* stm32f4 Bank1:0x60000000 */ #define SRAM_BANK_ADDR ((uint32_t)0x68000000) /* data width: 8, 16, 32 */ #define SRAM_DATA_WIDTH 16 /* sram size */ #define SRAM_SIZE ((uint32_t)0x100000) /* Timing configuration for IS61WV102416BLL-10MLI */ #define ADDRESSSETUPTIME 0 #define ADDRESSHOLDTIME 0 #define DATASETUPTIME 9 #define DATAHOLDTIME 1 #define BUSTURNAROUNDDURATION 0 #define CLKDIVISION 0 #define DATALATENCY 0 #define ACCESSMODE FSMC_ACCESS_MODE_A /* Timing configuration for IS61WV102416BLL-10MLI */ #endif ``` 还需要需要修改对应的 Sconscript,这样就生成项目就可以自动添加文件了,例如 `F:\rt-thread\bsp\stm32\stm32f407-atk-explorer\board\Sconscript` 里添加: ``` if GetDepend(['BSP_USING_SRAM']): src += Glob('ports/drv_sram.c') ``` 如果希望用 rt_malloc 和 rt_free 统一管理这块内存,需要打开 memheap [attach]10090[/attach] 最后由于用到了 FSMC 和 SRAM 需要在 rtconfig.h 里添加: ``` #define BSP_USING_SRAM #define BSP_USING_FMC #define BSP_USING_EXT_FMC_IO ``` 这样就可以生成项目文件并编译了: ``` scons --target=mdk5 -s ``` RT-Thread 外置 SRAM 测试 如果一切正常的话开机在 msh 里输入 free 应当可以看到对应的内存块: ``` \ | / - RT - Thread Operating System / | \ 4.0.2 build Aug 12 2019 2006 - 2019 Copyright by rt-thread team [D/drv.sram] sram init success, mapped at 0x68000000, size is 1048576 bytes, data width is 16 msh >free memheap pool size max used size available size -------- ---------- ------------- -------------- sram 1048576 48 1048528 heap 126480 7192 119288 msh> ``` 可以看到这里我外置的 SRAM 大小就是 1M,如果输入 sram_test 可以对挂载的内存进行测试,确保数据读写是正常的: ``` msh >sram_test [D/drv.sram] Writing the 1048576 bytes data, waiting.... [D/drv.sram] Write data success, total time: 0.053S. [D/drv.sram] start Reading and verifying data, waiting.... [D/drv.sram] SRAM test end! msh > ``` ##总结 最后 STM32F407 的 SRAM1 有 128KB 的内存,加上外置的 1MB,一共就有了 1152KB 的内存了,但是这并不意味着可以一次性 malloc 这么多内存,因为它们在2个不同的物理内存单元上,RTT的内存管理可以将两个不同的物理内存单元合并为一个单元统一由 rt_malloc 和 rt_free 管理,但是只能在相同的物理内存单元上合并相邻的内存碎片,如果要申请的内存太大,即使跨物理单元有一块那么大的内存加在一起有那么大,也是没办法成功申请的。 还是希望能帮助到觉得内存不够的小伙伴。 [attach]10091[/attach] [attach]10092[/attach] [attach]10093[/attach]
查看更多
18
个回答
默认排序
按发布时间排序
lostage
2024-05-02
这家伙很懒,什么也没写!
```c ((__IO uint16_t *)ptr) = (uint16_t)0x5555; data = ((__IO uint16_t *)ptr); ``` 少了星号, 关于测试,这个ptr不自增,写入的数据的地址不都是0x6800000吗?
撰写答案
登录
注册新账号
关注者
0
被浏览
5.7k
关于作者
wuhanstudio
这家伙很懒,什么也没写!
提问
12
回答
243
被采纳
6
关注TA
发私信
相关问题
1
关于利用0x68000000作为扩展sram?
2
RTT内存使用情况的问题
3
ramfs中的memheap问题
4
rt_system_heap_init函数加入多块物理内存是否有计划解决
5
list_memheap 显示的 max used size
6
求助,外部SDRAM使用memheap管理后系统起不来了
7
C++应用memheap内存管理方法挂死
8
rt_memheap_free 引起的死机
9
探索者f407 使用rt_malloc分配外部sram作为lvgl缓存异常?
10
需要使能memheap在rtstudio中如何设置
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
最新文章
1
【NXP-MCXA153】 定时器驱动移植
2
GD32F450 看门狗驱动适配
3
【NXP-MCXA153】看门狗驱动移植
4
RT-Thread Studio V2.2.9 Release Note
5
CherryUSB的bootuf2配置
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
UART
WIZnet_W5500
ota在线升级
PWM
freemodbus
flash
cubemx
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
编译报错
Debug
rt_mq_消息队列_msg_queue
SFUD
msh
keil_MDK
ulog
C++_cpp
MicroPython
本月问答贡献
踩姑娘的小蘑菇
7
个答案
2
次被采纳
a1012112796
16
个答案
1
次被采纳
Ryan_CW
5
个答案
1
次被采纳
红枫
4
个答案
1
次被采纳
张世争
4
个答案
1
次被采纳
本月文章贡献
YZRD
3
篇文章
6
次点赞
catcatbing
3
篇文章
6
次点赞
lizimu
2
篇文章
9
次点赞
qq1078249029
2
篇文章
2
次点赞
xnosky
2
篇文章
1
次点赞
回到
顶部
发布
问题
分享
好友
手机
浏览
扫码手机浏览
投诉
建议
回到
底部