IAR 实现类linux驱动模块框架module_init(init_fun)

本文介绍如何在STM32单片机上采用类似Linux的驱动模块框架,通过定义特定的段和初始化函数,实现模块化的驱动管理。利用boot.icf文件配置内存区域,并在main.c中定义初始化函数列表,实现类Linux的驱动加载流程。

其实在单片机上也能使用类linux驱动模块框架module_init(init_fun),从而给驱动管理提供了新的方式。

boot.icf文件

  1. /*###ICF### Section handled by ICF editor, don't touch! ****/
  2. /*-Editor annotation file-*/
  3. /* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\cortex_v1_0.xml" */
  4. /*-Specials-*/
  5. define symbol __ICFEDIT_intvec_start__ = 0x08000000;
  6. /*-Memory Regions-*/
  7. define symbol __ICFEDIT_region_ROM_start__ = 0x08000000;
  8. define symbol __ICFEDIT_region_ROM_end__ = 0x0807FFFF;
  9. define symbol __ICFEDIT_region_RAM_start__ = 0x20000000;
  10. define symbol __ICFEDIT_region_RAM_end__ = 0x2001FFFF;
  11. /*-Sizes-*/
  12. define symbol __ICFEDIT_size_cstack__ = 0x8000;
  13. define symbol __ICFEDIT_size_heap__ = 0x0000;
  14. /**** End of ICF editor section. ###ICF###*/
  15. define memory mem with size = 4G;
  16. define region ROM_region = mem:[from __ICFEDIT_region_ROM_start__ to __ICFEDIT_region_ROM_end__];
  17. define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__ to __ICFEDIT_region_RAM_end__];
  18. define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { };
  19. define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { };
  20. initialize by copy { readwrite };
  21. do not initialize { section .noinit };
  22. place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec };
  23. place in ROM_region { readonly, section mysection };
  24. place in RAM_region { readwrite,
  25. block CSTACK, block HEAP };
  26. export symbol __ICFEDIT_region_RAM_start__;
  27. export symbol __ICFEDIT_region_RAM_end__;

其实改icf文件很简单,就在 ROM区创建一个名为 “mysection ” 的段。

place in ROM_region   { readonly, section mysection };

main.c

  1. #include <stdio.h>
  2. #pragma section="mysection"
  3. #define MODULE_BEGIN (__segment_begin("mysection"))
  4. #define MODULE_END (__segment_end("mysection"))
  5. typedef void (*init_function_t)(void);
  6. #define _init __attribute__((used, section("mysection")))
  7. #define MODULE_INIT(func) init_function_t _fn_##func @ "mysection" = func // 方法一
  8. //#define MODULE_INIT(func) init_function_t _fn_##func _init = func // 方法二
  9. void drv_spi_init (void)
  10. {
  11. printf("drv_spi_init...\n");
  12. }
  13. MODULE_INIT(drv_spi_init); //将函数放入 “mysection” 段
  14. void drv_uart_init (void)
  15. {
  16. printf("drv_uart_init...\n");
  17. }
  18. MODULE_INIT(drv_uart_init); //将函数放入 “mysection” 段
  19. void drv_i2c_init (void)
  20. {
  21. printf("drv_i2c_init...\n");
  22. }
  23. MODULE_INIT(drv_i2c_init); //将函数放入 “mysection” 段
  24. void do_initcall(void)
  25. {
  26. init_function_t *call = (init_function_t *)MODULE_BEGIN;
  27. init_function_t *end = (init_function_t *)MODULE_END;
  28. /* 逐个初始化驱动 */
  29. do
  30. {
  31. (*call)();
  32. call++;
  33. }while(call < end);
  34. }
  35. /*!
  36. \brief Boot main function
  37. \param[in] none
  38. \param[out] none
  39. \retval none
  40. */
  41. int main(void)
  42. {
  43. /* 驱动列表初始化 */
  44. do_initcall();
  45. /* user code */
  46. //...
  47. return 0;
  48. }

这样就可以在STM32等单片机上实现类linux风格的驱动管理了,同样的方法可以实现module_deinit。

