嵌入式Linux应用开发-基础知识-第七章 具体单板的 LED驱动程序

news2024/11/25 1:55:36

嵌入式Linux应用开发-基础知识-第七章 具体单板的 LED驱动程序

  • 第七章 具体单板的 LED 驱动程序
    • 7.1 怎么写 LED 驱动程序?
    • 7.2 AM335X的 LED驱动程序
      • 7.2.1 原理图 XXXXXX_AM335X开发板结构为:
      • 7.2.2 所涉及的寄存器操作
      • 7.2.3 写程序
      • 7.2.4 配置内核去掉原有 LED驱动
      • 7.2.5 课后作业

第七章 具体单板的 LED 驱动程序

在这里插入图片描述

我们选用的内核都是 4.x 版本,操作都是类似的:

rk3399 linux 4.4.154 
rk3288 linux 4.4.154 
imx6ul linux 4.9.88 
am3358 linux 4.9.168 

录制视频时,我的 source insight 里总是使用某个版本的内核。这没有关系,驱动程序中调用的内核
函数,在这些 4.x 版本的内核里都是一样的。

7.1 怎么写 LED 驱动程序?

详细步骤如下:
① 看原理图确定引脚,确定引脚输出什么电平才能点亮/熄灭 LED
② 看主芯片手册,确定寄存器操作方法:哪些寄存器?哪些位?地址是?
③ 编写驱动:先写框架,再写硬件操作的代码

注意:在芯片手册中确定的寄存器地址被称为物理地址,在 Linux 内核中无法直接使用。
需要使用内核提供的 ioremap 把物理地址映射为虚拟地址,使用虚拟地址。

ioremap 函数的使用

① 函数原型:
在这里插入图片描述
使用时,要包含头文件:

#include <asm/io.h>

② 它的作用: 把物理地址 phys_addr开始的一段空间(大小为 size),映射为虚拟地址;返回值是该段虚拟地址的首地址。

virt_addr  = ioremap(phys_addr, size); 

实际上,它是按页(4096字节)进行映射的,是整页整页地映射的。 假设 phys_addr = 0x10002,size=4,ioremap的内部实现是: a. phys_addr按页取整,得到地址 0x10000 b. size按页取整,得到 4096 c. 把起始地址 0x10000,大小为 4096的这一块物理地址空间,映射到虚拟地址空间, 假设得到的虚拟空间起始地址为 0xf0010000 d. 那么 phys_addr = 0x10002对应的 virt_addr = 0xf0010002

③ 不再使用该段虚拟地址时,要 iounmap(virt_addr):

void iounmap(volatile void __iomem *cookie)

volatile的使用
① 编译器很聪明,会帮我们做些优化,比如:

int   a; 
a = 0;   // 这句话可以优化掉,不影响 a的结果 
a = 1; 

② 有时候编译器会自作聪明,比如:

int *p = ioremap(xxxx, 4);  // GPIO寄存器的地址 
*p = 0;   // 点灯,但是这句话被优化掉了 
*p = 1;   // 灭灯 

③ 对于上面的情况,为了避免编译器自动优化,需要加上 volatile,告诉它“这是容易出错的,别乱优化”:

volatile  int *p = ioremap(xxxx, 4);  // GPIO寄存器的地址 
*p = 0;   // 点灯,这句话不会被优化掉 
*p = 1;   // 灭灯 

7.2 AM335X的 LED驱动程序

7.2.1 原理图 XXXXXX_AM335X开发板结构为:

底板+核心板,其中一个 LED原理图如下:
在这里插入图片描述
它使用 GPIO1_16这个引脚,当它输出低电平时,LED被点亮;当它输出高电平时,LED被熄灭。

7.2.2 所涉及的寄存器操作

a. 使能 GPIO1
在这里插入图片描述

/* set PRCM to enalbe GPIO1   
* set CM_PER_GPIO1_CLKCTRL (0x44E00000 + 0xAC)  
* * val: (1<<18) | 0x2  
* */ 

