类linux驱动模块框架module_init(init_fun)在STM32上的实现

2023-05-16

原文:https://zhuanlan.zhihu.com/p/81309285

设计思想

利用编译器的特性,在程序编译时将各模块初始化函数顺序存放到内存的指定地址,然后在程序运行时main函数从这块内存区域中 依次调用各模块的初始化函数,自动完成各个模块的初始化工作,同时增强了程序的高内聚低耦合特性,提高了软件的质量。

试验环境

  • 工具链:Keil5
  • 开发板:STM32F103ZE

1. 修改链接脚本

修改链接脚本的目的是:在STM32的内存中,留出一块合适的大小(大小根据自己的需求调整), 用来存放各个模块的初始化函数

1.1 内存分配

在Keil中新建一个工程,编译后在工程目录下的Objects文件夹中会自动生成一个以.sct结尾的链接脚本, 其内容如下:

; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************

LR_IROM1 0x08000000 0x00080000  {    ; load region size_region
  ER_IROM1 0x08000000 0x00080000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
   .ANY (+XO)
  }

  ; 此区域(RW_IRAM1)使用所有的内存64Kb
  RW_IRAM1 0x20000000 0x00010000  {  ; RW data
   .ANY (+RW +ZI)
  }
}

我们将其修改:RW_IRAM1为48K,RW_IRAM2为16K,其中RW_IRAM2用来顺序存放各模块的初始化函数。

; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************

LR_IROM1 0x08000000 0x00080000  {    ; load region size_region
  ER_IROM1 0x08000000 0x00080000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
   .ANY (+XO)
  }

  ;RW_IRAM1为48K,供应用程序使用
  RW_IRAM1 0x20000000 0x0000c000  {  ; RW data
   .ANY (+RW +ZI)
  }

  ;RW_IRAM2为16K,用于存放各个模块的初始化函数
  RW_IRAM2 0x2000c000 0x00004000  {  ; RW data
   *.o(RAMCODE)
  }
}

友情提示:keil中链接脚本的修改方法如下图所示

1.2 将指定的函数存放到指定的内存区域

上面我们对STM32的内存进行了分配,16K大小的RW_IRAM2内存区域将用作存储初始化函数, 那么怎么才能将指定的函数放进这个区域呢?

  • 实现方法如下:
// 初始化函数的原型,函数原型可根据实际需求调整
typedef void (*init_function_list)(uint8_t taskID);

// 通过MODULE_INIT(func),func函数在编译时将会被链接到RAMCODE内存区,既我们为初始化函数预先分配的内存区域
#define _init __attribute__((used, section("RAMCODE")))
#define MODULE_INIT(func) init_function_list _fn_##func _init = func

将所有的初始化函数都写进特定内存区域后,我们只需知道这个区域的起止地址,就可以统一遍历调用所有的初始化函数, 从而实现对各个模块的初始化。

  • 模块的初始化有顺序要求怎么办? 有时一个模块的正常使用必须在某个模块初始化之后,比如一个模块需要打印Log,那么Log模块必须在它之前被初始化。 怎么解决了?其实很简单,统一调用初始化函数时,我们是根据内存地址顺序调用的,那么将Log模块的初始化函数放在其前面就可以了。

在Keil中可以这么做:

1.3 使用举例

Talk is cheap. Show me the code.

FanHongchuang/module_init​github.com

  • module1.c,module2.c,module3.c 为3个独立的模块,其初始化函数都为内部函数(使用static修饰),符合高内聚低耦合的软件设计思想
  • main.c中,do_init函数直接通过初始化函数的内存地址,对初始化函数逐个进行调用

简单示例代码如下:

  • module1.c
static void module1_init(uint8_t taskID)
{
    // write your code ...
}

MODULE_INIT(module1_init);
  • module2.c
static void module2_init(uint8_t taskID)
{
    // write your code ...
}

MODULE_INIT(module2_init);
  • module3.c
static void module3_init(uint8_t taskID)
{
    // write your code ...
}

MODULE_INIT(module3_init);
  • main.c
