1450|0

469

帖子

3

TA的资源

五彩晶圆(初级)

楼主
 

【正点原子RV1126 AI Linux开发板】 GPIO驱动程序测试 [复制链接]

  本帖最后由 TL-LED 于 2024-3-29 15:07 编辑

编写字符驱动程序,测试下GPIO口的输出。

 

一、硬件部分

 

测试使用端口GPIO0_A4,开发板端口电路图如下:

 

二、硬件驱动分析

 

开发上LED端口对应的是GPIO3_D4端口,驱动程序也是配置这个端口测试的,下里面来分析下使用GPIO0_A4端口怎么配置。

开发板主芯片资料有些地方没有看太明白,根据芯片手册和开发板教程来理解测试。

配置端口需要配置以下方面:

 

PMUGRF_GPIO0A_IOMUX_H和PMUGRF_GPIO0A_DS_H寄存器来配置GPIO0_A4~GPIO0_A7端口的复用功能和驱动能力,下面是的偏移地址。

 

2.1、端口引脚复用配置

寄存器PMUGRF_GPIO0A_IOMUX_H的配置gpio0_A4选择GPIO功能,write_enable相应的为置1后,可以写入寄存器。

 

2.2、端口驱动能力配置

寄存器MUGRF_GPIO0A_DS_H的配置gpio0_A4_ds选择端口的驱动能力,这部分手册上也没有找到介绍,这里选择默认0。

write_enable相应的为置1后,可以写入寄存器。

 

2.3、GPIO输入输出设置

设置寄存器GPIO0_SWPORT_DDR_L

 

2.4、GPIO数据寄存器

端口的输入输出电平在寄存器GPIO0_SWPORT_DR_L中设置或读取

 

关于GPIO方向和输入\输出的电平设置可以参考开发板驱动手册中有管的讲解。

 

三、程序

 

