首页 > 系统相关 >嵌入式Linux中的LED驱动控制(续)

嵌入式Linux中的LED驱动控制(续)

时间:2024-06-11 21:23:13浏览次数:30  
标签:LED 引脚 端口 Linux 值为 模式 嵌入式 寄存器 15

前面的实例实现了在野火STM32MP157开发板上对三个LED灯的控制,这里来讨论一下该驱动程序的具体实现方式。由于实例使用的是STM32MP157这款芯片,所以先来看一下与该芯片端口操作相关的寄存器。

先看端口模式寄存器MODER,该类型的寄存器在STM32MP157中有11个,即x的值从A到K。它们分别针对11组不同的I/O端口,其结构完全相同(下同)。下面是该寄存器的全部位结构。它的偏移地址为:0x00。

第31~0位分别配置第15~第0引脚的具体模式,每两位配置一个引脚。当值为00时,引脚为输入模式,值为01时,引脚为通用输出模式,值为10时,引脚为多功能模式,值为11时,引脚为模拟模式。默认为模拟模式。

接着看端口输出类型寄存器OTYPER,下面是该寄存器的全部位结构。它的偏移地址为:0x04。

第15~0位分别配置第15~第0引脚的输出类型,每一位配置一个引脚,第31~16位未使用。当值为0时,引脚为推挽模式,值为1时,引脚为开漏模式。默认为推挽模式。

接下来是端口输出速度寄存器OSPEEDR,下面是该寄存器的全部位结构。它的偏移地址为:0x08。

第31~0位分别配置第15~第0引脚的具体模式,每两位配置一个引脚。当值为00时,引脚为低速模式,值为01时,引脚为中速模式,值为10时,引脚为高速模式,值为11时,引脚为超高速模式。默认为低速模式。

然后看端口上/下拉寄存器PUPDR,下面是该寄存器的全部位结构。它的偏移地址为:0x0C。

第31~0位分别配置第15~第0引脚的具体模式,每两位配置一个引脚。当值为00时,引脚为无上下拉(浮空)模式,值为01时,引脚为上拉模式,值为10时,引脚为下拉模式,值为11时保留。默认为浮空模式。

接着看端口输入数据寄存器IDR,下面是该寄存器的全部位结构。它的偏移地址为:0x10。

第15~0位分别提供第15~第0引脚的输入数据,每一位对应一个引脚,第31~16位未使用。当值为0时,引脚输入为低电平,值为1时,引脚输入为高电平。该寄存器为只读。

然后是端口输出数据寄存器ODR,下面是该寄存器的全部位结构。它的偏移地址为:0x14。

第15~0位分别提供第15~第0引脚的输出数据,每一位对应一个引脚,第31~16位未使用。当值为0时,引脚输出低电平,值为1时,引脚输出高电平。默认为低电平。

最后看端口位配置寄存器BSRR,下面是该寄存器的全部位结构。它的偏移地址为:0x18。

第31~16位分别提供第15~第0引脚的清零,每一位对应一个引脚,写1时引脚清零(输出低电平),写0无效。第15~0位分别提供第15~第0引脚的置位,每一位对应一个引脚,写1时引脚置位(输出高电平),写0无效。默认为无效。

在操作端口的输出电平时,可以有ODR和BSRR两个寄存器选择,虽然两者都能实现端口电平的输出,但还是有所区别的。当要求操作某一引脚的电平而不影响其他引脚的电平时,若使用ODR寄存器则要实现“读——改——写”的过程,即先把ODR数据读出,然后通过逻辑与或进行修改,再写入到ODR寄存器中。若使用BSRR寄存器则可直接写入,非常方便。

除了上述对端口控制的寄存器之外,还有一个时钟使能寄存器也需要讨论(只有一个),它寄存器名称为RCC_MP_AHB4ENSETR,下面是该寄存器的全部位结构。它的偏移地址为:0xA28。

第0~10位分别控制第A~第K组端口的时钟,值为1时使能该组端口时钟,值为0时禁止时钟。默认为禁止。

以上就是本例中使用到的寄存器,他们都位于AHB4总线之中,这些寄存器的地址都是以AHB4的基址为偏移的,具体地址如下表所示。

在Linux系统中,并不能直接使用物理地址对寄存器进行操作,必须先把寄存器的物理地址映射到操作系统中来形成虚拟地址,然后才能进行相应地操作。实现映射功能的函数名为ioremap,其原型为:void __iomem *ioremap(phys_addr_t paddr, unsigned long size)。第一个参数为物理地址,第二个参数为长度,返回值是一个指向__iomem类型的指针。__iomem是一个宏,它表示返回的地址是一个IO存储空间的有效地址。相应的解除映射函数iounmap,其原型为:void iounmap(void *addr)。只有一个参数,为前面映射时的返回指针,该函数没有返回值。

下面以映射GPIO_MODER_PA寄存器为例进行说明,先对GPIO_MODER_PA寄存器的物理地址进行一个宏定义,定义采取基址+偏移量的方式,如下。

#define AHB4_PERIPH_BASE (0x50000000)
#define GPIOA_BASE (AHB4_PERIPH_BASE + 0x2000)
#define GPIOA_MODER (GPIOA_BASE + 0x0000)

然后定义一个用于接收映射的返回值的指针变量,如下。

volatile void __iomem *GPIO_MODER_PA

变量加上前缀volatile关键字,表示它不接受编译器优化(一般定义寄存器都要如此)。

然后就可以进行地址映射了,如下。

GPIO_MODER_PA = ioremap(GPIOA_MODER, 4);