<think>我们正在讨论IAR编译器中的`__iar_init_core`函数。根据IAR编译器的内部机制,这个函数是启动代码(startupcode)的一部分,负责在进入main函数之前初始化处理器核心状态。下面我将详细解释其作用和工作原理。 ###1. **功能定位**`__iar_init_core`是IAR启动序列中的**核心初始化函数**,由汇编启动代码调用。它执行以下关键任务:- **设置初始堆栈指针(SP)**:将SP指向链接器配置中定义的堆栈起始地址[^1]。- **初始化全局变量**:对`.data`段(已初始化全局变量)和`.bss`段(未初始化全局变量)进行内存布局[^2]。- **硬件抽象层初始化**:配置处理器内核寄存器(如ARM架构的CPSR),确保CPU进入正确的操作模式(如Thumb/ARM模式切换)[^3]。 ###2. **执行流程** 在典型的IAR启动序列中,调用关系如下:```mermaidgraph LRReset_Handler -->__iar_program_start__iar_program_start--> __iar_init_core__iar_init_core -->__iar_init_vfp[若存在VFP单元]__iar_init_core -->__cmain__cmain--> main```> **注**:`__cmain`负责C运行时环境的完整建立,包括调用全局对象的构造函数(C++)[^3]。 ###3. **与链接脚本的关联**该函数依赖链接器脚本(如`.xcl`文件)中定义的内存区域符号。例如:-`D_RAM_CODE_FLASH_END`:定义代码段结束地址,用于计算数据段加载位置[^1]。- `SFE(CSTACK)`:指定主堆栈的结束地址(ARM架构中堆栈通常向下增长)。 ###4. **故障诊断** 当出现未定义符号错误(如`Undefinedexternal “?V1”`)时,可能涉及以下问题:- **虚拟寄存器不足**:需在IAR选项中增加`Numberof virtualregisters`(典型值8-16)[^3]。- **启动文件缺失**:检查`chipcon_cstartup.s51`等启动文件是否被正确包含在工程中[^3]。 ###示例场景若用户修改USB初始化代码后出现启动异常(如`HAL_HCD_MspInit`未执行),需验证: 1. `__iar_init_core`是否正确初始化了时钟系统(通过`BSP_CLK_Init`)[^2]。 2.堆栈指针是否指向有效内存区域(避免溢出导致函数调用崩溃)。 ---### §§相关问题§§1.IAR链接器脚本中如何定义堆栈和堆的大小?2.如何自定义IAR的启动文件以支持非标准硬件?3.在调试时如何观察`__iar_init_core`的执行过程?4.为什么修改`D_RAM_CODE_FLASH_END`会影响程序运行?[^1]</think>### `__iar_init_core` 函数在 IAR 编译器中的作用 `__iar_init_core` 是 IAR 编译器启动代码(startup code)中的**核心初始化函数**,负责在程序执行 `main()` 函数前完成处理器核心的初始化工作。其核心作用如下: #### 1. **基础硬件初始化** - **设置堆栈指针(SP)** 初始化主堆栈(Main Stack Pointer)和进程堆栈(Process Stack Pointer),确保函数调用和中断处理有有效的内存空间[^1]。 - **初始化关键寄存器** 配置处理器控制寄存器(如 ARM 的 CONTROL 寄存器),确定操作模式(特权级/用户级)和堆栈使用方式。 #### 2. **内存布局配置** - **定位代码/数据段** 根据链接脚本(如 `.xcl` 文件)中定义的符号(如 `D_RAM_CODE_FLASH_END`)[^1],将代码段(`.text`)、初始化数据段(`.data`)和未初始化数据段(`.bss`)映射到物理地址: ```c // 伪代码示例 extern uint32_t D_RAM_CODE_FLASH_END; // 来自链接脚本 void __iar_init_core() { __set_SP(D_RAM_CODE_FLASH_END); // 设置堆栈起始位置 } ``` - **清零 `.bss` 段** 将未初始化全局变量所在内存区域清零,避免随机值导致未定义行为。 #### 3. **异常向量表初始化** - **设置异常入口** 配置中断向量表(如 ARM 的 `VTOR` 寄存器),确保中断/异常发生时能跳转到正确的处理程序[^3]。 #### 4. **时钟系统预配置** - **基础时钟启动** 在调用用户初始化函数(如 `HAL_HCD_MspInit` 中的 `BSP_CLK_Init()` [^2])前,确保内核时钟处于可操作状态。 --- ### 典型执行流程 ```mermaid graph TD A[芯片上电复位] --> B[执行复位处理程序] B --> C[调用 __iar_init_core] C --> D1[初始化堆栈指针] C --> D2[配置内存布局] C --> D3[清零.bss段] C --> D4[设置异常向量表] C --> D5[基础时钟使能] C --> E[调用 __iar_data_init3] E --> F[初始化.data段] F --> G[进入main函数] ``` --- ### 常见问题解决 当出现类似 `Undefined external “?V1”` 的错误时[^3],可能涉及: 1. **虚拟寄存器不足**:在 IAR 选项中增加 `Number of virtual registers`(通常设为 8-16)。 2. **启动文件缺失**:检查 `chipcon_cstartup.s51` 等启动文件是否包含在工程中。 3. **链接脚本错误**:确认 `.xcl` 文件中符号定义(如 `D_RAM_CODE_FLASH_END`)的地址范围是否冲突[^1]。 > **示例**:修改 `f8w2530.xcl` 中的 `D_RAM_CODE_FLASH_END` 值后需重新编译,否则可能导致堆栈溢出或内存覆盖[^1]。 --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值