1.内核空间操作LED寄存器的方法
驱动运行在内核空间,内核空间3-4G是虚拟地址,不能够直接操作LED对应的物理地址的寄存器,需要将寄存器的地址映射成虚拟地址,以后对这个虚拟地址的操作就相当于对LED的寄存器的物理地址的操作。
2.地址映射函数的API
#include <linux/io.h>
void *ioremap(unsigned long offset, unsigned long size)
功能:将物理地址映射成虚拟地址
参数:
@offset:物理地址
@size:大小(单位字节)
返回值:成功返回虚拟地址,失败返回NULL
void iounmap(volatile void *addr)
功能:取消地址映射
参数:
@addr:虚拟地址
返回值:无
3.LED1寄存器地址
LED1-->PE10
RCC 0x50000a28 [4] 1 时钟使能
MODER 0x50006000 [21:20] 01 输出
ODR 0x50006014 [10] 1 灯亮 0 灯灭
4.LED的驱动实例
myled.c
#include <linux/fs.h> #include <linux/init.h> #include <linux/module.h> #include <linux/uaccess.h> #include <linux/io.h> #define CNAME "myled" #define MODER_BASE 0x50006000 #define ODR_BASE 0x50006014 #define RCC_GPIOE 0x50000a28 int major = 0; char kbuf[128] = { 0 }; unsigned int *rcc_base=NULL; unsigned int *moder_base=NULL; unsigned int *odr_base=NULL; #define LED1ON (*odr_base |= (1<<10)) #define LED1OFF (*odr_base &= ~(1<<10)) int myled_open(struct inode* inode, struct file* file) { printk("%s:%s:%d\n", __FILE__, __func__, __LINE__); //寄存器初始化 *rcc_base1=(1<<4);//使用gpioe的时钟 *moder_base &= ~(3<<20);//清零 *moder_base |= (1<<20);//输出gpioe10 *odr_base &= ~(1<<10);//LED熄灭 /* // 地址映射 rcc = ioremap(0x50000a28, 4); if (rcc == NULL) { printk("ioremap rcc error\n"); return -ENOMEM; } moder = ioremap(0x50006000, 4); if (moder == NULL) { printk("ioremap moder error\n"); return -ENOMEM; } odr = ioremap(0x50006014, 4); if (odr == NULL) { printk("ioremap odr error\n"); return -ENOMEM; } // 将LED1初始化为熄灭的状态 *rcc |= (1 << 4); // 时钟使能 *moder &= ~(3 << 20); // 清零这两个bit *moder |= (1 << 20); // 方向设置为输出 *odr &= ~(1 << 10); // LED1灭 */ return 0; } ssize_t mycdev_read(struct file* file,char __user* ubuf, size_t size, loff_t* offs) {