b. 设置 GPIO1_16的功能
让它工作于 GPIO模式 根据原理图可以找到 GPIO1_16这个引脚接到 AM3358的 R13引脚,根据下图知道 pin name为 GPMC_A0,并且知道要设置这个引脚为 Mode 7。
在这里插入图片描述
在芯片手册中搜“conf_gpmc_a0”,可得:
在这里插入图片描述

/* set Control Module to set GPIO1_16 (R13) used as GPIO   
* conf_gpmc_a0 as mode 7  
* * addr : 0x44E10000 + 0x840  
* * val  : 7  
* */ 

c. 设置 GPIO1_16的方向,让它作为输出引脚
在这里插入图片描述

/* set GPIO1's registers , to set GPIO1_16'S dir (output)   
* GPIO_OE   
* * addr : 0x4804C000 + 0x134  
* * clear bit 16  
* */ 

d. 设置 GPIO1_16的数据,让它输出高电平 AM335X芯片支持 set-and-clear protocol,设置 GPIO_SETDATAOUT的 bit 16为 1即可让引脚输出 1:
在这里插入图片描述

/* set GPIO1_16's registers , to output 1   
* GPIO_SETDATAOUT  
* addr : 0x4804C000 + 0x194  
*/ 

e. 清除 GPIO1_16的数据,让它输出低电平 AM335X芯片支持 set-and-clear protocol,设置 GPIO_CLEARDATAOUT的 bit 16为 1即可让引脚输出0:
在这里插入图片描述

/* set GPIO1_16's registers , to output 0   
* GPIO_CLEARDATAOUT  
* addr : 0x4804C000 + 0x190  
*/
 

7.2.3 写程序

使用 GIT下载所有源码后,本节源码位于如下目录:

01_all_series_quickstart\ 
05_嵌入式 Linux驱动开发基础知识\source\02_led_drv\       
02_led_drv_for_boards\am335x_src_bin 

硬件相关的文件是 board_am335x.c,其他文件跟 LED框架驱动程序完全一样。 它首先构造了一个 led_operations结构体,用来表示 LED的硬件操作:

100 static struct led_operations board_demo_led_opr = { 
101     .num  = 1, 
102     .init = board_demo_led_init, 
103     .ctl  = board_demo_led_ctl, 
104 }; 

led_operations结构体中有 init函数指针,它指向 board_demo_led_init函数,在里面将会初始化LED引脚:使能、设置为 GPIO模式、设置为输出引脚。 值得关注的是第 33~37行,对于寄存器要先使用 ioremap得到它的虚拟地址,以后使用虚拟地址访问寄存器。

19 #include "led_opr.h" 
20 
21 static volatile unsigned int *CM_PER_GPIO1_CLKCTRL; 
22 static volatile unsigned int *conf_gpmc_a0; 
23 static volatile unsigned int *GPIO1_OE; 
24 static volatile unsigned int *GPIO1_CLEARDATAOUT; 
25 static volatile unsigned int *GPIO1_SETDATAOUT; 
26 
27 static int board_demo_led_init (int which) /* 初始化 LED, which-哪个 LED */ 
28 { 
29     if (which == 0) 
30     { 
31         if (!CM_PER_GPIO1_CLKCTRL) 
32         { 
33             CM_PER_GPIO1_CLKCTRL = ioremap(0x44E00000 + 0xAC, 4); 
34             conf_gpmc_a0 = ioremap(0x44E10000 + 0x840, 4); 
35             GPIO1_OE = ioremap(0x4804C000 + 0x134, 4); 
36             GPIO1_CLEARDATAOUT = ioremap(0x4804C000 + 0x190, 4); 
37             GPIO1_SETDATAOUT = ioremap(0x4804C000 + 0x194, 4); 
38         } 
39 
40         //printk("%s %s line %d, led %d\n", __FILE__, __FUNCTION__, __LINE__, which); 
41         /* a. 使能 GPIO1 
42          * set PRCM to enalbe GPIO1 
43          * set CM_PER_GPIO1_CLKCTRL (0x44E00000 + 0xAC) 
44          * val: (1<<18) | 0x2 
45          */ 
46         *CM_PER_GPIO1_CLKCTRL = (1<<18) | 0x2; 
47 
48         /* b. 设置 GPIO1_16的功能,让它工作于 GPIO模式 
49          * set Control Module to set GPIO1_16 (R13) used as GPIO 
50          * conf_gpmc_ad0 as mode 7 
51          * addr : 0x44E10000 + 0x800 
52          * val  : 7 
53          */ 
54         *conf_gpmc_a0 = 7; 
55 
56         /* c. 设置 GPIO1_16的方向,让它作为输出引脚 
57          * set GPIO1's registers , to set GPIO1_16'S dir (output) 
58          * GPIO_OE 
59          * addr : 0x4804C000 + 0x134 
60          * clear bit 16 61          */ 
62 
63         *GPIO1_OE &= ~(1<<16); 
64     } 
65 
66     return 0; 
67 } 
68 

