正点原子嵌入式linux驱动开发——LED驱动开发

news2024/10/7 17:32:35

在上一篇笔记中,详细的讲解了字符设备驱动开发步骤,并且用一个虚拟的chrdevbase设备为例完成了第一个字符设备驱动的开发。本章就开始编写第一个真正的Linux字符设备驱动。在正点原子STM32MP157开发板上有一个LED灯,本章就学习一下如何编写Linux下的LED灯驱动

Linux下LED灯驱动原理

Linux下的任何外设驱动,最终都是要配置相应的硬件寄存器。所以LED灯驱动最终也是对STM32MP157 的IO口进行配置,与裸机实验不同的是,在Linux下编写驱动要符合Linux的驱动框架。开发板上的LED0连接到STM32MP157的PI0这个引脚上,因此重点就是编写Linux下STM32MP157引脚控制驱动

地址映射

先简单了解一下MMU,MMU全称叫做Memory
Manage Unit,也就是内存管理单元
。在老版本的Linux中要求处理器必须有MMU,但是现在Linux内核已经支持无MMU的处理器了。MMU 主要完成的功能如下:

  1. 完成虚拟空间到物理空间的映射。
  2. 内存保护,设置存储器的访问权限,设置虚拟存储空间的缓冲特性。

虚拟空间到物理空间的映射,也叫做地址映射。首先了解两个地址概念:虚拟地址(VA,Virtual Address)、物理地址(PA,Physcical Address)。对于32位的处理器来说,虚拟地址范围2^32=4GB,开发板上有1GB的DDR3,这1GB的内存就是物理内存,经过MMU可以将其映射到整个4GB的虚拟空间,如下图所示:
内存映射
Linux内核启动的时候会初始化MMU,设置好内存映射,设置好以后CPU访问的都是虚拟地址。比如STM32MP157的PI0引脚的端口模式寄存器GPIOI_MODER物理地址为0x5000A000。开启了 MMU,并且设置了内存映射,因此不能直接向0x5000A000这个地址写入数据,必须得到0x5000A000这个物理地址在Linux系统里面对应的虚拟地址,这里就涉及到了物理内存和虚拟内存之间的转换,需要用到两个函数:ioremap和iounmap

ioremap函数

ioremap函数用于获取指定物理地址空间对应的虚拟地址空间,定义在arch/arm/include/asm/io.h文 件中。函数定义如下:

void __iomem *ioremap(resource_size_t res_cookie, size_t size);

一共有两个参数,而函数内部实际是调用了arch_ioremap_caller,并且有一个返回值:

  • res_cookie:要映射的物理起始地址。
  • size:映射的内存空间大小。
  • 返回值:__iomem类型指针,指向映射后虚拟空间首地址。

iounmap函数

卸载驱动的时候需要使用iounmap函数释放掉 ioremap函数所做的映射, iounmap函数原型如下:

void iounmap (volatile void __iomem *addr);

只有一个参数,就是要取消映射的虚拟地址空间首地址

I/O内存访问函数

I/O是输入/输出。这里涉及到两个概念:I/O端口和I/O内存。当外部寄存器或内存映射到IO空间时,称为I/O端口。当外部寄存器或内存映射到内存空间时,称为I/O内存。对于ARM体系下只有I/O内存 (可以直接理解为内存)。使用ioremap函数将寄存器的物理地址映射到虚拟地址以后,就可以直接通过指针访问这些地址,但是Linux内核不建议
这么做,而是推荐使用一组操作函数来对映射后的内存进行读写操作

读操作函数

readb、readw和readl这三个函数分别对应8bit、16bit和32bit读操作,参数addr就是要读取写内存地址,返回值就是读取到的数据。

u8 readb(const volatile void __iomem *addr) 
u16 readw(const volatile void __iomem *addr) 
u32 readl(const volatile void __iomem *addr)

写操作函数

writeb、writew和writel这三个函数分别对应8bit、16bit和32bit写操作,参数value是要写入的数值,addr是要写入的地址。

void writeb(u8 value, volatile void __iomem *addr) 
void writew(u16 value, volatile void __iomem *addr) 
void writel(u32 value, volatile void __iomem *addr)

硬件原理图分析

正点原子的STM32MP157开发班上有一个LED0,如下图所示:
LED原理图
可以看出, LED0接到了PI0上,当PI0输出低电平LED0就会导通点亮,当PI0输出高电平LED0不会导通,因此LED0也就不会点亮。

实验程序编写

LED灯驱动

首先定义一些方便操作的宏,比如设备号、设备名字以及LED开/官状态宏;之后需要定义寄存器宏定义;定义映射后的寄存器地址指针,指针是__iomem*类型;

之后定义led_switch函数,通过readl和writel函数来操作LED的状态;之后定义led_unmap函数,其中就是iounmap来取消各个寄存器的映射;

