二、小试牛刀-利用驱动操作GPIO点灯
(1)IMX6ULL 的 GPIO 模块结构
IMX6ULL的GPIO一共有5组,每组引脚最多有32个。
-
GPIO1 :GPIO1_IO0~GPIO1_IO31;
-
GPIO2 :GPIO2_IO0~GPIO2_IO21;
-
GPIO3 :GPIO3_IO0~GPIO3_IO28;
-
GPIO4 :GPIO4_IO0~GPIO4_IO28;
-
GPIO5 :GPIO5_IO0~GPIO5_IO11;
GPIO 的控制涉及 4 大寄存器:CCM、IOMUXC、GPIO 。
-
CCM 用于设置是否向 GPIO 模块提供时钟 ,通过CCM_CCGR 寄 存器来设置。

-
IOMUXC:引脚的模式(Mode、功能),,IOMUX通过 2 个寄存器用来设置
IOMUXC_SW_MUX_CTL_PAD<PADNAME> :Mux pad xxx,选择某个 pad 的功能IOMUXC_SW_MUX_CTL_GRP_<GROUP NAME>:Mux grp xxx,选择某组引脚的功能,一个引脚对应一个寄存器对于操作GPIO点灯只需关注三个寄存器
GPIOx_GDIR:设置引脚方向,每位对应一个引脚,1-output,0-inputGPIOx_GDIR:设置输出引脚的电平,每位对应一个引脚,1-高电平,0-低电平GPIOx_PSR:读取引脚的电平,每位对应一个引脚,1-高电平,0-低电
-
具体操作
读引脚
-
设置 CCM_CCGRx 寄存器中某位使能对应的 GPIO 模块 -
设置 IOMUX 来选择引脚用于 GPIO -
设置 GPIOx_GDIR 中某位为 0,把该引脚设置为输入功能 -
读 GPIOx_DR 或 GPIOx_PSR 得到某位的值(读 GPIOx_DR 返回的是 GPIOx_PSR 的值)
写引脚
-
设置 CCM_CCGRx 寄存器中某位使能对应的 GPIO 模块 默认是使能的 -
设置 IOMUX 来选择引脚用于 GPIO -
设置 GPIOx_GDIR 中某位为 1,把该引脚设置为输出功能 -
写 GPIOx_DR 某位的值
需要注意的是,你可以设置该引脚的 loopback 功能,这样就可以从 GPIOx_PSR 中读到引脚的有实电平;你从 GPIOx_DR 中读回的只是上次设置的值,它并不能反应引脚的真实电平,比如可能因为硬件故障导致该引脚跟地短路了,你通过设置 GPIOx_DR 让它输出高电平并不会起效果。
(2)驱动程序
-
驱动程序分为上下两层:leddrv.c、board.c
将LED操作抽象为结构体
1 #ifndef _LED_OPR_H 2 #define _LED_OPR_H 3 4 5 struct led_operations 6 { 7 int num; 8 int (*init)(int which); 9 int (*ctl)(int which,char status); 10 }; 11 12 struct led_operations *get_board_led_opr(void);//函数声明注册单板GPIO 13 14 #endif
在芯片手册中确定的寄存器地址被称为物理地址,在 Linux 内核中无法直接使用,需要使用内核提供的 ioremap 把物理地址映射为虚拟地址,使用虚拟地址。
virt_addr = ioremap(phys_addr, size);
把物理地址 phys_addr 开始的一段空间(大小为 size),映射为虚拟地址;返回值是该段虚拟地址的首地址。

