RISC-V MCU 开发教程之CH32V307配置Flash和RAM

本文介绍了嵌入式微控制器赤兔V307的Flash和SRAM配置选项,包括可选的存储容量升级、用户代码部署策略以及使用WCHISBTool进行配置的方法。特别关注了可配置内存的细节和注意事项,适合RISC-V开发者和嵌入式系统设计者。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

赤菟V307(CH32V307)是一款RISC-V内核的MCU,搭载的是沁恒自研RISC-V内核青稞V4F,最高主频144MHz,支持单精度浮点运算(FPU)。通常官网介绍Flash大小为256 KB,SRAM大小为64 KB。

仔细阅读应用手册发现,其Flash和SRAM的大小支持配置,具体配置项如下:

  • 192 KB Flash + 128 KB SRAM

  • 224 KB Flash + 96 KB SRAM

  • 256 KB Flash + 54 KB SRAM

  • 288 KB Flash + 32 KB SRAM

彩蛋1

RAM最高可配置到128 KB,直接翻倍,可以撸起袖子敲代码啦,再也不用担心RAM不够啦~

其实赤菟V307内部有一块320 KB SRAM,分为A、B两块,A、B块的大小由用户选择字的user的SRAM_CODE_MODE 位决定,A块负责存放用户代码,B块留作单片机真正的SRAM,每次上电运行时,内部自动从Code Flash中加载A块大小的用户代码运行。

当然用户代码的实际Flash和SRAM大小不要超出配置的范围,否则会导致程序无法运行等问题。

实际在操作Flash时,也不会有Flash等待的问题。

彩蛋2

细心的小伙伴或许会发现,V307 Flash最大配置为288 KB,而Code Flash的大小为488 KB,这也是隐藏的彩蛋哦,剩下的200 KB Flash可以当作存储用,不过需要注意该处Flash等待的问题

配置方法

既然赤菟V307的Flash和SRAM是可配置的,那么聊聊配置的方法吧!

(1)WCHISBTool配置

  • step 1:切换启动模式,BOOT0 = 1,BOOT1 = 0

  • step 2:通过WCHISPTool工具配置用户选择字,具体步骤见下图

  • step 3:切换启动模式,BOOT0 = 0,BOOT1 = 0

(2)用户代码配置

typedef enum
{
    FlASH_192_SRAM_128 = 0,
    FLASH_224_SRAM_96,
    FLASH_256_SRAM_64,
    FLASH_288_RAM_32
} FLASH_SRAM_DEFIN;
​
//note: this operation will take effect after reset
void Config_Flash_SRAM(FLASH_SRAM_DEFIN SetFlashSRAM)
{
    uint8_t UserByte = FLASH_GetUserOptionByte() & 0xff; //get user option byte
​
    switch(SetFlashSRAM)
    {
    case 0:
        UserByte &= ~(0xc0); // SRAM_CODE_MODE = 00
        break;
    case 1:
        UserByte &= ~(0xc0); // SRAM_CODE_MODE = 00
        UserByte |= 0x7f;    // SRAM_CODE_MODE = 01
        break;
    case 2:
        UserByte &= ~(0xc0); // SRAM_CODE_MODE = 00
        UserByte |= 0xbf;    // SRAM_CODE_MODE = 10
        break;
    case 3:
        UserByte |= 0xff;    // SRAM_CODE_MODE = 11
        break;
    default:
        break;
    }
​
    FLASH_Unlock();
    FLASH_ProgramOptionByteData(0x1ffff802, UserByte);
    FLASH_Lock();
}
​
/*********************************************************************
 * @fn      main
 *
 * @brief   Main program.
 *
 * @return  none
 */
int main(void)
{
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    Delay_Init();
    USART_Printf_Init(115200);
    printf("SystemClk:%d\r\n", SystemCoreClock);
​
​
    Config_Flash_SRAM(FLASH_288_RAM_32); //配置Flash为244 KB,SRAM为96KB ,复位后生效
    
    printf("userByte = %02x \r\n",FLASH_GetUserOptionByte() & 0xff);  
​
    while(1)
    {
        ;
    }
}