void do_init(void)
{
    uint8_t taskID = 0;
    init_function_list *call = (init_function_list *)&Image$$RW_IRAM2$$Base;
    init_function_list *end = (init_function_list *)&Image$$RW_IRAM2$$Limit;
    do
    {
        (*call)(taskID++);
        call++;
    }while(call < end);
}


int main()
{
    // init all module in the function 
    do_init();

    // write your code ...

    while(1)
    {
        // write your code ...
    }
}

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

类linux驱动模块框架module_init(init_fun)在STM32上的实现 的相关文章

  • 从 gitlab docker runner 启动声纳扫描仪

    我有一个 CI 工作流程 集成了 linting 作业和代码质量作业 我的 Linting 工作是一个 docker runner 从应用程序代码启动我的 eslint 脚本 然后我的代码质量工作应该启动声纳扫描仪泊坞窗实例 检查我的代码并
  • 使用 linux perf 工具测量应用程序的 FLOP

    我想使用 perf Linux 性能计数器子系统的新命令行接口命令 来测量某些应用程序执行的浮点和算术运算的数量 出于测试目的 我使用了我创建的一个简单的虚拟应用程序 请参见下文 因为我找不到任何为测量 FP 和整数运算而定义的 perf
  • 如何防止模块被导入两次?

    在编写python模块时 有没有办法防止它被客户端代码导入两次 就像 c c 头文件一样 ifndef XXX define XXX endif 非常感谢 Python 模块不会被多次导入 仅运行两次 import 不会重新加载模块 如果你
  • 如何使用sprof?

    请举例说明 从邮件中找到here http sources redhat com ml libc alpha 2003 07 msg00029 html and here http sourceware org ml binutils 20
  • 如何使用 tmuxinator 在 tmux 中拆分水平窗格内的两个垂直窗格

    目前我的 tmuxinator yml 文件中有这个 windows editor layout main horizontal panes vim server rails s 这给了我两个窗口 一个用于编辑器 另一个用于服务器 在编辑器
  • Snap-confine 具有提升的权限,并且不受限制,但应该受到限制。拒绝继续避免权限升级攻击

    我已经使用 snap 一段时间了 但最近升级后 当我尝试打开任何应用程序时 出现此错误 Snap confine has elevated permissions and is not confined but should be Refu
  • 即使 makefile 和源代码存在,为什么“Build Project”在 Eclipse Helios CDT 中显示为灰色?

    我无法构建我的项目 我在 Eclipse Helios 中创建了一个新的 CDT 项目 并告诉它使用现有的源代码和 makefile 这两者都正确显示在 Package 和 Project 视图中 然而 项目 菜单中的 构建全部 和 构建项
  • bash双括号问题

    我对 bash 脚本非常陌生 在使用双括号时遇到了问题 我似乎无法让它们在 Ubuntu Server 11 10 中工作 我的下面的脚本位于 if test sh 中 bin bash if 14 14 then echo FOO fi
  • 从 Linux 命令行发送 SNMP 陷阱消息

    Folks 我需要从 Linux 命令行使用此命令 snmptrap 将自定义消息发送到陷阱侦听器 我需要根据用户设置在 v1 和 v2c 中发送相同的消息 这是我发现的 For v1 snmptrap v 1 c Tas hostname
  • 跟踪 pthread 调度

    我想做的是创建某种图表 详细说明 Linux 中 两个 线程的执行情况 我不需要查看线程的作用 只需查看它们何时被安排以及持续多长时间 基本上是一条时间线 在过去的几个小时里 我一直在互联网上搜索跟踪 pthread 调度的方法 不幸的是
  • 如何删除树莓派的相机预览

    我在我的 raspberryPi 上安装了 SimpleCv 并安装了用于使用相机板的驱动程序 uv4l 驱动程序 现在我想使用它 当我在 simpleCV shell Camera 0 getImage save foo jpg 上键入时
  • 为什么使用Python的os模块方法而不是直接执行shell命令?

    我试图了解使用Python的库函数执行特定于操作系统的任务 例如创建文件 目录 更改文件属性等 背后的动机是什么 而不是仅仅通过执行这些命令os system or subprocess call 例如 我为什么要使用os chmod而不是
  • 无法为 Python 3.4 创建工作虚拟环境

    I 安装Python 3 4 2 https docs python org 3 using unix html building python和我的 Linux Mint 17 1 中的 Virtualenv 12 0 5 然后我尝试创建
  • 测试linux下磁盘空间不足

    我有一个程序 当写入某个文件的磁盘空间不足时 该程序可能会死掉 我不确定是否是这种情况 我想运行它并查看 但我的测试服务器不会很快耗尽空间 有什么办法可以嘲笑这种行为吗 看起来没有任何方法可以在 Ubuntu 中设置文件夹 文件大小限制 并
  • 变量作为 bash 数组索引?

    bin bash set x array counter 0 array value 1 array 0 0 0 for number in array do array array counter array value array co
  • 退出 bash 脚本但保持进程运行

    我正在运行服务器 需要使用参数执行以下命令 这些脚本目前工作得很好 但问题是当我运行脚本时我无法返回到控制台 它在控制台中保持运行 如果我强行停止它 那么该过程也会停止 我想继续运行该进程并返回到控制台 bin sh php home st
  • 如何在 Linux 中使用单行命令获取 Java 版本

    我想通过单个命令获取 Linux 中的 Java 版本 我是 awk 的新手 所以我正在尝试类似的事情 java version awk print 3 但这不会返回版本 我将如何获取1 6 0 21从下面的Java版本输出 java ve
  • gdb 错误 - 文件不是可执行格式:无法识别文件格式

    我正在尝试使用 gdb 调试某个名为 xdf 的程序 但是当我运行 gdb xdf 时 出现以下错误 home nealtitusthomas X ray astronomy heasoft 6 24 x86 64 pc linux gnu
  • 使用脚本自动输入 SSH 密码

    我需要创建一个自动向 OpenSSH 输入密码的脚本ssh client 假设我需要通过 SSH 进入myname somehost用密码a1234b 我已经尝试过 bin myssh sh ssh myname somehost a123
  • sqlite 插入需要很长时间

    我正在将不到 200 000 行插入到 sqlite 数据库表中 我只是在终端中通过 sqlite3 使用一个非常简单的 sql 文件 我打赌它已经运行了至少 30 分钟 这是正常现象还是我应该关闭该过程并尝试不同的方法 sqlite中的插

