请选择 进入手机版 | 继续访问电脑版

你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

Stm32mp157A-DK1评估Linux LED驱动-4 gpio子系统

[复制链接]
寒门过河卒 发布时间:2021-7-1 10:49
我们之前的程序都是对需要的gpio寄存器地址进行映射,从而实现对gpio口的配置,在Linux内核中可以调用某些API接口实现对gpio口的设置,这就是gpio子系统。
可以将设备树下的led节点改为:
stm32mp1_led {
              compatible= "stm32mp1-led";
              status= "okay";
              reg= <0X50000A28 0X04 /* RCC_MP_AHB4ENSETR */
              0X500020000X04 /* GPIOI_MODER */
              0X500020040X04 /* GPIOI_OTYPER */
              0X500020080X04 /* GPIOI_OSPEEDR */
              0X5000200C0X04 /* GPIOI_PUPDR */
              0X500020180X04 >; /* GPIOI_BSRR */
      };
改为,其中改了个名字,compatible改为”name,led”否则申请不到该设备,reg原来为映射地址,此处改为led-gpio,在gpio子系统中直接设置io信息。
       xhy_led{
              compatible= "xhy,led";
              status= "okay";
              led-gpio= <&gpioa 14 GPIO_ACTIVE_LOW>;
      };  
然后重新编译.dtb文件:
make ARCH=armCROSS_COMPILE=arm-none-linux-gnueabihf- dtbs
然后将dts/stm32mp157a-dk1.dtb复制到tftp文件夹中:
cp arch/arm/boot/dts/stm32mp157a-dk1.dtb/home/helloxhy/tftp/ -rf
板子重启后可以在超级终端上面查询到修改后的设备树信息:
ls /proc/device-tree/
QQ图片20210701104230.png
接下来写驱动程序:
首先加入子系统需要的头文件:
#include <linux/of_gpio.h>
然后把地址映射的指针所有信息删除:
/*
static void __iomem*MPU_AHB4_PERIPH_RCC_PI;
static void __iomem *GPIOI_MODER_PI;
static void __iomem *GPIOI_OTYPER_PI;
static void __iomem *GPIOI_OSPEEDR_PI;
static void __iomem *GPIOI_PUPDR_PI;
static void __iomem *GPIOI_BSRR_PI;
*/
接下来在设备结构体中添加节点的gpio编号:
struct newchrled_dev{
        dev_t devid; /*  设备号 */
        struct cdev cdev; /* cdev */
        struct class *class; /*  类 */
        struct device *device; /*  设备 */
        int major; /* 主设备号 */
        int minor; /* 次设备号 */
        struct device_node *nd; /* 在设备结构体中添加设备节点 */
        int led_gpio; /* led 所使用的 GPIO 编号 */
};
然后在led_write中修改对GPIOI_BSRR_PI的操作,改为对设备节点的操作,直接调用API接口gpio_set_value:
gpio_set_value(dev->led_gpio, 1);     //关闭LED
gpio_set_value(dev->led_gpio, 0);     //开启LED
接下来对led_init进行修改,不需要做寄存器映射和寄存器操作了,直接在设备树节点上面的信息进行获取然后调用API进行操作就可以了。
首先把映射和寄存器操作全部删除:
       MPU_AHB4_PERIPH_RCC_PI= of_iomap(newchrled.nd, 0);
       GPIOI_MODER_PI= of_iomap(newchrled.nd, 1);
       GPIOI_OTYPER_PI= of_iomap(newchrled.nd, 2);
       GPIOI_OSPEEDR_PI= of_iomap(newchrled.nd, 3);
       GPIOI_PUPDR_PI= of_iomap(newchrled.nd, 4);
       GPIOI_BSRR_PI= of_iomap(newchrled.nd, 5);
        //2、时钟配置打开对应寄存器的时钟,查阅手册第866页,GPIOA为寄存器的第0位
       val= readl(MPU_AHB4_PERIPH_RCC_PI);
       val&= ~(0X1 << 0);     // 清除以前的设置
       val|= (0X1 << 0);      // 设置新值
       writel(val,MPU_AHB4_PERIPH_RCC_PI);
       /*2、设置GPIOI_MODER_PI寄存器,查阅手册第1072页13.4.1,PA14设置第28、29两个字节。
       00:输入模式
       01:输出模式
       10:复用模式
       11:模拟模式
       *//*
       val= readl(GPIOI_MODER_PI);
       val&= ~(0X3 << 28);   // bit0:1清零
       val|= (0X1 << 28);       // bit0:1设置01
       writel(val,GPIOI_MODER_PI);
       /*3、设置GPIOI_OTYPER_PI寄存器,查阅手册第1072页13.4.2,PA14设置第14字节。
       0:推览输出
       1:上拉模式
       *//*
       val= readl(GPIOI_OTYPER_PI);
       val&= ~(0X1 << 14);   /* bit0清零,设置为上拉*/
       /*writel(val,GPIOI_OTYPER_PI);
       /*4、设置GPIOI_ OSPEEDR _PI寄存器,查阅手册第1073页13.4.3,PA14设置第28、29两个字节
       设置IO口速度:
       00ow speed
       01:Medium speed
       10:High speed
       11:Very high speed
       *//*
       val= readl(GPIOI_OSPEEDR_PI);
       val&= ~(0X3 << 28); /* bit0:1 清零 */
       /*val|= (0x2 << 28); /* bit0:1 设置为10*/
       /*writel(val,GPIOI_OSPEEDR_PI);
       /*5、设置GPIOI_ PUPDR寄存器,查阅手册第1073页13.4.4,PA14设置第28、29两个字节。
       配置I/O上拉或下拉
       00:禁止上拉、下拉
       01:上拉
       10:下拉
       11:保留
       */
       /*val= readl(GPIOI_PUPDR_PI);
       val&= ~(0X3 << 28); /* bit0:1 清零*/
       /*val|= (0x1 << 28); /*bit0:1 设置为01*/
       /*writel(val,GPIOI_PUPDR_PI);
       /*6、设置GPIOI_ BSRR寄存器,查阅手册第1074页13.4.7,PA14设置第14、30两个字节。
       用来设置IO的开关
        */
       ////val= readl(GPIOI_BSRR_PI);
       //val|= (0x1 << 14);     
       //writel(val,GPIOI_BSRR_PI);