设备的read和open以及release都直接return 0就可以了,没什么操作;write函数就需要把数据拷贝过来之后,接收到的消息来判断具体的操作,在其中调用led_switch改变LED状态;然后file_operations把这几个设备操作函数封装一下;

最后是init函数,在这其中需要通过配置寄存器的方式来配置LED:首先通过ioremap读取物理寄存器映射后虚拟地址,然后就是寄存器的方法配置,最后需要register_chrdev注册led这个字符设备;注册失败需要回收,通过led_unmap来搞定;

最后还有exit函数,就是直接led_unmap取消映射,然后注销unregister_chrdev;

最后module_init和module_exit以及添加license和author就可以了,最后在表示这个驱动是intree模块驱动。

编写测试APP

就是最基础的打开、关闭以及写操作。

先判断argc是否为3,然后把设备名字argv[1]传入自己的char* filename,之后int fd通过open接住打开的设备,fd<0说明没有打开就直接return -1;之后把读取的数据传入databuf[0],这也是自己定义的unsigned char数组,大小为1,通过atoi(argv[2])传进去;最后调用write写进int retvalue;关闭文件同样调用close传给retvalue。

运行测试

编译驱动模块和测试APP

驱动程序就直接写一个Makefile,把obj-m设置为led.o就好了,然后make就能得到“led.ko”驱动模块文件。

测试APP则通过如下命令编译生成:

arm-none-linux-gnueabihf-gcc ledApp.c -o ledApp

运行测试

把编译生成的两个文件拷贝到rootfs/lib/modules/5.4.31中,然后重启开发板,进入lib/modules/5.4.31然后加载驱动:

depmod //第一次加载驱动的时候需要运行此命令
modprobe led //加载驱动

成功后就创建“/dev/led”设备节点:

mknod /dev/led.c 200 0

然后通过ledAPP测试驱动:

./ledApp /dev/led 1 //打开 LED灯
./ledApp /dev/led 0 //关闭 LED灯

如果成功,之后可卸载驱动:

rmmod led.ko

总结

本篇主要就是通过Linux的地址映射,把物理寄存器地址映射到虚拟内存中,然后通过字符设备的操作方式,操作LED的亮灭。这里面主要还要学习一下寄存器配置的方式,翻翻手册记一下就好了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1115862.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

探讨Unity新的收费模式:对开发者与游戏行业的影响、负面因素的解析及面对挑战的建议

本人详解 作者&#xff1a;王文峰&#xff0c;参加过 CSDN 2020年度博客之星&#xff0c;《Java王大师王天师》采购供应链共享平台人员,财务规则对账人员&#xff0c;物流门禁计量系统对接人员&#xff0c;ERP事业部人员 Unity是一款备受开发者欢迎的跨平台游戏引擎&#xff0c…

基于SSM的台球厅管理系统

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;Vue 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是 目录…

【再识C进阶5(上)】详细介绍C语言文件操作——文件是用于存储数据

前言 &#x1f493;作者简介&#xff1a; 加油&#xff0c;旭杏&#xff0c;目前大二&#xff0c;正在学习C&#xff0c;数据结构等&#x1f440; &#x1f493;作者主页&#xff1a;加油&#xff0c;旭杏的主页&#x1f440; ⏩本文收录在&#xff1a;再识C进阶的专栏&#x1…

成绩查询页面和自助查询方式

科技发展让我们有更多的方式来发布和查询学生成绩。今天&#xff0c;我想向大家介绍什么是成绩查询页面&#xff0c;并分享如何通过各种代码和Excel来实现让学生自助查询成绩。 成绩查询页面是一个专门用来发布和查询学生成绩的网络页面。这个页面具有发布、查询、统计成绩等功…

Vue 3使用 Iconify 作为图标库与图标离线加载的方法、 Icones 开源在线图标浏览库的使用

之前一直naive-ui搭配使用的是xicons&#xff0c;后来发现Iconify支持的图标合集更多&#xff0c;因此转而使用Iconify。 与FontAwesome不同的是&#xff0c;Iconify配合Icones相当于是一个合集&#xff0c;Iconify提供了快捷引入图标的方式&#xff0c;而Icones是一个大的图标…

二、vue基础语法

一、模板语法 1、文本渲染 使用双花括号语法插入文本 <template><div><h3>msg: {{ message }}</h3></div> </template><script> export default {data() {return {message: "输出信息"}} } </script><style s…

SAP 路径及运输功能

一、 概述 SAP的发运功能包括两部份内容&#xff0c;一是运输路径&#xff1b;二是运输功能。运输路径是运输功能的基础。 SAP 中的运输功能是后勤执行的一部分&#xff0c;用于自动计算交货成本&#xff1b;也就是说&#xff0c;SAP 可以让系统自动对销售发货的商品计算运费&…

web APIs——第一天(上)