3.1、驱动程序dev_led_n.c

  • //dev_led.c
  • #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/fs.h>
  • #include <linux/kdev_t.h>
  • #include <linux/cdev.h>
  • #include <linux/device.h>
  • #include <linux/errno.h>
  • #include <asm/io.h>
  • #define DEVICE_NUMBER 1 //定义次设备号的个数
  • #define DEVICE_NAME "dev_led_n" //设备名字
  • struct chr_dev_led
  • {
  • dev_t devid;
  • struct cdev cdev; //定义一个 cdev 结构体
  • struct class *class; //定义类
  • struct device *device; //设备
  • int major; //主设备号
  • int minor; //次设备号
  • };
  • struct chr_dev_led new_chr_dev_led; //设备
  • //#define DEV_LED_MAJOR 200 /* 主设备号 */
  • #define LEDOFF 0 /* 关灯 */
  • #define LEDON 1 /* 开灯 */
  • #define GRF_BASE (0XFE000000)
  • #define GRF_GPIO3D_IOMUX_H (GRF_BASE + 0X1006C)
  • #define GRF_GPIO3D_DS_H (GRF_BASE + 0X100EC)
  • #define GPIO3_BASE (0XFF640000)
  • #define GPIO3_SWPORT_DR_H (GPIO3_BASE + 0X0004)
  • #define GPIO3_SWPORT_DDR_H (GPIO3_BASE + 0X000C)
  • #define PMUGRF_BASE (0XFE020000)
  • #define PMUGRF_GPIO0A_IOMUX_L (PMUGRF_BASE + 0X0000)
  • #define PMUGRF_GPIO0A_IOMUX_H (PMUGRF_BASE + 0X0004)
  • #define PMUGRF_GPIO0A_DS_L (PMUGRF_BASE + 0X0020)
  • #define PMUGRF_GPIO0A_DS_H (PMUGRF_BASE + 0X0024)
  • #define GPIO0_BASE (0XFF460000)
  • #define GPIO0_SWPORT_DR_L (GPIO0_BASE + 0X0000)
  • #define GPIO0_SWPORT_DR_H (GPIO0_BASE + 0X0004)
  • #define GPIO0_SWPORT_DDR_L (GPIO0_BASE + 0X0008)
  • #define GPIO0_SWPORT_DDR_H (GPIO0_BASE + 0X000C)
  • /* 映射后的寄存器虚拟地址指针 */
  • static void __iomem *GRF_GPIO3D_IOMUX_H_PI;
  • static void __iomem *GRF_GPIO3D_DS_H_PI;
  • static void __iomem *GPIO3_SWPORT_DR_H_PI;
  • static void __iomem *GPIO3_SWPORT_DDR_H_PI;
  • static void __iomem *PMUGRF_GPIO0A_IOMUX_L_PI;
  • static void __iomem *PMUGRF_GPIO0A_IOMUX_H_PI;
  • static void __iomem *PMUGRF_GPIO0A_DS_L_PI;
  • static void __iomem *PMUGRF_GPIO0A_DS_H_PI;
  • static void __iomem *GPIO0_SWPORT_DR_L_PI;
  • static void __iomem *GPIO0_SWPORT_DR_H_PI;
  • static void __iomem *GPIO0_SWPORT_DDR_L_PI;
  • static void __iomem *GPIO0_SWPORT_DDR_H_PI;
  • void led_switch(u8 sta)
  • {
  • u32 val = 0;
  • if(sta == LEDON) {
  • val = readl(GPIO3_SWPORT_DR_H_PI);
  • val &= ~(0X1 << 12); /* bit12 清零*/
  • val |= ((0X1 << 28) | (0X1 << 12)); /* bit28 置1,允许写bit12,
  • bit12,低电平 */
  • writel(val, GPIO3_SWPORT_DR_H_PI);
  • //--------------------------------------------
  • val = readl(GPIO0_SWPORT_DR_L_PI);
  • val &= ~(0X1 << 4);
  • val |= ((0X1 << 20) | (0X1 << 4));
  • writel(val, GPIO0_SWPORT_DR_L_PI);
  • }else if(sta == LEDOFF) {
  • val = readl(GPIO3_SWPORT_DR_H_PI);
  • val &= ~(0X1 << 12); /* bit12 清零*/
  • val |= ((0X1 << 28) | (0X0 << 12)); /* bit28 置1,允许写bit12,
  • bit12,低电平 */
  • writel(val, GPIO3_SWPORT_DR_H_PI);
  • //--------------------------------------------
  • val = readl(GPIO0_SWPORT_DR_L_PI);
  • val &= ~(0X1 << 4);
  • val |= ((0X1 << 20) | (0X0 << 4));
  • writel(val, GPIO0_SWPORT_DR_L_PI);
  • }
  • }
  • /*
  • * @description : 物理地址映射
  • * @return : 无
  • */
  • void led_remap(void)
  • {
  • GRF_GPIO3D_IOMUX_H_PI = ioremap(GRF_GPIO3D_IOMUX_H, 4);
  • GRF_GPIO3D_DS_H_PI = ioremap(GRF_GPIO3D_DS_H, 4);
  • GPIO3_SWPORT_DR_H_PI = ioremap(GPIO3_SWPORT_DR_H, 4);
  • GPIO3_SWPORT_DDR_H_PI = ioremap(GPIO3_SWPORT_DDR_H, 4);
  • //GPIO0_A
  • PMUGRF_GPIO0A_IOMUX_H_PI = ioremap(PMUGRF_GPIO0A_IOMUX_H, 4);
  • PMUGRF_GPIO0A_IOMUX_L_PI = ioremap(PMUGRF_GPIO0A_IOMUX_L, 4);
  • PMUGRF_GPIO0A_DS_L_PI = ioremap(PMUGRF_GPIO0A_DS_L, 4);
  • PMUGRF_GPIO0A_DS_H_PI = ioremap(PMUGRF_GPIO0A_DS_H, 4);
  • GPIO0_SWPORT_DR_L_PI = ioremap(GPIO0_SWPORT_DR_L, 4);
  • GPIO0_SWPORT_DR_H_PI = ioremap(GPIO0_SWPORT_DR_H, 4);
  • GPIO0_SWPORT_DDR_L_PI = ioremap(GPIO0_SWPORT_DDR_L, 4);
  • GPIO0_SWPORT_DDR_H_PI = ioremap(GPIO0_SWPORT_DDR_H, 4);
  • }
  • /*
  • * @description : 取消映射
  • * @return : 无
  • */
  • void led_unmap(void)
  • {
  • /* 取消映射 */
  • iounmap(GRF_GPIO3D_IOMUX_H_PI);
  • iounmap(GRF_GPIO3D_DS_H_PI);
  • iounmap(GPIO3_SWPORT_DR_H_PI);
  • iounmap(GPIO3_SWPORT_DDR_H_PI);
  • iounmap(PMUGRF_GPIO0A_IOMUX_H_PI);
  • iounmap(PMUGRF_GPIO0A_IOMUX_L_PI);
  • iounmap(PMUGRF_GPIO0A_DS_H_PI);
  • iounmap(PMUGRF_GPIO0A_DS_L_PI);
  • iounmap(GPIO0_SWPORT_DR_L_PI);
  • iounmap(GPIO0_SWPORT_DR_H_PI);
  • iounmap(GPIO0_SWPORT_DDR_L_PI);
  • iounmap(GPIO0_SWPORT_DDR_H_PI);
  • }
  • static int dev_led_open(struct inode *inode, struct file *filp)
  • {
  • filp->private_data = &new_chr_dev_led; //设置私有数据
  • return 0;
  • }
  • static ssize_t dev_led_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
  • {
  • return 0;
  • }
  • static ssize_t dev_led_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
  • {
  • int retvalue;
  • 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); /* 打开LED灯 */
  • } else if(ledstat == LEDOFF) {
  • led_switch(LEDOFF); /* 关闭LED灯 */
  • }
  • return 0;
  • }
  • static int dev_led_release(struct inode *inode, struct file *filp)
  • {
  • return 0;
  • }
  • /*
  • * 设备操作函数结构体
  • */
  • static struct file_operations dev_led_fops = {
  • .owner = THIS_MODULE,
  • .open = dev_led_open,
  • .read = dev_led_read,
  • .write = dev_led_write,
  • .release = dev_led_release,
  • };
  • static int __init dev_led_init(void)
  • {
  • int retvalue = 0;
  • u32 val = 0;
  • /* 初始化LED */
  • /* 1、寄存器地址映射 */
  • led_remap();
  • /* 2、设置GPIO3_D4为GPIO功能。*/
  • val = readl(GRF_GPIO3D_IOMUX_H_PI);
  • val &= ~(0X7 << 0); /* bit2:0,清零 */
  • val |= ((0X7 << 16) | (0X0 << 0)); /* bit18:16 置1,允许写bit2:0,
  • bit2:0:0,用作GPIO3_D4 */
  • writel(val, GRF_GPIO3D_IOMUX_H_PI);
  • /* 3、设置GPIO3_D4驱动能力为level0 */
  • val = readl(GRF_GPIO3D_DS_H_PI);
  • val &= ~(0XF << 0); /* bit3:0清零*/
  • val |= ((0XF << 16) | (0X0 << 0)); /* bit19:16 置1,允许写bit3:0,
  • bit2:0:0,用作GPIO3_D4 */
  • writel(val, GRF_GPIO3D_DS_H_PI);
  • /* 4、设置GPIO3_D4为输出 */
  • val = readl(GPIO3_SWPORT_DDR_H_PI);
  • val &= ~(0X1 << 12); /* bit12 清零*/
  • val |= ((0X1 << 28) | (0X1 << 12)); /* bit28 置1,允许写bit12,
  • bit12,高电平 */
  • writel(val, GPIO3_SWPORT_DDR_H_PI);
  • /* 5、设置GPIO3_D4为低电平,关闭LED灯。*/
  • val = readl(GPIO3_SWPORT_DR_H_PI);
  • val &= ~(0X1 << 12); /* bit12 清零*/
  • val |= ((0X1 << 28) | (0X1 << 12)); /* bit28 置1,允许写bit12,
  • bit12,低电平 */
  • writel(val, GPIO3_SWPORT_DR_H_PI);
  • //-----------------------------------------------------------------------
  • //GPIO0_A--GPIO设置为GPIO功能
  • val = readl(PMUGRF_GPIO0A_IOMUX_H_PI);
  • val &= ~(0X7 << 0); /* bit2:0,清零 */
  • val |= ((0X7 << 16) | (0X0 << 0)); /* bit18:16 置1,允许写bit2:0,
  • bit2:0:0,用作GPIO0_A0 */
  • writel(val, PMUGRF_GPIO0A_IOMUX_H_PI);
  • //val = readl(PMUGRF_GPIO0A_IOMUX_L_PI);
  • //printk("PMUGRF_GPIO0A_IOMUX_L_PI=0x%x\r\n",val);
  • //设置GPIO0_A0驱动能力为level0
  • val = readl(PMUGRF_GPIO0A_DS_H_PI);
  • val &= ~(0XF << 0); /* bit3:0清零*/
  • val |= ((0XF << 16) | (0X0 << 0));
  • writel(val, PMUGRF_GPIO0A_DS_H_PI);
  • //设置GPIO0_A0为输出
  • val = readl(GPIO0_SWPORT_DDR_L_PI);
  • val &= ~(0X1 << 4); /* bit0 清零*/
  • val |= ((0X1 << 20) | (0X1 << 4));
  • writel(val, GPIO0_SWPORT_DDR_L_PI);
  • //val = readl(GPIO0_SWPORT_DDR_L_PI);
  • //printk("GPIO0_SWPORT_DDR_L_PI=0x%x\r\n",val);
  • //设置GPIO0_A0为低电平
  • val = readl(GPIO0_SWPORT_DR_L_PI);
  • val &= ~(0X1 << 4);
  • val |= ((0X1 << 20) | (0X1 << 4));
  • writel(val, GPIO0_SWPORT_DR_L_PI);
  • //printk("GPIO0_SWPORT_DR_L_PI=0x%x\r\n",val);
  • //-----------------------------------------------------------------------
  • //注册字符设备驱动
  • //创建设备号
  • if (new_chr_dev_led.major)
  • {
  • new_chr_dev_led.devid = MKDEV(new_chr_dev_led.major, 0);
  • retvalue = register_chrdev_region(new_chr_dev_led.devid, DEVICE_NUMBER, DEVICE_NAME);
  • if(retvalue < 0)
  • {
  • //printk("register chrdev failed!\r\n");
  • pr_err("cannot register %s char driver [ret=%d]\n",DEVICE_NAME, DEVICE_NUMBER);
  • goto fail_map;
  • }
  • }
  • else
  • {
  • retvalue = alloc_chrdev_region(&new_chr_dev_led.devid, 0, DEVICE_NUMBER, DEVICE_NAME);
  • if(retvalue < 0)
  • {
  • //printk("register chrdev failed!\r\n");
  • pr_err("%s Couldn't alloc_chrdev_region, ret=%d\r\n", DEVICE_NAME, retvalue);
  • goto fail_map;
  • }
  • new_chr_dev_led.major = MAJOR(new_chr_dev_led.devid);
  • new_chr_dev_led.minor = MINOR(new_chr_dev_led.devid);
  • }
  • printk(" major=%d,minor=%d\r\n",new_chr_dev_led.major,new_chr_dev_led.minor);
  • //初始化cdev
  • new_chr_dev_led.cdev.owner = THIS_MODULE;
  • cdev_init(&new_chr_dev_led.cdev, &dev_led_fops);
  • //添加cdev
  • retvalue = cdev_add(&new_chr_dev_led.cdev, new_chr_dev_led.devid, DEVICE_NUMBER);
  • if(retvalue < 0)
  • {
  • goto del_unregister;
  • }
  • //创建类
  • new_chr_dev_led.class = class_create(THIS_MODULE, DEVICE_NAME);
  • if(IS_ERR(new_chr_dev_led.class))
  • {
  • goto del_cdev;
  • }
  • //创建设备
  • new_chr_dev_led.device = device_create(new_chr_dev_led.class, NULL,new_chr_dev_led.devid, NULL, DEVICE_NAME);
  • if (IS_ERR(new_chr_dev_led.device))
  • {
  • goto destroy_class;
  • }
  • return 0;
  • destroy_class:
  • class_destroy(new_chr_dev_led.class);
  • del_cdev:
  • cdev_del(&new_chr_dev_led.cdev);
  • del_unregister:
  • unregister_chrdev_region(new_chr_dev_led.devid, DEVICE_NUMBER);
  • fail_map:
  • led_unmap();
  • return -EIO;
  • }
  • static void __exit dev_led_exit(void)
  • {
  • u32 val=0;
  • //--------------------------------------------------------------------------
  • val = readl(GPIO3_SWPORT_DR_H_PI);
  • val &= ~(0X1 << 12); /* bit12 清零*/
  • val |= ((0X1 << 28) | (0X0 << 12)); /* bit28 置1,允许写bit12,
  • bit12,低电平 */
  • writel(val, GPIO3_SWPORT_DR_H_PI);
  • val = readl(GPIO0_SWPORT_DR_L_PI);
  • val &= ~(0X1 << 4); /* bit12 清零*/
  • val |= ((0X1 << 20) | (0X0 << 4)); /* bit28 置1,允许写bit12,
  • bit12,低电平 */
  • writel(val, GPIO0_SWPORT_DR_L_PI);
  • //--------------------------------------------------------------------------
  • //取消映射
  • led_unmap();
  • //注销字符设备驱动
  • cdev_del(&new_chr_dev_led.cdev);//删除cdev
  • unregister_chrdev_region(new_chr_dev_led.devid, DEVICE_NUMBER); //注销设备号
  • device_destroy(new_chr_dev_led.class, new_chr_dev_led.devid);
  • class_destroy(new_chr_dev_led.class);
  • }
  • /*
  • * 将上面两个函数指定为驱动的入口和出口函数
  • */
  • module_init(dev_led_init);
  • module_exit(dev_led_exit);
  • /*
  • * LICENSE和作者信息
  • */
  • MODULE_LICENSE("GPL");
  • MODULE_AUTHOR("ALIENTEK");
  • MODULE_INFO(intree, "Y");

 