随机推荐

  • 2011河北金融学院CSDN高校俱乐部动员大会

    2011年11月24日下午二点 xff0c 我校CSDN高校俱乐部动员大会在教学楼B123举行 该次大会主要针对大一学生召开 xff0c 号召大家了解并加入CSDN高校俱乐部 俱乐部指导老师王洪涛老师 计算机协会指导老师杜光辉老师 以及优秀
  • “激情与梦想 我的程序员之路”—2012高校巡讲

    2012年3月29日下午2点半 xff0c CSDN高校俱乐部项目主管潘永强老师在我校进行了一场以 激情与梦想 xff0c 我的程序员之路 为主题的演讲 信息管理与工程系团总支书记陈春燕 指导老师王洪涛以及杜光辉 刘冲等7位老师出席了该次讲
  • TX2下编译qt程序步骤

    1 将 aarch64 qt 5 15 1 tar bz2 解压到 opt 2 在 bashrc 添加qt的库和路进 art 64 art desktop opt cat bashrc tail n 2 export LD LIBRARY
  • 电子政务三网架构

    国家电子政务网络架构由政务内网 政务专网 政务外网组成 政务内网是涉密网络 xff0c 在上面传输涉密公文 xff0c 属高度机密的网络 xff0c 覆盖范围尽可能小 xff0c 它与国际互联网物理隔离 政务专网是党政机关非涉密办公网 xf
  • SDN介绍(什么是SDN)

    SDN介绍 一 xff0e 什么是SDN 二 xff0e SDN解决什么问题 xff1f 三 xff0e 传统网络概念和结构体系传统网络数据控制与转发 xff1a 传统网络架构 xff1a 四 xff0e SDN概述SDN xff08 So
  • 我的2011--快乐最重要

    呵呵 xff0c 听着郭德纲和于谦老师的相声 xff0c 开始写这篇文章 xff0c 刚毕业不到六个月 xff0c 就换了一份工作 xff0c 很多事情都在意料之外 xff0c 很多事情又在意料之中 xff0c 总之 xff0c 以后回忆到
  • 朱金灿:韧性、悟性、具备快速学习能力是我喜欢的特质

    英雄会是CSDN旗下针对国内IT技术领域专家展示和交流的平台 通过线下线上的互动形式 xff0c 为CSDN社区专家提供更多学习 合作 宣传的机会 英雄会后续将在北上广深等国内一二线城市建立分会 xff0c 各个分会后期将组织技术交流活动
  • 本地vnc(TigerVNC)远程linux server,提示拒绝连接

    可能原因 amp 分析 xff1a 可确认下初始的系统环境变量是否被改动 xff0c 如新安装的anaconda自动添加到环境变量 xff0c 且放置在系统的原有环境变量的前面 xff0c 可尝试将后加的环境变量编辑到后面 xff0c 再重
  • 高质量嵌入式Linux C编程第一次博客作业

    1 xff1a linux 与 Unix的关系 xff1f 某些PC机的Unix和Linux在实现方面相类似 几乎所有的商业Unix版本都基本支持同样的软件 程序设计环境和网络特性 然而 xff0c Linux和Unix的商业版本依然存在许
  • java enum(枚举)使用详解 + 总结

    enum 的全称为 enumeration xff0c 是 JDK 1 5 中引入的新特性 xff0c 存放在 java lang 包中 下面是我在使用 enum 过程中的一些经验和总结 xff0c 主要包括如下内容 xff1a 1 原始的
  • RBAC用户、角色、权限、组设计方案

    设计一个灵活 通用 方便的权限管理系统 在这个系统中 xff0c 我们需要对系统的所有资源进行权限控制 xff0c 那么系统中的资源包括哪些呢 xff1f 我们可以把这些资源简单概括为静态资源 xff08 功能操作 数据列 xff09 和动
  • ssh 怎样以root用户登录

    sudo vim etc ssh sshd config 找到并用 注释掉这行 xff1a PermitRootLogin prohibit password 新建一行 添加 xff1a PermitRootLogin yes 重启服务 s
  • python 函数内部修改外部变量

    如果内部修改外部变量需要nonlocal xff0c global def f1 print 34 in f1 34 num 61 111 def f2 nonlocal num num 61 222 print num f2 print
  • python 列表生成式将两个列表组合

    l1 61 1 2 3 4 5 l2 61 10 20 30 40 50 l3 61 x y for x in l1 for y in l2 if y x 61 61 10 l4 61 x y for x in l1 for y in l2
  • python monkey脚本

    import wx import wx xrc import os import threading import thread import logging import re import time import csv import
  • tiny210 ubuntu下sd卡分区

    1 ubuntu实现SD Flasher exe原理 友善官方给出的烧录uboot的工具是SD Flasher exe xff0c 这个工具只能在windows下使用 由于本人电脑无法打开这个工具 xff0c 所以在windows下无法制作
  • MonkeyScript API 文档

    一 前言 本文档记录了和 MonkeyScript 相关的 API 文档 xff0c 由承香墨影整理 所有 API 描述均来自 MonkeySourceScript java 也可以自行查看源码 xff0c 在线阅读地址 xff1a htt
  • mysql教程01

    常用数据类型如下 xff1a 整数 xff1a int xff0c bit小数 xff1a decimal字符串 xff1a varchar char日期时间 date time datetime枚举类型 enum decimal表示浮点数
  • mysql02

    查看版本 xff1a select version 查看所有数据库 xff1a show databases xff1b 创建数据数据库 xff1a create database test01 charset 61 utf8 使用数据库
  • 类linux驱动模块框架module_init(init_fun)在STM32上的实现

    原文 xff1a https zhuanlan zhihu com p 81309285 设计思想 利用编译器的特性 xff0c 在程序编译时将各模块初始化函数顺序存放到内存的指定地址 xff0c 然后在程序运行时main函数从这块内存区域