当前位置: 首页 > news >正文

网站服务器收费关于建设单位网站的方案

网站服务器收费,关于建设单位网站的方案,asp网站后台上传不了图片,个人简历网站开发“新字符设备的GPIO驱动”和“设备树下的GPIO驱动”都要用到寄存器地址#xff0c;使用“物理内存”和“虚拟内存”映射时#xff0c;非常不方便#xff0c;而pinctrl和gpio子系统的GPIO驱动#xff0c;非常简化。因此#xff0c;要重点学习pinctrl和gpio子系统下的GPIO驱…“新字符设备的GPIO驱动”和“设备树下的GPIO驱动”都要用到寄存器地址使用“物理内存”和“虚拟内存”映射时非常不方便而pinctrl和gpio子系统的GPIO驱动非常简化。因此要重点学习pinctrl和gpio子系统下的GPIO驱动开发。但是“设备树下的GPIO驱动”也要去学习因为“设备树下的GPIO驱动”重点是学习“OF函数”。最好三个都要去认真学习有助于加强和巩固学习Linux驱动框架。 1、了解“虚拟内存” STM32MP157是32位的处理器因此它的“虚拟地址”范围是2^324GB这就是说它有4GB的虚拟空间或者说它有4GB的虚拟内存。 2、了解“物理内存” STM32MP157开发板上的DDR3为1GB这个1GB的内存就是“物理内存”。 3、了解“MMU内存管理单元” MMU是Memory Manage Unit的缩写意思是“内存管理单元”。老版本的Linux内核要求处理器必须有“MMU内存管理单元”而新版本的Linux内核不再要求处理器具有“MMU内存管理单元”了因此需要我们完成“虚拟内存”到“物理内存”之间的映射。 4、内存映射 5、“新字符设备中的GPIO驱动” 在“新字符设备驱动”中“物理内存”和“虚拟内存”可以通过ioremap()和iounmap()进行转换。 1)、ioremap()函数 void __iomem *ioremap(resource_size_t res_cookie, size_t size); 函数功能将“物理内存中首地址为res_cookie”映射到虚拟内存中的“首地址”向“虚拟内存”申请一块内存用作“虚拟地址”映射。 res_cookie“物理内存”中的起始地址 size“物理内存中首地址为res_cookie”的空间大小 返回值映射到“虚拟内存中的首地址” ioremap()函数定义在arch/arm/include/asm/io.h文件中。 2)、iounmap()函数 void iounmap (volatile void __iomem *addr); 函数功能释放掉“虚拟内存中的首地址为addr的数据块”即取消ioremap()函数所做的“物理地址”映射 3)、读操作函数 u8 readb(const volatile void __iomem *addr) 从“虚拟地址”为addr中读取1个字节; u16 readw(const volatile void __iomem *addr) 从“虚拟地址”为addr中读取2个字节; u32 readl(const volatile void __iomem *addr) 从“虚拟地址”为addr中读取4个字节; 4)、写操作函数 void writeb(u8 value, volatile void __iomem *addr) 将value的值(单字节)写入到“虚拟地址”为addr的存储单元中; void writew(u16 value, volatile void __iomem *addr) 将value的值(双字节)写入到“虚拟地址”为addr的存储单元中; void writel(u32 value, volatile void __iomem *addr) 将value的值(4字节)写入到“虚拟地址”为addr的存储单元中; 5)、“新字符设备中的GPIO驱动”内存映射与读写操作的应用 #define LEDOFF 0 /* 关灯 */ #define LEDON 1 /* 开灯 */ /*寄存器物理地址*/ #define PERIPH_BASE         (0x40000000) #define MPU_AHB4_PERIPH_BASE   (PERIPH_BASE 0x10000000) #define RCC_BASE            (MPU_AHB4_PERIPH_BASE 0x0000) #define RCC_MP_AHB4ENSETR (RCC_BASE 0XA28) #define GPIOI_BASE (MPU_AHB4_PERIPH_BASE 0xA000) #define GPIOI_MODER       (GPIOI_BASE 0x0000) #define GPIOI_OTYPER       (GPIOI_BASE 0x0004) #define GPIOI_OSPEEDR       (GPIOI_BASE 0x0008) #define GPIOI_PUPDR       (GPIOI_BASE 0x000C) #define GPIOI_BSRR       (GPIOI_BASE 0x0018) /*映射后的寄存器虚拟地址指针*/ static void __iomem *MPU_AHB4_PERIPH_RCC_PI; /*RCC_MP_AHB4ENSETR寄存器*/ static void __iomem *GPIOI_MODER_PI; /*GPIOx_MODER寄存器xA to K, Z*/ static void __iomem *GPIOI_OTYPER_PI;/*GPIOx_OTYPERxA to K,Z*/ static void __iomem *GPIOI_OSPEEDR_PI;/*GPIOx_OSPEEDRxA to K, Z*/ static void __iomem *GPIOI_PUPDR_PI; /*GPIOx_PUPDRxA to K, Z*/ static void __iomem *GPIOI_BSRR_PI;/*GPIOx_BSRRxA to K, Z*/ /*寄存器地址映射*/ static void led_ioremap(void) { MPU_AHB4_PERIPH_RCC_PI ioremap(RCC_MP_AHB4ENSETR, 4); //向“虚拟内存”申请一块内存长度为4个字节用作“物理地址为RCC_MP_AHB4ENSETR”的映射。 GPIOI_MODER_PI ioremap(GPIOI_MODER, 4); //向“虚拟内存”申请一块内存长度为4个字节用作“物理地址为GPIOI_MODER”的映射。 GPIOI_OTYPER_PI ioremap(GPIOI_OTYPER, 4); //向“虚拟内存”申请一块内存长度为4个字节用作“物理地址为GPIOI_OTYPER”的映射。 GPIOI_OSPEEDR_PI ioremap(GPIOI_OSPEEDR, 4); //向“虚拟内存”申请一块内存长度为4个字节用作“物理地址为GPIOI_OSPEEDR”的映射。 GPIOI_PUPDR_PI ioremap(GPIOI_PUPDR, 4); //向“虚拟内存”申请一块内存长度为4个字节用作“物理地址为GPIOI_PUPDR”的映射。 GPIOI_BSRR_PI ioremap(GPIOI_BSRR, 4); //向“虚拟内存”申请一块内存长度为4个字节用作“物理地址为GPIOI_BSRR”的映射。 } /*取消“寄存器地址映射”*/ static void led_iounmap(void) { iounmap(MPU_AHB4_PERIPH_RCC_PI); //释放掉“虚拟内存中的首地址为MPU_AHB4_PERIPH_RCC_PI的数据块”即取消“物理地址”映射 iounmap(GPIOI_MODER_PI); //释放掉“虚拟内存中的首地址为GPIOI_MODER_PI的数据块”即取消“物理地址”映射 iounmap(GPIOI_OTYPER_PI); //释放掉“虚拟内存中的首地址为GPIOI_OTYPER_PI的数据块”即取消“物理地址”映射 iounmap(GPIOI_OSPEEDR_PI); //释放掉“虚拟内存中的首地址为GPIOI_OSPEEDR_PI的数据块”即取消“物理地址”映射 iounmap(GPIOI_PUPDR_PI); //释放掉“虚拟内存中的首地址为GPIOI_PUPDR_PI的数据块”即取消“物理地址”映射 iounmap(GPIOI_BSRR_PI); //释放掉“虚拟内存中的首地址为GPIOI_BSRR_PI的数据块”即取消“物理地址”映射 } void led_switch(u8 sta) { u32 val 0; if(sta LEDON) { val readl(GPIOI_BSRR_PI); /*从“虚拟地址”为GPIOI_BSRR_PI中读取1个字节即相当于读GPIOI_BSRR寄存器*/ val ~(0X1 16); /* bit16 清零*/ val | (0x1 16); /*bit16 设置为1令PI0输出低电平*/ writel(val, GPIOI_BSRR_PI); /* 将val的值(单字节)写入到“虚拟地址”为GPIOI_BSRR_PI的存储单元中即相当于将val的值写入GPIOI_BSRR寄存器 */ } else if(sta LEDOFF) { val readl(GPIOI_BSRR_PI); /*从“虚拟地址”为GPIOI_BSRR_PI中读取1个字节即相当于读读GPIOI_BSRR寄存器*/ val ~(0X1 0); /* bit0 清零*/ val | (0x1 0);/*bit0 设置为1令PI0输出高电平*/ writel(val, GPIOI_BSRR_PI); /* 将val的值(单字节)写入到“虚拟地址”为GPIOI_BSRR_PI的存储单元中即相当于将val的值写入GPIOI_BSRR寄存器 */ } } 6、设备树下的的GPIO驱动 6.1、OF函数 1)、inline struct device_node *of_find_node_by_path(const char *path) path:带有全路径的节点名可以使用节点的别名比如“/backlight”就是 backlight 这个节点的全路径。 返回值:返回找到的节点如果为NULL表示查找失败。 2)、void __iomem *of_iomap(struct device_node *np, int index) np:设备节点。 index:reg属性中要完成内存映射的段如果reg属性只有一段的话则index0。 返回值:经过内存映射后的虚拟内存首地址如果为NULL的话则表示内存映射失败。 6.2、“设备树下的的GPIO驱动”的内存映射与读写操作 1)、打开虚拟机上“VSCode”点击“文件”点击“打开文件夹”点击“zgq”点击“linux”点击“atk-mp1”点击“linux”点击“my_linux”点击“linux-5.4.31”点击“确定”见下图 2)、点击“转到”点击“转到文件”输入“stm32mp157d-atk.dts回车”打开设备树文件stm32mp157d-atk.dts。 3)、在根节点“/”下创建一个名为“stm32mpl_1ed”的子节点添加内容如下 stm32mp1_led { compatible atkstm32mp1-led; /*设置属性compatible的值为atkstm32mp1-led*/ status okay;/*设置属性status的值为okay*/ reg 0X50000A28 0X04 /* RCC_MP_AHB4ENSETR */ 0X5000A000 0X04 /* GPIOI_MODER */ 0X5000A004 0X04 /* GPIOI_OTYPER */ 0X5000A008 0X04 /* GPIOI_OSPEEDR */ 0X5000A00C 0X04 /* GPIOI_PUPDR */ 0X5000A018 0X04 ; /* GPIOI_BSRR */ /*设置属性reg的值为0X50000A28 0X04 0X5000A000 0X04 0X5000A004 0X04 0X5000A008 0X04 0X5000A00C 0X04 0X5000A018 0X04*/ }; 见下图 4)、编译设备树 ①在VSCode终端输入“make dtbs回车”执行编译设备树 ②输入“ls arch/arm/boot/uImage -l” 查看是否生成了新的“uImage”文件 ③输入“ls arch/arm/boot/dts/stm32mp157d-atk.dtb -l” 查看是否生成了新的“stm32mp157d-atk.dtb”文件 5)、拷贝输出的文件 ①输入“cp arch/arm/boot/uImage /home/zgq/linux/atk-mp1/linux/bootfs/ -f回车”执行文件拷贝准备烧录到EMMC ②输入“cp arch/arm/boot/dts/stm32mp157d-atk.dtb /home/zgq/linux/atk-mp1/linux/bootfs/ -f回车”执行文件拷贝准备烧录到EMMC; ③输入“cp arch/arm/boot/uImage /home/zgq/linux/tftpboot/ -f回车”执行文件拷贝准备从tftp下载 ④输入“cp arch/arm/boot/dts/stm32mp157d-atk.dtb /home/zgq/linux/tftpboot/ -f回车”执行文件拷贝准备从tftp下载 ⑤输入“ls -l /home/zgq/linux/atk-mp1/linux/bootfs/回车”查看“/home/zgq/linux/atk-mp1/linux/bootfs/”目录下的所有文件和文件夹; ⑥输入“ls -l /home/zgq/linux/tftpboot/回车”查看“/home/zgq/linux/tftpboot/”目录下的所有文件和文件夹; ⑦输入“chmod 777 /home/zgq/linux/tftpboot/stm32mp157d-atk.dtb回车” 给“stm32mp157d-atk.dtb”文件赋予可执行权限; ⑧输入“chmod 777 /home/zgq/linux/tftpboot/uImage回车” ,给“uImage”文件赋予可执行权限; ⑨输入“ls /home/zgq/linux/tftpboot/回车”查看“/home/zgq/linux/tftpboot/”目录下的所有文件和文件夹; 6)、“设备树下的的GPIO驱动”的内存映射与读写操作举例 #include linux/types.h /* 数据类型重命名 使能bool,u8,u16,u32,u64, uint8_t, uint16_t, uint32_t, uint64_t 使能s8,s16,s32,s64,int8_t,int16_t,int32_t,int64_t */ #include linux/cdev.h //使能cdev结构 #include linux/device.h//使能class结构和device结构 #include linux/of.h    //使能device_node结构 #include linux/of_address.h //使能of_iomap() struct MyDtsLED_dev{ dev_t devid; /*声明32位变量devid用来给保存设备号 */ int major; /* 主设备号 */ int minor; /* 次设备号 */ struct cdev  cdev; /*字符设备结构变量cdev */ struct class *class; /* 类 */ struct device *device;/*设备*/ struct device_node *nd;/* 设备节点 */ }; struct MyDtsLED_dev strMyDtsLED; /* 映射后的寄存器虚拟地址指针 */ static void __iomem *MPU_AHB4_PERIPH_RCC_PI; /*RCC_MP_AHB4ENSETR寄存器*/ static void __iomem *GPIOI_MODER_PI; /*GPIOx_MODER寄存器xA to K, Z*/ static void __iomem *GPIOI_OTYPER_PI;/*GPIOx_OTYPERxA to K,Z*/ static void __iomem *GPIOI_OSPEEDR_PI;/*GPIOx_OSPEEDRxA to K, Z*/ static void __iomem *GPIOI_PUPDR_PI; /*GPIOx_PUPDRxA to K, Z*/ static void __iomem *GPIOI_BSRR_PI;/*GPIOx_BSRRxA to K, Z*/ /* 寄存器地址映射 */ int led_ioremap(void) { int ret; u32 regdata[12]; const char *str; struct property *proper; strMyDtsLED.nd of_find_node_by_path(/stm32mp1_led); //获取设备节点 //通过全路径“/stm32mp1_led”来查找stm32mp1_led节点 //“/stm32mp1_led”就是stm32mp1_led这个节点的全路径。 //返回值:返回找到的节点如果为NULL表示查找失败。 if(strMyDtsLED.nd NULL) return -EINVAL; MPU_AHB4_PERIPH_RCC_PI of_iomap(strMyDtsLED.nd, 0); //将“reg属性的第0段地址信息0X50000A28”转换为“虚拟地址” //npstrMyDtsLED.nd指定设备节点 //index0表示读取reg属性的第0段 //返回值:经过内存映射后的虚拟内存首地址如果为NULL的话则表示内存映射失败 GPIOI_MODER_PI of_iomap(strMyDtsLED.nd, 1); //将“reg属性的第1段地址信息0X5000A000”转换为“虚拟地址” //npstrMyDtsLED.nd指定设备节点 //index1表示读取reg属性的第1段 //返回值:经过内存映射后的虚拟内存首地址如果为NULL的话则表示内存映射失败 GPIOI_OTYPER_PI of_iomap(strMyDtsLED.nd, 2); //将“reg属性的第2段地址信息0X5000A004”转换为“虚拟地址” //npstrMyDtsLED.nd指定设备节点 //index2表示读取reg属性的第2段 //返回值:经过内存映射后的虚拟内存首地址如果为NULL的话则表示内存映射失败 GPIOI_OSPEEDR_PI of_iomap(strMyDtsLED.nd, 3); //将“reg属性的第3段地址信息0X5000A008”转换为“虚拟地址” //npstrMyDtsLED.nd指定设备节点 //index3表示读取reg属性的第3段 //返回值:经过内存映射后的虚拟内存首地址如果为NULL的话则表示内存映射失败 GPIOI_PUPDR_PI of_iomap(strMyDtsLED.nd, 4); //将“reg属性的第4段地址信息0X5000A00C”转换为“虚拟地址” //npstrMyDtsLED.nd指定设备节点 //index4表示读取reg属性的第4段 //返回值:经过内存映射后的虚拟内存首地址如果为NULL的话则表示内存映射失败 GPIOI_BSRR_PI of_iomap(strMyDtsLED.nd, 5); //将“reg属性的第5段地址信息0X5000A018”转换为“虚拟地址” //npstrMyDtsLED.nd指定设备节点 //index5表示读取reg属性的第5段 //返回值:经过内存映射后的虚拟内存首地址如果为NULL的话则表示内存映射失败 return 0; } /*取消“寄存器地址映射”*/ static void led_iounmap(void) { iounmap(MPU_AHB4_PERIPH_RCC_PI); //释放掉“虚拟内存中的首地址为MPU_AHB4_PERIPH_RCC_PI的数据块”即取消“物理地址”映射 iounmap(GPIOI_MODER_PI); //释放掉“虚拟内存中的首地址为GPIOI_MODER_PI的数据块”即取消“物理地址”映射 iounmap(GPIOI_OTYPER_PI); //释放掉“虚拟内存中的首地址为GPIOI_OTYPER_PI的数据块”即取消“物理地址”映射 iounmap(GPIOI_OSPEEDR_PI); //释放掉“虚拟内存中的首地址为GPIOI_OSPEEDR_PI的数据块”即取消“物理地址”映射 iounmap(GPIOI_PUPDR_PI); //释放掉“虚拟内存中的首地址为GPIOI_PUPDR_PI的数据块”即取消“物理地址”映射 iounmap(GPIOI_BSRR_PI); //释放掉“虚拟内存中的首地址为GPIOI_BSRR_PI的数据块”即取消“物理地址”映射 } //引脚初始化 void led_Pin_Init(void) { u32 val 0; val readl(MPU_AHB4_PERIPH_RCC_PI); /*从“虚拟地址”为MPU_AHB4_PERIPH_RCC_PI中读取4个字节即相当于读RCC_MP_AHB4ENSETR寄存器*/ val ~(0X1 8);val | (0X1 8);/* 设置bit81 */ writel(val, MPU_AHB4_PERIPH_RCC_PI); /* 将val的值(4字节)写入到“虚拟地址”为MPU_AHB4_PERIPH_RCC_PI的存储单元中即相当于将val的值写入RCC_MP_AHB4ENSETR寄存器 */ val readl(GPIOI_MODER_PI);/*读GPIOI_MODER寄存器*/ /*从“虚拟地址”为GPIOI_MODER_PI中读取4个字节即相当于读GPIOI_MODER寄存器*/ val ~(0X3 0);val | (0X1 0);/* bit0:1设置01配置为输出模式 */ writel(val, GPIOI_MODER_PI); /* 将val的值(4字节)写入到“虚拟地址”为GPIOI_MODER_PI的存储单元中即相当于将val的值写入GPIOI_MODER寄存器 */ val readl(GPIOI_OTYPER_PI);/*读GPIOI_OTYPER寄存器*/ /*从“虚拟地址”为GPIOI_OTYPER_PI中读取4个字节即相当于读GPIOI_OTYPER寄存器*/ val ~(0X1 0); /* bit0清零设置PI0为推挽模式*/ writel(val, GPIOI_OTYPER_PI); /* 将val的值(4字节)写入到“虚拟地址”为GPIOI_OTYPER_PI的存储单元中即相当于将val的值写入GPIOI_OTYPER寄存器 */ val readl(GPIOI_OSPEEDR_PI);/*读GPIOI_OSPEEDR寄存器*/ /*从“虚拟地址”为GPIOI_OSPEEDR_PI中读取4个字节即相当于读GPIOI_OSPEEDR寄存器*/ val ~(0X3 0); val | (0x3 0);/* bit0:1 设置为11极高速*/ writel(val, GPIOI_OSPEEDR_PI); /* 将val的值(4字节)写入到“虚拟地址”为GPIOI_OSPEEDR_PI的存储单元中即相当于将val的值写入GPIOI_OSPEEDR寄存器 */ val readl(GPIOI_PUPDR_PI);/*读GPIOI_PUPDR寄存器*/ /*从“虚拟地址”为GPIOI_PUPDR_PI中读取4个字节即相当于读GPIOI_PUPDR寄存器*/ val ~(0X3 0);val | (0x1 0); /*bit0:1 设置为01配置为上拉*/ writel(val,GPIOI_PUPDR_PI); /* 将val的值(4字节)写入到“虚拟地址”为GPIOI_PUPDR_PI的存储单元中即相当于将val的值写入GPIOI_PUPDR寄存器 */ val readl(GPIOI_BSRR_PI);/*读GPIOI_BSRR寄存器*/ /*从“虚拟地址”为GPIOI_BSRR_PI中读取4个字节即相当于读GPIOI_BSRR寄存器*/ val ~(0X1 16);val | (0x1 16);/*bit16 设置为1令PI0输出低电平*/ writel(val, GPIOI_BSRR_PI); /* 将val的值(4字节)写入到“虚拟地址”为GPIOI_BSRR_PI的存储单元中即相当于将val的值写入GPIOI_BSRR寄存器 */ val readl(GPIOI_BSRR_PI);/*读GPIOI_BSRR寄存器*/ /*从“虚拟地址”为GPIOI_BSRR_PI中读取4个字节即相当于读GPIOI_BSRR寄存器*/ val ~(0X1 0);val | (0x1 0); /*bit0 设置为1令PI0输出高电平*/ writel(val, GPIOI_BSRR_PI); /* 将val的值(4字节)写入到“虚拟地址”为GPIOI_BSRR_PI的存储单元中即相当于将val的值写入GPIOI_BSRR寄存器 */ } void led_switch(u8 sta) { u32 val 0; if(sta LEDON) { val readl(GPIOI_BSRR_PI); /*从“虚拟地址”为GPIOI_BSRR_PI中读取4个字节即相当于读GPIOI_BSRR寄存器*/ val ~(0X1 16); val | (0x1 16);/*bit16 设置为1令PI0输出低电平*/ writel(val, GPIOI_BSRR_PI); /* 将val的值(4字节)写入到“虚拟地址”为GPIOI_BSRR_PI的存储单元中即相当于将val的值写入GPIOI_BSRR寄存器 */ } else if(sta LEDOFF) { val readl(GPIOI_BSRR_PI); /*从“虚拟地址”为GPIOI_BSRR_PI中读取4个字节即相当于读GPIOI_BSRR寄存器*/ val ~(0X1 0);val | (0x1 0); /*bit0 设置为1令PI0输出高电平*/ writel(val, GPIOI_BSRR_PI); /* 将val的值(4字节)写入到“虚拟地址”为GPIOI_BSRR_PI的存储单元中即相当于将val的值写入GPIOI_BSRR寄存器 */ } } 7、pinctrl和gpio子系统下的GPIO驱动 “新字符设备的GPIO驱动”和“设备树下的GPIO驱动”都要用到寄存器地址使用非常不方便。于是Limux内核提供了pinctrl和gpio子系统用于GPIO驱动开发借助它可简化GPIO驱动开发。 7.1、pinctrl和gpio子系统下的函数 1)、inline struct device_node *of_find_node_by_path(const char *path) path:带有全路径的节点名可以使用节点的别名比如“/backlight”就是 backlight 这个节点的全路径。 返回值:返回找到的节点如果为NULL表示查找失败。 2)、int of_get_named_gpio(struct device_node *np, const char *propname, int index) //根据给定的“设备节点”读取GPIO编号 np指定的“设备节点”。 propname包含要获取GPIO信息的属性名 IndexGPIO索引因为一个属性里面可能包含多个GPIO此参数指定要获取哪个GPIO的编号如果只有一个GPIO信息的话此参数为0 返回值正值获取到的GPIO编号负值失败。 需要包含头文件#include linux/gpio.h 3)、申请“gpio编号” int gpio_request(unsigned gpio, const char *label) gpio要申请的“gpio编号” Iabel给这个gpio引脚设置个名字为label所指向的字符串 返回值0申请“gpio编号”成功;其他值申请“gpio编号”失败 注意GPIOA有16个引脚因此GA0的“gpio编号”为0GA15的“gpio编号”为15GPIOB有16个引脚因此GB0的“gpio编号”为16GB15的“gpio编号”为31GPIOC有16个引脚因此GC0的“gpio编号”为32GC15的“gpio编号”为47等等以此类推 4)、释放“gpio编号” void gpio_free(unsigned gpio) gpio要释放的“gpio编号” 7.2、pinctrl和gpio子系统下的GPIO驱动的内存映射与读写操 1)、打开虚拟机上“VSCode”点击“文件”点击“打开文件夹”点击“zgq”点击“linux”点击“atk-mp1”点击“linux”点击“my_linux”点击“linux-5.4.31”点击“确定”见下图 2)、点击“转到”点击“转到文件”输入“stm32mp157d-atk.dts回车”打开设备树文件stm32mp157d-atk.dts。 3)、在根节点“/”下创建一个名为“gpio_led”的子节点添加内容如下 led0{ compatible zgq,led; /*设置属性compatible的值为zgq,led*/ status okay;/*设置属性status的值为okay*/ led-gpio  gpioi 0 GPIO_ACTIVE_LOW; /*“gpioi”表示led-gpio引脚所使用的IO属于GPIOI组*/, /*“0’表示GPIOI组的第0号IO即PI0引脚*/ /*“GPIO_ACTIVE_LOW”表示低电平有效,“GPIO_PULL_UP”表示上拉*/ }; 4)、编译设备树 ①在VSCode终端输入“make dtbs回车”执行编译设备树 ②输入“ls arch/arm/boot/uImage -l” 查看是否生成了新的“uImage”文件 ③输入“ls arch/arm/boot/dts/stm32mp157d-atk.dtb -l” 查看是否生成了新的“stm32mp157d-atk.dtb”文件 5)、拷贝输出的文件 ①输入“cp arch/arm/boot/uImage /home/zgq/linux/atk-mp1/linux/bootfs/ -f回车”执行文件拷贝准备烧录到EMMC ②输入“cp arch/arm/boot/dts/stm32mp157d-atk.dtb /home/zgq/linux/atk-mp1/linux/bootfs/ -f回车”执行文件拷贝准备烧录到EMMC ③输入“cp arch/arm/boot/uImage /home/zgq/linux/tftpboot/ -f回车”执行文件拷贝准备从tftp下载 ④输入“cp arch/arm/boot/dts/stm32mp157d-atk.dtb /home/zgq/linux/tftpboot/ -f回车”执行文件拷贝准备从tftp下载 ⑤输入“ls -l /home/zgq/linux/atk-mp1/linux/bootfs/回车”查看“/home/zgq/linux/atk-mp1/linux/bootfs/”目录下的所有文件和文件夹 ⑥输入“ls -l /home/zgq/linux/tftpboot/回车”查看“/home/zgq/linux/tftpboot/”目录下的所有文件和文件夹 ⑦输入“chmod 777 /home/zgq/linux/tftpboot/stm32mp157d-atk.dtb回车” 给“stm32mp157d-atk.dtb”文件赋予可执行权限 ⑧输入“chmod 777 /home/zgq/linux/tftpboot/uImage回车” ,给“uImage”文件赋予可执行权限 ⑨输入“ls /home/zgq/linux/tftpboot/回车”查看“/home/zgq/linux/tftpboot/”目录下的所有文件和文件夹 5)、pinctrl和gpio子系统下的GPIO驱动的内存映射与读写操举例 #include linux/types.h /* 数据类型重命名 使能bool,u8,u16,u32,u64, uint8_t, uint16_t, uint32_t, uint64_t 使能s8,s16,s32,s64,int8_t,int16_t,int32_t,int64_t */ #include linux/cdev.h //使能cdev结构 #include linux/cdev.h //使能class结构和device结构 #include linux/of.h   //使能device_node结构 #include linux/of_gpio.h //使能of_gpio_named_count(),of_gpio_count(),of_get_named_gpio() #define LEDOFF 0 /* 关灯 */ #define LEDON 1 /* 开灯 */ struct MyGpioLED_dev{ dev_t devid; /*声明32位变量devid用来给保存设备号 */ int major; /* 主设备号 */ int minor; /* 次设备号 */ struct cdev  cdev; /*字符设备结构变量cdev */ struct class *class; /* 类 */ struct device *device;/*设备*/ struct device_node *nd;/* 设备节点 */ int led_gpio; /* led所使用的GPIO编号 */ }; struct MyGpioLED_dev strMyGpioLED; int Get_gpio_num(void) { int ret 0; const char *str; strMyGpioLED.nd of_find_node_by_path(/led0); //获取设备节点strMyGpioLED //path/led0使用“全路径的节点名“在“stm32mp157d-atk.dts“中查找节点“led0” //返回值:返回找到的节点如果为NULL表示查找失败。 if(strMyGpioLED.nd NULL) return -EINVAL; strMyGpioLED.led_gpio of_get_named_gpio(strMyGpioLED.nd, led-gpio, 0); //获取设备树中的gpio属性得到LED所使用的LED编号 //在led0节点中led-gpio gpioi 0 GPIO_ACTIVE_LOW //npstrMyGpioLED.nd,指定的“设备节点” //propnameled-gpio给定要读取的属性名字 //Index0,给定的GPIO索引为0 //返回值正值获取到的GPIO编号负值失败。 if(strMyGpioLED.led_gpio 0) return -EINVAL; printk(led-gpio num %d\r\n, strMyGpioLED.led_gpio); //打印结果为“led-gpio num 128“ //因为GPIO编号是从0开始的GPIOI端口的序号是8每个端口有16个IO口因此GPIOI0的编号为8*16128 return 0; } int led_GPIO_request(void) { int ret 0; ret gpio_request(strMyGpioLED.led_gpio, LED-GPIO); //向gpio子系统申请使用“gpio编号” //gpiostrMyGpioLED.led_gpio指定要申请的“gpio编号” //LabelLED-GPIO给这个gpio引脚设置个名字为LED-GPIO //返回值0申请“gpio编号”成功;其他值申请“gpio编号”失败 if (ret) return ret; ret gpio_direction_output(strMyGpioLED.led_gpio, 1); //设置PI0为输出并且输出高电平默认关闭LED灯 //gpiostrMyGpioLED.led_gpio,指定的“gpio编号”这里是128对应的是GI0引脚 //value1设置引脚输出高电平 //返回值0设置“引脚输出为vakued的值”成功;负值设置“引脚输出为vakued的值”失败。 if(ret 0) { printk(cant set gpio!\r\n); return ret; } return 0; } void led_switch(u8 sta,struct MyGpioLED_dev *dev) { if(sta LEDON) { gpio_set_value(dev-led_gpio, 0); /* 打开LED灯 */ } else if(sta LEDOFF) { gpio_set_value(dev-led_gpio, 1); /* 关闭LED灯 */ } } //函数功能释放MyGpioLED的gpio void MyLED_free(void) { gpio_free(strMyGpioLED.led_gpio); } 通过比较我们发现“新字符设备的GPIO驱动”和“设备树下的GPIO驱动”都要用到寄存器地址使用“物理内存”和“虚拟内存”映射时非常不方便而pinctrl和gpio子系统的GPIO驱动非常简化。因此要重点学习pinctrl和gpio子系统下的GPIO驱动开发。
http://www.w-s-a.com/news/411302/