led_operations结构体中有 ctl函数指针,它指向 board_demo_led_ctl函数,在里面将会根据参数设置 LED引脚的输出电平:

69 static int board_demo_led_ctl (int which, char status) /* 控制 LED, which-哪个 LED, status:1-亮,0-灭 */ 
70 { 
71     //printk("%s %s line %d, led %d, %s\n", __FILE__, __FUNCTION__, __LINE__, which, status ? "on" : "off"); 
72 
73     if (which == 0) 
74     { 
75         if (status) /* on: output 0 */ 
76         { 
77             /* e. 清除 GPIO1_16的数据,让它输出低电平 
78              * AM335X芯片支持 set-and-clear protocol,设置 GPIO_CLEARDATAOUT的 bit 16为 1即可让引脚输出 0: 
79              * set GPIO1_16's registers , to output 0 
80              * GPIO_CLEARDATAOUT 
81              * addr : 0x4804C000 + 0x190 
82              */ 
83             *GPIO1_CLEARDATAOUT = (1<<16); 
84         } 
85         else 
86         { 
87             /* d. 设置 GPIO1_16的数据,让它输出高电平 
88              * AM335X芯片支持 set-and-clear protocol,设置 GPIO_SETDATAOUT的 bit 16为1即可让引脚输出 1: 
89              * set GPIO1_16's registers , to output 1 
90              * GPIO_SETDATAOUT 
91              * addr : 0x4804C000 + 0x194 
92              */ 
93             *GPIO1_SETDATAOUT = (1<<16); 
94         } 
95     } 
96 
97     return 0; 
98 } 
99 

下面的 get_board_led_opr函数供上层调用,给上层提供 led_operations结构体:

106 struct led_operations *get_board_led_opr(void) 
107 { 
108     return &board_demo_led_opr; 
109 } 
110 

7.2.4 配置内核去掉原有 LED驱动

不需要重新配置内核,只需要在开发板上执行以下 3条命令关闭内核对 LED的使用即可:

# echo none > /sys/class/leds/am335x:green:cpu0/trigger 
# echo none > /sys/class/leds/am335x:green:mmc0/trigger 
# echo none > /sys/class/leds/am335x:green:nand/trigger 

然后就可以去安装驱动程序,执行测试程序了,操作过程跟 LED框架驱动程序的测试是一样的。

7.2.5 课后作业

a. 在 board_am335x.c里有 ioremap,什么时候执行 iounmap?请完善程序
b. 视频里我们只实现了点一个 LED,请修改代码实现操作 4个 LED

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

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

相关文章

PyTorch meshgrid 生成网格坐标

