驱动开发(三):内核层控制硬件层

news/2024/6/18 21:32:28 标签: 驱动开发, 嵌入式硬件, arm开发
 驱动开发系列文章:
                驱动开发(一):驱动代码的基本框架    
                驱动开发(二):创建字符设备驱动
                驱动开发(三):内核层控制硬件层​​​​​​​         ←本文

目录

驱动是如何操作寄存器的

地址映射函数

物理地址映射为虚拟地址

取消映射

实际操作流程演示


驱动是如何操作寄存器的

驱动操作寄存器可以通过以下步骤实现:

  1. 获取寄存器的地址:首先需要确定要操作的寄存器的地址。这可以通过查阅芯片的数据手册或者使用芯片提供的寄存器映射文档来获得。

  2. 设置寄存器的值:使用编程语言提供的位操作或者寄存器操作函数,将需要设置的值写入到寄存器中。可以使用位掩码来确定要设置的位或者位域。

  3. 读取寄存器的值:使用编程语言提供的位操作或者寄存器操作函数,读取寄存器的当前值。可以使用位掩码来获取特定位或者位域的值。

需要注意的是,在操作寄存器时,要确保对寄存器的访问是合法的,遵循芯片厂商的规定,避免对未定义或者只读的寄存器进行写操作。此外,还要考虑并发访问的问题,如果多个驱动同时操作同一个寄存器,可能会引发竞争条件或者数据不一致的问题,需要进行同步或者互斥操作。

以点亮一盏灯为例,控制rgb_led灯的寄存器是物理地址,但是在Linux内核启动之后,在使用地址的时候,操作的全是虚拟地址需要将物理地址转换为虚拟地址。在驱动代码中操作的虚拟地址就相当于操作的实际物理地址。

地址映射函数

物理地址映射为虚拟地址

void * ioremap(phys_addr_t offset, unsigned long size)
    功能:将物理地址映射成虚拟地址
    参数:
	     @offset :要映射的物理地址
	     @size   :大小(字节)
    返回值:成功返回虚拟地址,失败返回NULL;

取消映射

void iounmap(void  *addr)
    功能:取消映射
    参数:	
	    @addr :虚拟地址
    返回值:无

实际操作流程演示

1、以S5P6818的U21引脚输出高电平熄灭LED灯为例

2、在手册芯片搜索U21引脚

 GPIOXOUT寄存器:控制高低电平

GPIOXOUTENB寄存器:输入/输出模式 对应位置1设置为输出模式

 GPIOXALTFN寄存器:功能模式寄存器(配置引脚是哪种功能),刚刚查询引脚时可以看到,功能0为GPIO,选择功能0,

 GPIOA28 (0XC001A000)----> red_base   //起始地址

*(red_base) |= 1<<28;    //操作GPIOXOUT寄存器,控制引脚电平

*(red_base+1) |= 1<<28;   //操作GPIOXOUTENB寄存器,设置为输出模式

*(red_base+9) &= ~(3<<24);  //操作GPIOXALTFN寄存器,选择GPIO功能模式

 3、根据查询到的信息编写驱动代码

#include <linux/init.h>
#include <linux/module.h>
#include <linux/printk.h>
#include <asm/io.h>

#define RED 0XC001A000      //起始物理地址
unsigned int *red_base = NULL;

static int __init hello_init(void)
{
    red_base = ioremap(RED,40); //将物理地址映射成虚拟地址
    if (NULL == red_base )
    {
        printk("ioremap err\n");
    }
    *(red_base) &= ~(1<<28);    //操作寄存器
    *(red_base+1) |= 1<<28;
    *(red_base+9) &= ~(3<<24);

    return 0;
}
static void __exit hello_exit(void)
{
    *(red_base) |= (1<<28);    //还原LED状态
    iounmap(red_base);         //取消映射
}
module_init(hello_init); //入口
module_exit(hello_exit); //出口
MODULE_LICENSE("GPL");   //许可证


http://www.niftyadmin.cn/n/5520425.html

相关文章

深度学习(八)——神经网络:卷积层

一、卷积层Convolution Layers函数简介 官网网址&#xff1a;torch.nn.functional — PyTorch 2.0 documentation 由于是图像处理&#xff0c;所以主要介绍Conv2d。 class torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride1, padding0, dilation1, groups1, b…

【React】在 React 组件中,怎么使用useContext

在React中,useContext 是一个Hook,它允许你无需显式地通过组件树的每一层来传递 props,就能将值深入到组件树的任何位置。要使用 useContext,你需要先创建一个 Context 对象,然后使用这个对象提供的 Provider 组件来包裹你的应用中的一部分。然后,任何在这个 Provider 下…

存储技术介绍

存储技术介绍 概述存储技术DASNASSANDAS、NAS、SAN 的比较NAS 和 SAN 的比较存储方式对象存储块存储文件存储差异比较存储接口SCSIiSCSISASSATA带宽速度换算eSATAFCFCoE可靠性技术RAID各 RAID 级别的比较备份快照镜像镜像与备份、拷贝、复制的比较群集并发存取相关硬件磁盘阵列…

解锁Java高效并发:newFixedThreadPool深度剖析与实战

1. 引言 在Java的并发编程中,线程池是一个重要的概念。而newFixedThreadPool作为Java标准库java.util.concurrent中Executors类的一个静态方法,为开发者提供了一个固定大小的线程池实现。本文旨在深入剖析newFixedThreadPool的原理、源码实现以及最佳实践,更好地理解和应用…

5、闭环检测

闭环检测&#xff08;Loop Closure Detection&#xff09; 闭环检测&#xff08;Loop Closure Detection&#xff09;是SLAM&#xff08;同步定位与地图构建&#xff09;系统中的一个关键步骤。它的主要目的是检测出机器人&#xff08;或相机&#xff09;是否再次访问了先前已…

李永乐线代笔记

线性方程组 解方程组的变换就是矩阵初等行变换 三秩相等 方程组系数矩阵的行秩列秩&#xff0c;线性相关的问题应求列秩&#xff0c;但求行秩方便 齐次线性方程组 对应向量组的线性相关&#xff0c;所以回顾下线性相关的知识&#xff1a; 其中k是x&#xff0c;所以用向…

前端菜鸡流水账日记 -- pnpm的学习

哈咯哇大家&#xff0c;我又来了&#xff0c;最近稍微悠闲一些&#xff0c;所以就趁着这个机会学习一些新的知识&#xff0c;今天就是碰巧遇到了pnm&#xff0c;这个可以看作是npm的升级版本&#xff0c;比npm要快&#xff0c;用起来也更得劲更迅速 官网地址&#xff1a;https…

10.第十章 列表

10. 列表 本章介绍Python语句最有用的内置类型之一: 列表. 你还能学到更多关于对象的知识, 以及同一个对象有两个或更多变量时会发生什么.10.1 列表是一个序列 和字符串相似, 列表(list)是值的序列. 在字符串中, 这些值是字符; 在列表中, 它可以是任何类型. 列表中的值称为元…