接下来对设备数进行读取,依然把获取的信息放在.nd中:
newchrled.nd =of_find_node_by_path("/xhy_led");  
然后获取设备树的compatible信息"xhy,led":        
       proper= of_find_property(newchrled.nd, "compatible", NULL);
获取status 属性内容"okay":
ret =of_property_read_string(newchrled.nd, "status", &str);
原来的程序时获取reg信息,此时已经改为led-gpio,所以此处获取gpio属性<&gpioa 14 GPIO_ACTIVE_LOW>:
newchrled.led_gpio =of_get_named_gpio(newchrled.nd, "led-gpio", 0);
获取到led-gpiod 编号和信息,下一步需要调用API使申请到的信息起作用,此处发现一个问题,compatible参数如果不为name,name2格式的话会报错:
ret = gpio_request(newchrled.led_gpio,"LED-GPIO");
然后设备便起作用了,接下来进行操作就可以了:
gpio_direction_output(newchrled.led_gpio,1);
另外需要把led_init和led_exit解除映射改为清除gpio:
iounmap(MPU_AHB4_PERIPH_RCC_PI);
       iounmap(GPIOI_MODER_PI);
       iounmap(GPIOI_OTYPER_PI);
       iounmap(GPIOI_OSPEEDR_PI);
       iounmap(GPIOI_PUPDR_PI);
       iounmap(GPIOI_BSRR_PI);*/
改为:
gpio_free(newchrled.led_gpio);
led-gpio.rar (31.01 KB, 下载次数: 0)
收藏 评论0 发布时间:2021-7-1 10:49

举报

0个回答
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版