3.2、应用程序

  • #include "stdio.h"
  • #include "unistd.h"
  • #include "sys/types.h"
  • #include "sys/stat.h"
  • #include "fcntl.h"
  • #include "stdlib.h"
  • #include "string.h"
  • #define LEDOFF 0
  • #define LEDON 1
  • int main(int argc, char *argv[])
  • {
  • int fd, retvalue;
  • char *filename;
  • unsigned char ledbuf[1];
  • if(argc != 3){
  • printf("Error Usage!\r\n");
  • return -1;
  • }
  • filename = argv[1];
  • /* 打开驱动文件 */
  • fd = open(filename, O_RDWR);
  • if(fd < 0){
  • printf("Can't open file %s\r\n", filename);
  • return -1;
  • }
  • ledbuf[0]=atoi(argv[2]);
  • retvalue = write(fd, ledbuf, sizeof(ledbuf));
  • if(retvalue < 0){
  • printf("write file led failed!\r\n");
  • close(fd);
  • return -1;
  • }
  • retvalue = close(fd);
  • if(retvalue < 0){
  • printf("Can't close file %s\r\n", filename);
  • return -1;
  • }
  • return 0;
  • }

 

四、运行

 

4.1、复制文件到开发板

root@ubuntu:/opt/atk-rv1126_app/led_test_n# scp dev_led_n.ko root@192.168.1.117:/lib/modules/4.19.111/
root@ubuntu:/opt/atk-rv1126_app/led_test_n# scp dev_led_app_n root@192.168.1.117:/lib/modules/4.19.111/

 

4.2、加载模块

[root@ATK-DLRV1126:/lib/modules/4.19.111]# modprobe dev_led_n
加载的的模块

 

自动创建的设备号

 

4.3、控制GPIO口输出

[root@ATK-DLRV1126:/lib/modules/4.19.111]# ./dev_led_app_n /dev/dev_led_n 0
[root@ATK-DLRV1126:/lib/modules/4.19.111]# ./dev_led_app_n /dev/dev_led_n 1


使用示波器查看GPIO0_A4引脚输出电平信号。

点赞 关注
 
 

回复
举报
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条
有奖直播 | AI之眼——安森美图像传感器 报名中
直播时间:2025年4月25日(周五)上午10:00-11:30
直播主题:AI之眼——安森美图像传感器
报名观看直播、直播间提问、填写问卷均有机会获得精美礼品!

查看 »

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网 13

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表