做资源网站,广丰区建设局网站,wordpress单页后台模板,建筑工地招工招聘信息平台1、地址映射 在编写驱动之前#xff0c;需要知道MMU#xff0c;也就是内存管理单元#xff0c;在老版本的 Linux 中要求处理器必须有 MMU#xff0c;但是现在Linux 内核已经支持无 MMU 的处理器了。 MMU的功能如下#xff1a; 完成虚拟空间到物理空间的映射 内存保护…1、地址映射 在编写驱动之前需要知道MMU也就是内存管理单元在老版本的 Linux 中要求处理器必须有 MMU但是现在Linux 内核已经支持无 MMU 的处理器了。 MMU的功能如下 完成虚拟空间到物理空间的映射 内存保护设置存储器的访问权限设置虚拟存储空间的缓冲特性 我们重点来讲第一点物理空间映射是虚拟空间到物理空间的映射也叫做地址映射。 先了解虚拟地址(VA,Virtual Address)、物理地址(PAPhyscicalAddress)这两个概念对于 32 位 的处理器来说虚拟地址范围是 2^324GB我们的开发板上有 512MB 的 DDR3这 512MB 的 内存就是物理内存经过 MMU 可以将其映射到整个 4GB 的虚拟空间。
所以后续我们访问相关引脚进行操作的时候如果没有开启 MMU 的话 直接向 0X020E0068 这个寄存器地址写入数据就可以配置 GPIO1_IO03 的复用功能。现在开启 了 MMU并且设置了内存映射因此就不能直接向 0X020E0068 这个地址写入数据了。我们必须得到 0X020E0068 这个物理地址在 Linux 系统里面对应的虚拟地址这里就涉及到了物理内 存和虚拟内存之间的转换需要用到两个函数ioremap 和 iounmap。总得来说也就是上面的步骤多加了一个IO映射的一个过程仅此而已。 2、引脚操作回顾
2.1 STM32 GPIO回顾
主要是通过流程来作为思维的引导。我们一般拿到一款全新的芯片第一个要做的事情的就是驱动其 GPIO控制其 GPIO 输出高低电平我们学习 I.MX6U 也一样的先来学习一下 I.MX6U 的 GPIO。在学习 I.MX6U 的 GPIO 之前我们先来回顾一下 STM32 的 GPIO 初始化(如果没有学过 STM32 就不用回顾了)我们以最常见的 STM32F103 为例来看一下 STM32 的 GPIO 初始化示例代码如下
void LED_Init(void)
{GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//使能 PB 端口时钟GPIO_InitStructure.GPIO_Pin GPIO_Pin_5; //PB5 端口配置GPIO_InitStructure.GPIO_Mode GPIO_Mode_Out_PP; //推挽输出GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; //IO 口速度GPIO_Init(GPIOB, GPIO_InitStructure); //根据设定参数初始化 GPIOB.5GPIO_SetBits(GPIOB,GPIO_Pin_5); //PB.5 输出高
}
看不止是看代码要看流程1.使能时钟 2.初始化GPIO比如上下拉、速度 3.io口是否需要复用 4.GPIO输出高电平还是低电平 这是流程。
我们还需要了解相关位操作具体如下所示
分别是写设置读清除
val data_reg;
val val | (1n);
data_reg val;
上述为写操作具体涉及 “ | ”不影响其他位。
val data_reg;
val val ~(1n);
data_reg val;
上述为读操作具体涉及 “ ~ “ ” ”不影响其他位。 3、编译驱动程序
#include linux/types.h
#include linux/kernel.h
#include linux/delay.h
#include linux/ide.h
#include linux/init.h
#include linux/module.h
#include linux/errno.h
#include linux/gpio.h
#include asm/mach/map.h
#include asm/uaccess.h
#include asm/io.h#define LED_MAJOR 200 /* 主设备号 */
#define LED_NAME led /* 设备名字 */#define LEDOFF 0 /* 关灯 */
#define LEDON 1 /* 开灯 */#define CCM_CCGR1_BASE (0X020C406C)
#define SW_MUX_GPIO1_IO03_BASE (0X020E0068)
#define SW_PAD_GPIO1_IO03_BASE (0X020E02F4)
#define GPIO1_DR_BASE (0X0209C000)
#define GPIO1_GDIR_BASE (0X0209C004)static void __iomem *IMX6U_CCM_CCGR1;
static void __iomem *SW_MUX_GPIO1_IO03;
static void __iomem *SW_PAD_GPIO1_IO03;
static void __iomem *GPIO1_DR;
static void __iomem *GPIO1_GDIR;/** description : LED 打开/关闭* param - sta : LEDON(0) 打开 LEDLEDOFF(1) 关闭 LED* return : 无*/
void led_switch(u8 sta)
{u32 val 0;if(sta LEDON) {val readl(GPIO1_DR);val ~(1 3); writel(val, GPIO1_DR);}else if(sta LEDOFF) {val readl(GPIO1_DR);val | (1 3);writel(val, GPIO1_DR);}
}static int led_open (struct inode *inodp, struct file *filp)
{return 0;
}static ssize_t led_read (struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{return 0;
}/*
* description : 向设备写数据
* param - filp : 设备文件表示打开的文件描述符
* param - buf : 要写给设备写入的数据
* param - cnt : 要写入的数据长度
* param - offt : 相对于文件首地址的偏移
* return : 写入的字节数如果为负值表示写入失败
*/
static ssize_t led_write (struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{int retvalue 0;unsigned char databuf[1];unsigned char ledstat;retvalue copy_from_user(databuf,buf,cnt);if(retvalue 0){printk(kernel write failed\r\n);return -EFAULT;}ledstat databuf[0];if(ledstat LEDON){led_switch(LEDON);}else if(ledstat LEDOFF){led_switch(LEDOFF);}return 0;
}/** description : 关闭/释放设备* param - filp : 要关闭的设备文件(文件描述符)* return : 0 成功;其他 失败*/
static int led_release (struct inode *inodp, struct file *filp)
{return 0;
}static struct file_operations led_fops {.owner THIS_MODULE,.open led_open,.read led_read,.write led_write,.release led_release,
};static int __init led_init(void){int retvalue 0;u32 val 0;IMX6U_CCM_CCGR1 ioremap(CCM_CCGR1_BASE,4);SW_MUX_GPIO1_IO03 ioremap(SW_MUX_GPIO1_IO03_BASE,4);SW_PAD_GPIO1_IO03 ioremap(SW_PAD_GPIO1_IO03_BASE,4);GPIO1_DR ioremap(GPIO1_DR_BASE,4);GPIO1_GDIR ioremap(GPIO1_GDIR_BASE,4);/* 2、使能 GPIO1 时钟 */val readl(IMX6U_CCM_CCGR1);val ~(3 26); /* 清除以前的设置 */val | (3 26); /* 设置新值 */writel(val, IMX6U_CCM_CCGR1);/* 3、设置 GPIO1_IO03 的复用功能将其复用为* GPIO1_IO03最后设置 IO 属性。*/writel(5, SW_MUX_GPIO1_IO03);/* 寄存器 SW_PAD_GPIO1_IO03 设置 IO 属性 */writel(0x10B0, SW_PAD_GPIO1_IO03);/* 4、设置 GPIO1_IO03 为输出功能 */val readl(GPIO1_GDIR);val ~(1 3); /* 清除以前的设置 */val | (1 3); /* 设置为输出 */writel(val, GPIO1_GDIR);/* 5、默认关闭 LED */val readl(GPIO1_DR);val | (1 3); writel(val, GPIO1_DR);//设备号 名字 字符模型驱动的一个结构体retvalue register_chrdev(LED_MAJOR,LED_NAME,led_fops);if(retvalue 0){// exit}return 0;
}static void __exit led_exit(void){iounmap(IMX6U_CCM_CCGR1);iounmap(SW_MUX_GPIO1_IO03);iounmap(SW_PAD_GPIO1_IO03);iounmap(GPIO1_DR);iounmap(GPIO1_GDIR);unregister_chrdev(LED_MAJOR,LED_NAME);
}module_init(led_init);
module_exit(led_exit);MODULE_LICENSE(GPL);
MODULE_AUTHOR(7yewh);