变量声明的时候建议 const优先&#xff0c;尽量使用const 原因&#xff1a; const语义化更好很多变量我们声明的时候就知道他不会被更改了&#xff0c;那为什么不用const呢&#xff1f;实际开发中也是&#xff0c;比如react框架&#xff0c;基本const如果你有纠结的时候&…

记一次Clickhouse 复制表同步延迟排查

现象 数据从集群中一个节点写入之后&#xff0c;其他两个节点无法及时查询到数据&#xff0c;等了几分钟。因为我们ck集群是读写分离架构&#xff0c;也就是一个节点写数据&#xff0c;其他节点供读取。 排查思路 从业务得知&#xff0c;数据更新时间点为&#xff1a;11:30。…

信驰达RF-BM-2340x系列BLE蓝牙模块正式登录TI官网

信驰达作为TI中国低功耗连接技术第三方IDH&#xff0c;RF-BM-2340x系列低功耗蓝牙模块正式通过TI认证并在全球进行推广。 图 1 TI官网信驰达RF-BM-2340x系列BLE蓝牙模块 一直以来&#xff0c;信驰达重视在无线射频通信领域基础技术上的投入&#xff0c;奠定了公司在低功耗蓝牙…

Redis数据结构之SDS

前言 字符串在 Redis 中的应用场景十分广泛&#xff0c;所有的键都是字符串类型&#xff0c;值也可能是字符串类型。 比如电商系统用 Redis 缓存商品信息&#xff0c;可以把商品 ID 作为键&#xff0c;商品信息序列化为 JSON 后作为值写入&#xff1a; SET item:1001 {"…

使用python自动化操作如何使用subprocess,mac如何查看软件安装路径

使用下面这种方法实现需要配置全局的环境变量&#xff0c;很麻烦 import subprocessdef open_wps_new_doc():try:# 打开WPS应用程序subprocess.Popen(wps)# 等待一段时间&#xff0c;确保WPS完全打开time.sleep(2)# 发送快捷键组合&#xff0c;新建一个Word文档pyautogui.hotk…

linux进阶(3)

课程链接 CH10-2-Apache的其他用途_哔哩哔哩_bilibili scp不够好,因为他需要知道服务器上具体的一个目录

MySQL -- 数据库基础

MySQL – 数据库基础 文章目录 MySQL -- 数据库基础一、基础知识1.什么是数据库2.连接服务器3.服务器、数据库、表的关系3.MySQL架构4.SQL分类5.存储引擎 一、基础知识 1.什么是数据库 文件存储数据有以下几个缺点&#xff1a; 文件的安全性问题文件不利于数据查询和管理文件…

【ARM AMBA5 CHI 入门 12.2 -- CHI 协议层详细介绍 】

文章目录 1 协议层1.1 协议层传输通道1.2 域段1.2.1 ID域段1.2.2 其他关键域段1.2.2.1 Address1.2.2.2 Secure bit1.2.2.3 Memory Attributes1.2.2.4 Transaction attribute combinations 1.4.1 Transaction 路由1.4.2 SAM 介绍1.4.3 Node ID 1.5 节点间数据怎么传输的呢&#…

jdk11的HttpClient

我们都知道在jdk11之前都在用okhttp或者org.apache.httpcomponents 其实早在jdk9的时候这个方案就在孵化中 上面的截图来自openjdk的官网&#xff0c;注&#xff1a;openjdk是个开源项目&#xff0c;不存在侵权现象 这是openjdk的官网&#xff1a;JEP 110: HTTP/2 Client (In…

vue 插槽 作用域插槽

vue 插槽 作用域插槽 **创建 工程&#xff1a; H:\java_work\java_springboot\vue_study ctrl按住不放 右键 悬着 powershell H:\java_work\java_springboot\js_study\Vue2_3入门到实战-配套资料\01-随堂代码素材\day05\准备代码\10-插槽-作用域插槽 vue --version vue crea…

安科瑞关于红外测温技术在变电站运维中的应用

安科瑞 崔丽洁 红外测温技术 特点 工作中的输变电机械设备由于电流热效应产生了红外线照射效应&#xff0c;从而在电气设备表层形成了相应的高温场&#xff0c;而红外线测温高温技术则透过吸取这些自高温场发出的红外线照射热能&#xff0c;并透过电流效应以及放大器和A/D转换器…

Linux - 还不懂 gdb 调试器?(调试软件)

前言 当前&#xff0c;我们可以使用 make/makefile 来程序化执行代码文件&#xff1b;可以使用 gcc/g 等编译器来编译代码&#xff1b;可以使用 vim 编辑器来编写代码&#xff1b;其实在 Linux 当中还有一个工具&#xff0c;可以实现调试工作&#xff0c;这个工具就是 -- gdb。…

RK3568驱动指南|第七期-设备树-第57章 实例分析:中断

瑞芯微RK3568芯片是一款定位中高端的通用型SOC&#xff0c;采用22nm制程工艺&#xff0c;搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码&#xff0c;支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU&#xff0c;可用于轻量级人工…