相关文章:

  • 应用网站如何做营销型网站的重要特点
  • 怎么样百度搜到自己的网站加强社区网站建设
  • 建设网站所需技术wordpress延时加载js
  • 网站建设沈阳搜云seo
  • 怎么申请免费的网站空间微信公众平台注册收费吗
  • 东营网站搭建最基本的网站设计
  • 网站建设技术的发展最近的国际新闻大事
  • 德州有名的网站建设公司网站如何做引流
  • 建设一个收入支出持平的网站网络推广计划书格式
  • 什么是网站黑链全球新冠疫苗接种率
  • 网站开发 chrome gimp网站不备案做seo没用
  • 织梦校园招生网站源码沪佳哪个好
  • 建设企业网站可信度软件产品如何做网站推广
  • 网站建设企业号助手贵阳景观设计公司
  • 网站开发第三方建设银行个人网站显示不了
  • 无锡兼职做网站郑州网站建设搜索优化
  • iis禁止通过ip访问网站品牌策划案例ppt
  • 电子商务网站建设实习seo黑帽优化
  • 如何做好网站建设销售闸北集团网站建设
  • 重庆装饰公司北京官网seo推广
  • 深圳网站设计灵点网络品牌网站充值接口
  • 建设书局 网站国内国际时事图片
  • 成都 网站建设培训学校屏蔽wordpress自带编辑器
  • 公司网站制作工作室中天建设集团有限公司第五建设公司
  • 网站的网页设计毕业设计苏州宣传册设计广告公司
  • 商城网站优化方案注册公司制作网站
  • 政务服务网站建设整改报告wordpress的导航代码
  • 图片素材网站建设做教育网站用什么颜色
  • 快站淘客中转页wordpress商业插件
  • 可信网站网站认证免费软件下载网站免费软件下载网站