映射成功后,就可以使用GPIO_MODER_PA来进行赋值了,如下。

tmp = ioread32(GPIO_MODER_PA);
tmp &= ~(0x3 << 26);
tmp |= (0x1 << 26);
iowrite32(tmp, GPIO_MODER_PA);

上面的赋值采用了“读——改——写”的方式,所以只改变寄存器的第26、27两位,其余位不变。经过赋值后,GPIOA的第13引脚就被配置成了通用输出模式。

在Linux中,对端口的读写有专用的函数,一般不推荐直接对指针进行操作。ioread32函数用于读取一个32位的值,iowrite32函数用于写入一个32位的值。(早期可能会使用readl和writel函数,现在不推荐使用)

本例把寄存器的地址映射放在了入口函数(led_init)中,同时也把端口配置放在了入口中。把解除映射函数放在出口函数(led_exit)中进行。对芯片寄存器的读、写等操作放在了文件操作接口里面(file_operations结构体成员函数中)。在使用设备时,应用程序会打开设备节点,并通过设备节点的inode结构体、file结构体最终找到file_operations结构体,然后从file_operations结构体中得到操作设备的具体方法。 这部分的具体内容可参见“嵌入式Linux中字符型驱动程序的基本框架”一文。在函数alloc_chrdev_region(&devno, 0, 3, "led")执行后,字符串led会出现在/proc/devices文件中。函数class_create(THIS_MODULE,  "led_dev")执行后,字符串led_dev会出现在/sys/class目录下。函数device_create(led_chrdev_class, Null, devid, Null, "led%d", i)执行后,字符串ledi会出现在/dev目录下。可在开发板上自行查看。

标签:LED,引脚,端口,Linux,值为,模式,嵌入式,寄存器,15
From: https://www.cnblogs.com/fxzq/p/18202291

相关文章

  • Linux速成技巧:通过Docker高效运行Swift
    Swift,作为苹果公司推出的一种强类型编程语言,以其高效、安全的特性在开发社区中广受欢迎。虽然Swift最初是为iOS和macOS开发设计的,但它的应用范围已经扩展到了Linux平台。在Linux环境中,通过Docker运行Swift成为了一种流行且高效的方式。本文将详细介绍如何在Linux环境中通过D......
  • QWidget 属性——enabled
    ......
  • 在Linux系统中使用Certbot为Nginx安装SSL证书
    在Linux系统中使用Certbot为Nginx安装SSL证书并进行配置,通常遵循以下步骤:1.安装Certbot首先确保你的系统已经安装了EPEL仓库,如果没有安装,可以通过以下命令安装:sudoyuminstallepel-release接着安装Certbot:sudoyuminstallcertbot2.配置Nginx在Nginx配置文件中添......
  • Linux系统通过CrossOver运行windows系统exe程序
    1.CrossOver下载下载网址:https://crossover.mairuan.com/?a_planid=462146305&a_unitid=9457631754&a_kw_enc_utf8=crossover+%E4%B8%8B%E8%BD%BD&a_creative=93751965498&cjtg=bdsem_cr_pp&bd_vid=11448931900093706309点击免费下载软件自动下载的安装包不是liunx需要的,需要下......
  • linux基本知识(2)
    链接(创建链接(硬链接,软连接))目录的本质:文件​ 如果想在一个目录中添加或者删除目录项,需要获得目录的写权限硬链接:目录在物理文件系统中的指向软连接(符号链接):里面存储文件的路径,类似指针lnlsfilename 为文件file创建一个名为name的硬链接 默认创建硬链......
  • linux导出所有文件名到文件
    在Linux中,你可以使用find命令配合xargs和echo来导出文件名到文件。以下是一个例子,它会在当前目录及其子目录下查找所有文件和目录,并将它们的名称导出到filenames.txt文件中:  find.-typef-or-typed|xargsecho{}>>filenames.txt解释:find.:在当前目录......
  • 嵌入式开发常见问题解决方法
    一、问题复现稳定复现问题才能正确的对问题进行定位、解决以及验证。一般来说,越容易复现的问题越容易解决。1.1模拟复现条件有的问题存在于特定的条件下,只需要模拟出现问题的条件即可复现。对于依赖外部输入的条件,如果条件比较复杂难以模拟可以考虑程序里预设直接进入对应......
  • linux内存管理(四)- 用户空间的内存分配在kernel中的实现
    malloc是常用的用户态分配内存的接口,它会调用brk系统调用来请内存分配内存。下面看看该系统调用的实现。插一句,每次调用malloc的时候未必都会调用brk去从kernel分配实际的内存,因为每次系统调用都是有开销的,为了避免频繁的陷入内核,malloc会多申请一部分内存当作内存池,之后要申请内......
  • linux内存管理(七)- 写时复制
    在fork进程的时候子进程会共享父进程的页表,但并没有分配新页。此时页表时只读的,如果父进程或者子进程写内存就会触发pagefault,内核会重新分配内存更改页表,从此分道扬镳。因此写时复制包含两部分内容,第一是fork进程时复制页表并设置pte为只读,第二是写内存发生pagefault。先来看......
  • 【Linux驱动设备开发详解】14.Linux网络设备架构
    1.Linux网络设备驱动的结构与字符设备和块设备不同,网络设备并不对应于/dev目录下的文件,应用程序最终使用套接字完成与网络设备的接口。Linux系统对网络设备驱动定义了4个层次,这4个层次为:网络协议接口层:向网络层协议提供同一的数据包收发接口,无论是IP还是ARP,都是通过dev_queue_......