注意以上两种配置方式完成后,还需要同步用户工程代码的ld链接文件中Flash 和 SRAM的大写,与用户选择字配置的大小保持一致。需要了解RISC-V MCU ld链接文件的可以查看该贴:RISC-V MCU ld链接脚本说明

———————————————— 版权声明:本文为优快云博主「Taoyukai」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.youkuaiyun.com/Taoyukai/article/details/123099571 

<think>我们正在讨论的是沁恒CH58x系列(特别是CH584M)基于RISC-V架构的MCU。根据引用[4],该芯片使用MounRiver Studio IDE环境进行编译,且代码兼容性较好。固定变量到固定地址的方法与之前讨论的类似,但由于是RISC-V架构,我们需要确认编译器支持的特性。 在RISC-V GCC编译器中(MounRiver Studio使用的工具链),通常使用`__attribute__((section(".section_name")))`结合链接脚本,或者使用`__attribute__((aligned(alignment)))`绝对地址定位。 但是,注意:在GCC中,直接指定绝对地址的attribute是`__attribute__((at(address)))`,但根据GCC文档,这个属性是ARM编译器(armcc)支持的,在RISC-V GCC中并不直接支持`at`属性。因此,我们需要使用链接脚本来实现。 ### 方法一:使用`__attribute__((section))`链接脚本(推荐) 1. **在代码中定义变量并指定段名**: 例如,将变量放在一个自定义的段中,比如`.myvars`。 ```c uint32_t my_variable __attribute__((section(".myvars"))) = 0x12345678; ``` 2. **修改链接脚本(.ld文件)**: 在链接脚本中,将自定义段定位到指定的地址。例如,我们想将变量定位到0x20001000(假设这是SRAM中的一个地址)。 打开项目的链接脚本(通常在项目目录下,扩展名为.ld),找到内存区域定义(如RAM),然后添加一个自定义段: ```ld MEMORY { RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 32K /* 假设RAM起始地址长度 */ ... /* 其他内存区域 */ } SECTIONS { ... /* 其他段 */ .myvars 0x20001000 : { . = ALIGN(4); *(.myvars) . = ALIGN(4); } > RAM ... /* 其他段 */ } ``` 这样,所有放在`.myvars`段中的变量都会被放置在0x20001000地址处。 ### 方法二:使用指针直接访问固定地址(不定义变量,直接操作内存) 如果只是需要访问特定地址,可以直接使用指针: ```c #define MY_VARIABLE_ADDRESS (0x20001000) volatile uint32_t * const my_variable = (uint32_t *)MY_VARIABLE_ADDRESS; // 使用 *my_variable = 0x12345678; ``` 这种方法不需要修改链接脚本,但要注意: - 该地址必须是可写的(如SRAM)。 - 确保没有其他变量或代码使用该地址。 ### 方法三:使用汇编定义符号(高级) 在汇编文件中定义一个符号,并在链接脚本中指定其地址,然后在C中引用。这种方法较为复杂,一般不常用。 ### 注意事项 1. **地址对齐**:确保指定的地址符合变量的对齐要求(例如,32位变量通常需要4字节对齐)。 2. **初始化**:对于需要初始化的变量,链接器会将其放在初始化数据段(.data)中,并在启动时由启动代码进行初始化。但使用链接脚本固定地址后,需要确保启动代码不会覆盖该地址的初始化(因为该地址可能不在.data段中)。因此,通常我们使用未初始化的段(.bss)或者自行初始化。 3. **多变量**:如果多个变量需要放在相邻的固定地址,可以在同一个段中定义多个变量,并在链接脚本中指定整个段的起始地址。 ### 示例:将多个变量放在固定地址 1. 代码: ```c uint32_t var1 __attribute__((section(".my_fixed_section"))); uint32_t var2 __attribute__((section(".my_fixed_section"))); ``` 2. 链接脚本: ```ld .my_fixed_section 0x20001000 : { *(.my_fixed_section) } > RAM ``` 这样,var1var2将被连续放置在0x200010000x20001004(假设对齐为4字节)。 ### 在MounRiver Studio中配置链接脚本 根据引用[4],MounRiver Studio支持RISC-V开发。要修改链接脚本,通常需要: 1. 在项目文件夹中找到链接脚本(如.ld文件)。 2. 修改链接脚本,添加自定义段。 3. 重新编译项目。 如果项目中没有链接脚本,可能需要从例程中复制一个,然后在工程设置中指定自定义链接脚本。 ### 总结 在沁恒CH58x(RISC-V架构)中固定变量到固定地址,推荐使用链接脚本结合`__attribute__((section))`的方法。这种方法灵活且可靠,适用于需要精确控制变量位置的情况。 --- §§相关问题§§ 1. 如何在沁恒CH58x中配置链接脚本以实现自定义内存布局? 2. 沁恒CH58x的SRAM地址范围是多少?如何避免地址冲突? 3. 如何在MounRiver Studio中调试并查看变量地址? 4. 沁恒CH58x的启动过程中如何初始化.data.bss段? 5. RISC-V架构的沁恒CH58x中断向量表如何重定位?</think>在沁恒 CH58x 系列(特别是 CH584M)RISC-V 架构芯片中,将变量固定到特定地址的方法主要基于 GCC 编译器的特性链接脚本控制。以下是具体实现方法: ### 一、使用 `__attribute__((section))` + 链接脚本(推荐方法) 这是最可靠且跨平台兼容的方式,适用于 MounRiver Studio 的 RISC-V GCC 工具链[^4]。 1. **代码中定义带段属性的变量**: ```c // 将变量放入自定义段 .fixed_addr_section uint32_t my_variable __attribute__((section(".fixed_addr_section"))) = 0x12345678; ``` 2. **修改链接脚本(.ld 文件)**: 在项目的链接脚本中(如 `CH58x.ld`)添加: ```ld MEMORY { RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 32K /* 根据实际芯片调整 */ } SECTIONS { /* 其他标准段... */ .fixed_addr 0x20001000 : { /* 指定绝对地址 */ KEEP(*(.fixed_addr_section)) /* 保持段不被优化 */ } > RAM } ``` ### 二、直接地址访问(简单场景) 对于不需要初始化的硬件寄存器或共享内存: ```c #define MY_REGISTER (*(volatile uint32_t *)(0x20001000)) void main() { MY_REGISTER = 0x55AA; // 直接写入地址 uint32_t val = MY_REGISTER; // 直接读取地址 } ``` ### 三、特殊编译器扩展(需验证支持) 某些工具链可能支持简化语法(需查阅具体编译器文档): ```c // 语法可能因工具链而异 __attribute__((at(0x20001000))) uint32_t my_var; // 部分编译器支持 ``` --- ### CH58x 关键注意事项 1. **地址有效性验证**: - SRAM 起始地址:`0x20000000`(参考 CH32V307 设计[^2]) - 使用前通过 `SystemInformation()` 函数确认实际内存范围 ```c extern uint32_t __RAM_start; // 链接脚本定义的符号 extern uint32_t __RAM_end; ``` 2. **多核/中断安全**: ```c // 对共享地址的操作需加锁 __disable_irq(); // 关中断 MY_SHARED_VAR += value; __enable_irq(); ``` 3. **调试验证**: - 在 MounRiver Studio 中: ```c printf("Var addr: %p", &my_variable); // 输出地址 ``` - 通过 Memory Viewer 直接查看 `0x20001000` 内容 --- ### 示例完整流程(MounRiver Studio) 1. 创建 `custom_sections.ld` 文件并添加到工程 2. 修改工程设置指定链接脚本: ``` Project Properties > C/C++ Build > Settings > Tool Settings > Linker > General > Script File ``` 3. 代码中使用: ```c // 固定到0x20001000的变量 __attribute__((section(".hw_reg"))) volatile uint32_t USB_STATUS_REG; // 链接脚本对应段 .usb_status 0x20001000 : { KEEP(*(.hw_reg)) } > RAM ``` ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值