1 static volatile unsigned int *CCM_CCGR1 ;//时钟 2 static volatile unsigned int *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3;//引脚 3 static volatile unsigned int *GPIO5_GDIR ;//输入输出 4 static volatile unsigned int *GPIO5_DR ;//高低电平 5 6 static int board_led_init(int which) 7 { 8 unsigned int val; 9 10 if(which==0) 11 { 12 13 if(!CCM_CCGR1) 14 { 15 CCM_CCGR1 = ioremap(0x20C406C, 4);//4字节 16 IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 = ioremap(0x2290014, 4); 17 GPIO5_GDIR = ioremap(0x020AC000 + 0x4, 4); 18 GPIO5_DR = ioremap(0x020AC000 + 0, 4); 19 } 20 21 *CCM_CCGR1 |= (3<<30);//GPIO5时钟 22 23 val = *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3;//配置引脚功能 24 val &= ~(0xf); 25 val |= (5); 26 *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 = val; 27 28 *GPIO5_GDIR |= (1<<3);//输出高电平 29 } 30 return 0; 31 } 32 33 34 static int board_led_ctl(int which,char status) 35 { 36 if(which==0) 37 { 38 if(status) 39 { 40 *GPIO5_DR&=(1<<3); 41 } 42 else 43 { 44 *GPIO5_DR|=(1<<3); 45 } 46 } 47 48 return 0; 49 } 50 51 struct led_operations board_led_opr= 52 { 53 .num=1, 54 .init=board_led_init, 55 .ctl=board_led_ctl, 56 }; 57 58 struct led_operations *get_board_led_opr(void) 59 { 60 return &board_led_opr; 61 }
1 #include <linux/module.h> 2 3 #include <linux/fs.h> 4 #include <linux/errno.h> 5 #include <linux/miscdevice.h> 6 #include <linux/kernel.h> 7 #include <linux/major.h> 8 #include <linux/mutex.h> 9 #include <linux/proc_fs.h> 10 #include <linux/seq_file.h> 11 #include <linux/stat.h> 12 #include <linux/init.h> 13 #include <linux/device.h> 14 #include <linux/tty.h> 15 #include <linux/kmod.h> 16 #include <linux/gfp.h> 17 18 #include "led_opr.h" 19 20 static int major=0; 21 static struct class *led_class; 22 static struct led_operations *p_led_opr; 23 24 static ssize_t led_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset) 25 { 26 printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); 27 return 0; 28 } 29 30 /* write(fd, &val, 1); */ 31 static ssize_t led_drv_write (struct file *file, const char __user *buf, size_t size, loff_t *offset) 32 { 33 int err; 34 char status; 35 struct inode *inode = file_inode(file); 36 int minor = iminor(inode);//提取次设备号 37 38 printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); 39 err = copy_from_user(&status, buf, 1); 40 41 /* 根据次设备号和status控制LED */ 42 p_led_opr->ctl(minor, status); 43 44 return 1; 45 } 46 47 static int led_drv_open (struct inode *node, struct file *file) 48 { 49 int minor = iminor(node); 50 51 printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); 52 /* 根据次设备号初始化LED */ 53 p_led_opr->init(minor); 54 55 return 0; 56 } 57 58 static int led_drv_close (struct inode *node, struct file *file) 59 { 60 printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); 61 return 0; 62 } 63 64 65 static struct file_operations led_drv = { 66 .owner = THIS_MODULE, 67 .open = led_drv_open, 68 .read = led_drv_read, 69 .write = led_drv_write, 70 .release = led_drv_close, 71 }; 72 73 74 static int __init led_init(void) 75 { 76 int err; 77 int i; 78 79 major=register_chrdev(0,"100ask_led",&led_drv); 80 81 led_class=class_create(THIS_MODULE,"100ask_led_class"); 82 err=PTR_ERR(led_class); 83 if(IS_ERR(led_class)) 84 { 85 printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); 86 unregister_chrdev(major,"100ask_led"); 87 return -1; 88 } 89 90 p_led_opr=get_board_led_opr(); 91 92 for(i=0;i<p_led_opr->num;i++) 93 { 94 device_create(led_class,NULL,MKDEV(major,i),NULL,"100ask_led%d", i); 95 } 96 97 return 0; 98 99 } 100 101 static void __exit led_exit(void) 102 { 103 int i; 104 printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); 105 106 for (i = 0; i < p_led_opr->num; i++) 107 device_destroy(led_class, MKDEV(major, i)); /* /dev/100ask_led0,1,... */ 108 109 device_destroy(led_class, MKDEV(major, 0)); 110 class_destroy(led_class); 111 unregister_chrdev(major, "100ask_led"); 112 } 113 114 module_init(led_init); 115 module_exit(led_exit); 116 117 MODULE_LICENSE("GPL");
1 #include <sys/types.h> 2 #include <sys/stat.h> 3 #include <fcntl.h> 4 #include <unistd.h> 5 #include <stdio.h> 6 #include <string.h> 7 8 /* 9 * ./ledtest /dev/100ask_led0 on 10 * ./ledtest /dev/100ask_led0 off 11 */ 12 int main(int argc, char **argv) 13 { 14 int fd; 15 char status; 16 17 /* 1. 判断参数 */ 18 if (argc != 3) 19 { 20 printf("Usage: %s <dev> <on | off>\n", argv[0]); 21 return -1; 22 } 23 24 /* 2. 打开文件 */ 25 fd = open(argv[1], O_RDWR); 26 if (fd == -1) 27 { 28 printf("can not open file %s\n", argv[1]); 29 return -1; 30 } 31 32 /* 3. 写文件 */ 33 if (0 == strcmp(argv[2], "on")) 34 { 35 status = 1; 36 write(fd, &status, 1); 37 } 38 else 39 { 40 status = 0; 41 write(fd, &status, 1); 42 } 43 44 close(fd); 45 46 return 0; 47 }

浙公网安备 33010602011771号