1.MMU简介
完成捏造空间到物理空间的映射
内存掩护设立存储器的访问权限,设置捏造存储空间的缓冲特性
stm32点灯可以直接利用寄存器,但是linux点灯不能直接访问寄存器,linux会使能mmu
linux中利用的都是捏造地点,要想访问物理地点0x0a就得先搞清晰0xa对应的捏造地点
得到物理地点对应的捏造地点使用ioremap函数,本质是个宏,参数分别是物理地点启始巨细,要转换的字节数目
卸载驱动的时间用iounmap()卸载映射
stm32没有这个MMU其控制gpio直接利用寄存器就行,在linux上由于这个内存映射在,必要知道真实物理地点,反推其捏造地点才华像stm32一样利用寄存器
linux做驱动有设置装备树更高级的利用方式,像这种利用寄存器的恰似手动档
2.代码:
驱动:- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/init.h>
- #include <linux/fs.h>
- #include <linux/slab.h>
- #include <linux/uaccess.h>
- #include <linux/io.h>
- #define LED_MAJOR 200
- #define LED_NAME "led"
- #define PMU_GRF_BASE (0xFDC20000)
- #define PMU_GRF_GPIO0C_IOMUX_L (PMU_GRF_BASE + 0x0010)
- #define PMU_GRF_GPIO0C_DS_0 (PMU_GRF_BASE + 0X0090)
- #define GPIO0_BASE (0xFDD60000)
- #define GPIO0_SWPORT_DR_H (GPIO0_BASE + 0X0004)
- #define GPIO0_SWPORT_DDR_H (GPIO0_BASE + 0X000C)
- /* 映射后的寄存器虚拟地址指针 */
- static void __iomem *PMU_GRF_GPIO0C_IOMUX_L_PI;
- static void __iomem *PMU_GRF_GPIO0C_DS_0_PI;
- static void __iomem *GPIO0_SWPORT_DR_H_PI;
- static void __iomem *GPIO0_SWPORT_DDR_H_PI;
- static int led_open(struct inode* inode, struct file* filp){
- return 0;
- }
- static int led_release(struct inode* inode, struct file* filp){
- return 0;
- }
- static ssize_t led_write(struct file* filp, const char __user* buf, size_t count, loff_t* ppos){
- return 0;
- }
- /* 字符设备操作集*/
- static const struct file_operations led_fops = {
- .owner = THIS_MODULE,
- .write = led_write,
- .open = led_open,
- .release = led_release,
- };
- /*注册驱动加载卸载*/
- static int __init led_init(void){ // 入口
- // 初始化led灯
- int ret = 0;
- u32 val = 0;
- PMU_GRF_GPIO0C_IOMUX_L_PI = ioremap(PMU_GRF_GPIO0C_IOMUX_L, 4);
- PMU_GRF_GPIO0C_DS_0_PI = ioremap(PMU_GRF_GPIO0C_DS_0, 4);
- GPIO0_SWPORT_DR_H_PI = ioremap(GPIO0_SWPORT_DR_H, 4);
- GPIO0_SWPORT_DDR_H_PI = ioremap(GPIO0_SWPORT_DDR_H, 4);
- // 初始化
- // 设置GPIO0_c0为GPIO功能
- val = readl(PMU_GRF_GPIO0C_IOMUX_L_PI);
- val &= ~(0x7 << 0); //最低三位置0
- val |= ((0x7 << 16) | (0x0 << 0)); // 16 17 18位置1其他不变,bit2:0:0,用作GPIO0_C0
- writel(val, PMU_GRF_GPIO0C_IOMUX_L_PI);
- // 设置GPIO_C0驱动能力为level5
- val = readl(PMU_GRF_GPIO0C_DS_0_PI);
- val &= ~(0x3f << 0); // 0 ~ 5置0
- val |= ((0x3f << 16) | (0x3f << 0)); // 16 ~ 21置1,0~5置1同时用作GPIO0c0
- writel(val, PMU_GRF_GPIO0C_DS_0_PI);
- // 设置GPIOO0_c0为输出
- val = readl(GPIO0_SWPORT_DDR_H_PI);
- val &= ~(0x1 << 0); // 0置0
- val |= ((0x1 << 16) | (0x1 << 0)); // 16置1,0置1
- writel(val, GPIO0_SWPORT_DDR_H_PI);
- // 设置GPIO_c0为低电平,关闭LED
- val = readl(GPIO0_SWPORT_DR_H_PI);
- val &= ~(0x1 << 0);
- val |= ((0x1 << 16) | (0x0 << 0));
- writel(val, GPIO0_SWPORT_DR_H_PI);
- // 开灯
- val = readl(GPIO0_SWPORT_DR_H_PI);
- val &= ~(0X1 << 0); /* bit0 清零*/
- val |= ((0X1 << 16) | (0X1 << 0)); /* bit16 置1,允许写bit0,
- bit0,高电平*/
- writel(val, GPIO0_SWPORT_DR_H_PI);
-
- // 注册字符设备
- ret = register_chrdev(LED_MAJOR, LED_NAME, &led_fops);
- if(ret < 0){
- printk("register chrdev failed!\r\n");
- return -EIO;
- }
- printk("led_init\r\n");
- return 0;
- }
- static void __exit led_exit(void){ // 出口
- u32 val = 0;
- // 关灯
- val = readl(GPIO0_SWPORT_DR_H_PI);
- val &= ~(0X1 << 0); /* bit0 清零*/
- val |= ((0X1 << 16) | (0X0 << 0)); /* bit16 置1,允许写bit0,
- bit0,低电平 */
- writel(val, GPIO0_SWPORT_DR_H_PI);
- // 取消地址映射
- iounmap(PMU_GRF_GPIO0C_IOMUX_L_PI);
- iounmap(PMU_GRF_GPIO0C_DS_0_PI);
- iounmap(GPIO0_SWPORT_DR_H_PI);
- iounmap(GPIO0_SWPORT_DDR_H_PI);
- // 注销
- unregister_chrdev(LED_MAJOR, LED_NAME);
- printk("led_exit\r\n");
- }
- module_init(led_init);
- module_exit(led_exit);
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("Narnat");
复制代码 ioremap(PMU_GRF_GPIO0C_IOMUX_L, 4);将物理地点转捏造内存
在步调挂载时初始化一些寄存器,并点亮led灯,卸载时关闭led灯
3.征象:
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |