RT-Thread论坛
直播中

萧蔼晨

9年用户 1070经验值
私信 关注
[问答]

请问keil+Env怎么把很大的数组定义到SDRAM中?

keil+Env怎么把很大的数组定义到SDRAM中?
RTT自带的SDRAM程序运行正常,能够申请里面的空间。
但是没有办法把很大的数组——ltdc_lcd_framebuf[1280][800]
定义到SDRAM中,一运行就出错,请问各位大佬怎么解决啊?


回帖(1)

王平

2025-10-20 17:08:19

在Keil+Env环境下将大数组(如ltdc_lcd_framebuf[1280][800])分配到SDRAM中,需要结合RT-Thread的内存管理和链接脚本配置。以下是详细步骤和解决方案:




根本原因分析



  1. 初始化顺序问题:SDRAM初始化(sdram_init())在全局变量初始化之后执行,导致数组访问时SDRAM尚未就绪。

  2. 内存属性配置:默认链接脚本未将SDRAM区域标记为可写(RW),导致硬件错误。

  3. 动态分配问题:直接定义全局数组时,编译器将其放入内部RAM(默认堆栈空间不足)。




解决方案一:动态分配(推荐)


在SDRAM初始化后动态申请内存,避免初始化顺序冲突。


#include 

// 声明为指针,而非静态数组
uint16_t (*lcd_fb)[800]; // 或 uint16_t *lcd_fb;

void lcd_init() {
    // SDRAM初始化后动态分配
    lcd_fb = rt_malloc(1280 * 800 * sizeof(uint16_t));
    if (!lcd_fb) {
        rt_kprintf("SDRAM alloc failed!n");
        return;
    }
    // 使用lcd_fb操作显存
}

优点:避开启动初始化顺序问题,无需修改链接脚本。




解决方案二:修改链接脚本(静态分配)


步骤 1:配置分散加载文件(.sct



  1. 在工程目录创建/修改链接脚本(如link.sct):
    LR_IROM1 0x08000000 {        ; 内部Flash
       ER_IROM1 0x08000000 0x100000 {
           *.o (RESET, +First)
           *(InRoot$$Sections)
           .ANY (+RO)
       }
       RW_IRAM1 0x20000000 0x50000 { ; 内部RAM
           .ANY (+RW +ZI)
       }
       RW_SDRAM 0xC0000000 0x800000 { ; SDRAM区域(起始地址0xC0000000)
           .ANY (sdram_section)       ; 自定义段名
       }
    }

  2. 在Keil中启用自定义链接脚本:

    Options for Target → Linker → Scatter File 选择link.sct


步骤 2:代码中指定段属性


// 将数组分配到sdram_section段
__attribute__((section("sdram_section"))) uint16_t ltdc_lcd_framebuf[1280][800];

步骤 3:确保SDRAM提前初始化


在启动代码(startup_xxx.s)或rt_hw_board_init()最早初始化SDRAM:


// board.c
void rt_hw_board_init() {
    sdram_init(); // 必须放在其他初始化之前
    // ...其他初始化
}



解决方案三:使用RT-Thread的memheap多内存堆


将SDRAM加入系统堆,动态分配自动使用SDRAM。


// 初始化SDRAM后,将其加入内存堆
#include

extern void sdram_init(void);
static struct rt_memheap sdram_heap;

void sdram_heap_init() {
    sdram_init(); // 初始化SDRAM
    rt_memheap_init(&sdram_heap, "sdram", (void*)0xC0000000, 8*1024*1024); // 8MB
}
INIT_BOARD_EXPORT(sdram_heap_init); // 设为最先初始化

// 动态分配(优先使用SDRAM)
uint16_t *fb = rt_malloc(1280*800*sizeof(uint16_t));



关键验证点



  1. SDRAM初始化顺序

    使用INIT_BOARD_EXPORT确保sdram_init()所有全局变量初始化前完成。

  2. 链接脚本正确性

    检查.sct文件中SDRAM地址与硬件一致(如0xC0000000)。

  3. 硬件访问权限

    确认MPU/MMU配置允许内核访问SDRAM区域(通常需配置为Normal Memory)。




常见问题排查



  • HardFault错误

    检查SDRAM初始化是否成功(读写测试)、链接脚本地址是否匹配硬件。

  • 数组未被放入SDRAM

    检查.map文件确认数组地址是否在0xC0000000起始范围。

  • 动态分配失败

    确保rt_memheap_init正确执行,且堆大小充足。


通过上述方法,即可安全地将大数组分配到SDRAM中。推荐优先使用动态分配,避免静态分配的初始化顺序问题。

举报

更多回帖

发帖
×
20
完善资料,
赚取积分