torch.meshgrid(*tensors, indexingNone) 使用输入的 1-D 张量创建网格坐标 示例 indexing‘xy’ import torcha torch.arange(3) b torch.arange(3, 6)x, y torch.meshgrid(a, b, indexingxy) print(x , x, sep\n) print(y , y, sep\n)输出: x tensor([[0, 1, 2],[0, …

麒麟信安组织开展国产操作系统技术赋能专题培训

近日&#xff0c;为学习国产操作系统基本概念、使用与运维知识&#xff0c;应对用户单位内部信息系统国产化需求&#xff0c;来自国营洛阳丹城无线电厂的运维工程师们走进麒麟信安&#xff0c;进行了为期一周的操作系统课程学习。 针对客户此次培训需求&#xff0c;结合学员实…

uni-app:canvas-图形实现1

效果 代码 <template><view><!-- 创建了一个宽度为300像素&#xff0c;高度为200像素的canvas元素。canvas-id属性被设置为"firstCanvas"&#xff0c;可以用来在JavaScript中获取该canvas元素的上下文对象。 --><canvas style"width:200p…

nodejs+vue电影网站elementui

第3章 系统分析 5 3.1 需求分析 5 3.2 系统可行性分析 5 3.2.1技术可行性&#xff1a;技术背景 5 3.2.2经济可行性 6 3.2.3操作可行性&#xff1a; 6 3.3 项目设计目标与原则 6 3.4系统流程分析 7 3.4.1操作流程 7 3.4.2添加信息流程 8 3.4.3删除信息流程 9 第4章 系统设计 11 …

助力古彝文保护,AI文字识别技术推动文化传承

文章目录 一、写在前面古彝文为何物&#xff1f;古彝文的保护背景 二、古彝文识别有何难点&#xff1f;如何解决&#xff1f;三、合合信息的强劲技术四、古文识别的重要意义 一、写在前面 古彝文为何物&#xff1f; 彝文指的是云南、贵州、四川等地的彝族人使用的文字&#x…

【Java 进阶篇】MySQL外键约束详解

在数据库设计和管理中&#xff0c;外键约束是一项重要的功能&#xff0c;它用于维护表与表之间的关联关系&#xff0c;保证数据的完整性和一致性。本文将详细介绍MySQL外键约束的概念、用法以及一些最佳实践&#xff0c;以帮助您更好地理解和应用外键约束。 1. 什么是外键约束…

使用领域引导图卷积神经网络GCNN增强基于脑电图EEG的神经疾病诊断完整代码

一种基于图卷积神经网络&#xff08;GCNN&#xff09;的新方法&#xff0c;用于改进使用头皮脑电图&#xff08;EEG&#xff09;进行神经系统疾病诊断。尽管脑电图是神经系统疾病诊断中主要使用的检测方法之一&#xff0c;但基于EEG的专家视觉诊断的敏感性仍然只有约50&#xf…

ubuntu18.04 OpenGL开发(显示YUV)

源码参考&#xff1a;https://download.csdn.net/download/weixin_55163060/88382816 安装opengl库 sudo apt install libglu1-mesa-dev freeglut3-dev mesa-common-dev 安装opengl工具包 sudo apt install mesa-utils 检查opengl版本信息&#xff08;桌面终端执行&#xff09…

JVM机制理解与调优方案

作者&#xff1a;逍遥Sean 简介&#xff1a;一个主修Java的Web网站\游戏服务器后端开发者 主页&#xff1a;https://blog.csdn.net/Ureliable 觉得博主文章不错的话&#xff0c;可以三连支持一下~ 如有需要我的支持&#xff0c;请私信或评论留言&#xff01; 前言 很多Java开发…

更直观地学习 Git 命令

theme: condensed-night-purple 前言 本文参考于 Learn Git Branching 这个有趣的 Git 学习网站。 在该网站&#xff0c;可以使用 show command 命令展示所有可用命令。 你也可以直接访问网站的sandbox&#xff0c;自由发挥。 本地篇 基础篇 git commit git commit将暂…

Matlab随机数的产生

1、常见分布随机数的产生 1.1 二项分布 在贝努力试验中&#xff0c;某事件A发生的概率为p&#xff0c;重复该实验n次&#xff0c;X表示这n次实验中A发生的次数&#xff0c;则随机变量X服从的概率分布律&#xff08;概率密度&#xff09;为 记为 binopdf(x,n,p) p…

BiMPM实战文本匹配【下】

引言 这是BiMPM实战文本匹配的第二篇文章。 注意力匹配 如上图所示&#xff0c;首先计算每个正向(或反向)上下文嵌入 h i p → \overset{\rightarrow}{\pmb h_i^p} hip​→​(或 h i p ← \overset{\leftarrow}{\pmb h_i^p} hip​←​)与另一句的每个正向(或反向)上下文嵌入 …

MQTT协议是什么?快速了解MQTT协议在物联网中的应用

随着工业互联网的迅猛发展&#xff0c;工业设备数据采集和实时监控成为制造业提高生产效率和质量的重要手段。在物联网应用中&#xff0c;通信技术包括Wi-Fi、RFID、NFC、RS232、RS485、USB等&#xff0c;其中在物联网技术框架体系中所使用到的通讯协议主要有&#xff1a;AMQP、…

企业软文推广应该如何巧妙植入品牌信息?

软文推广相比于传统硬广而言&#xff0c;成本更低且效果明显&#xff0c;因此不少企业在进行营销时都会优先考虑软文推广&#xff0c;但是部分企业在写软文时因为产品融入不明显导致软文推广没有效果。下面媒介盒子就来告诉大家&#xff0c;企业在进行软文推广时应该如何巧妙植…

数字孪生:降低现代船舶水声设备研制风险与成本的关键要素

声波是海洋中唯一能够有效传递远距离信息的载体&#xff0c;1000Hz的声波在海水中的每公里吸收衰减仅为0.067分贝&#xff0c;而在陆地上大显神通的电磁波由于受到海水高介电常数和高导电率的影响&#xff0c;因传播衰减量太大而无法通信。 声波在海洋中的传播也并非一帆风顺。…

C#,数值计算——Ranbyte的计算方法与源程序

1 文本格式 using System; namespace Legalsoft.Truffer { /// <summary> /// Generator for random bytes using the algorithm generally known as RC4. /// </summary> public class Ranbyte { private int[] s { get; set; } n…

vue安装步骤

1、winR ->cmd 打开运行窗口 2、如下两种方式&#xff0c;测试电脑现有vue版本&#xff0c;提示"MODULE_NOT_FOUND"错误 (1)方式一&#xff1a;vue -V (2)方式二&#xff1a;vue -version 3、输入以下命令&#xff1a; 参考链接&#xff1a;https://blog.csdn.n…

自发光贴图和光照贴图的原理和作用

什么自发光贴图 自发光贴图&#xff08;Emissive Mapping&#xff09;是一种用于在计算机图形学中模拟自发光效果的技术。它可以将光源直接嵌入纹理贴图中&#xff0c;以模拟物体表面具有发光效果的材质。 传统的纹理贴图只能模拟物体表面的颜色和纹理&#xff0c;无法模拟物体…

密码学算法都是怎样实现的? 都有哪些实现方式?

码学算法可以在多种不同的实现方式中进行&#xff0c;具体的实现方式取决于硬件平台、性能需求和应用场景。以下是一些常见的密码学算法实现方式&#xff1a; 纯软件实现&#xff1a; 这是最通用的方式&#xff0c;密码学算法完全由软件编写和执行。这种实现方式可以在各种计算…

anaconda、python卸载后重装以及anaconda--443

anaconda、python卸载后重装 一 .conda创建环境报错处理Collecting package etadata (current_repodata.json): DEBUG:urllib3问题&#xff1a;解决方法一&#xff1a;解决方法二&#xff1a; 二. anaconda3如何卸载干净1. 安装 Anaconda-Clean package2. 打开Anaconda Prompt&…