欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  网络运营

海思hi3516ev200GPIO驱动开发

程序员文章站 2022-07-03 09:10:02
继续上个文章海思hi3516ev200引脚GPIO直接输出高低电平,本次使用linux驱动来对GPIO进行控制。1、linux驱动开发,驱动代码如下(参考其他代码修改):#include #include #include #include #include #include <...

继续上个文章海思hi3516ev200引脚GPIO直接输出高低电平,本次使用linux驱动来对GPIO进行控制。

1、linux驱动开发,驱动代码如下(参考其他代码修改):

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>

#define DEV_NAME "led"

/* led */
#define GPIO6_BASE_ADDR          	0x120b6000
#define GPIO6_DIR_ADDR            ((GPIO6_BASE_ADDR) + (0x400))
#define GPIO6_DATA_OUT_ADDR       ((GPIO6_BASE_ADDR) + (0x000))
#define GPIO6_7_SET_DATA__ADDR    ((GPIO6_DATA_OUT_ADDR) + (0x200))


volatile unsigned long *gpio6_dir = NULL;
volatile unsigned long *gpio6_dataout = NULL;
volatile unsigned long *gpio6_setdata = NULL;
/* led end */

static int major = (-1); /* 初始化为无效值 */
static struct class *led_drv_class;

static int led_drv_open(struct inode *inode, struct file *file)
{
    /* 将dir寄存器bit7置1:表示output功能 */
    *gpio6_dir |= (1<<7);

    return 0;
}

static int led_drv_release(struct inode *pinode , struct file *pfile)
{
    /* 将data寄存器置1,表示输出高电平 */
    //*gpio6_setdata = (1<<7);

    return 0;
}

static ssize_t led_drv_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
	char val;
	int ret;
	
	ret = copy_from_user(&val, buf, count);
	
	if(!ret)
	{
		*gpio6_setdata = val;
	}
    	

    return 0;
}

static struct file_operations led_drv_fops = {
    .owner   = THIS_MODULE,
    .open    = led_drv_open,
    .release = led_drv_release,
    .write   = led_drv_write,
};

/* 驱动入口函数 */
static int led_drv_init(void)
{
    major = register_chrdev(0, "led_drv", &led_drv_fops); // 注册, 告诉内核,返回值major为自动分配的主设备号

    led_drv_class = class_create(THIS_MODULE, "leddrv");
    device_create(led_drv_class, NULL, MKDEV(major, 0), NULL, DEV_NAME); /* insmod xxx后,会自动生成/dev/xyz设备,并且自动给该设备分配主设备号major */

    /* 映射寄存器地址 */
    gpio6_dir      = (volatile unsigned long *)ioremap(GPIO6_DIR_ADDR, 32);
    gpio6_dataout = (volatile unsigned long *)ioremap(GPIO6_DATA_OUT_ADDR, 32);
    gpio6_setdata = (volatile unsigned long *)ioremap(GPIO6_7_SET_DATA__ADDR, 32);

    return 0;
}

/* 驱动出口函数 */
static void led_drv_exit(void)
{
    unregister_chrdev(major, "led_drv"); /* 卸载驱动程序,告诉内核 */

    device_destroy(led_drv_class, MKDEV(major, 0));
    class_destroy(led_drv_class);

    /* 删除映射关系 */
    iounmap(gpio6_setdata);
    iounmap(gpio6_dataout);
    iounmap(gpio6_dir);
}

module_init(led_drv_init);
module_exit(led_drv_exit);

MODULE_LICENSE("Dual BSD/GPL"); 

其中GPIO6_BASE_ADDR为0x120b6000,可以先去阅读前个文章直接对寄存器操作内容;对应配置好方向寄存器基地址和数据寄存器基地址,再通过ioremap把物理地址转换为虚拟地址,因为linux不能直接对物理地址进行操作,需要映射为linux可操作的虚拟地址才可以;此时映射好的虚拟地址gpio6_dir等就相当于物理地址一样,再配合write或者ioctl等函数进行操作即可。

Makefile:使用只需KERNEL_DIR修改为自己内核的路径才可以正常编译驱动。

KERNEL_DIR = /root/hi3516/linux-4.9.y

all:
	make -C $(KERNEL_DIR) M=`pwd` modules
	
clean:
	make -C $(KERNEL_DIR) M=`pwd` modules clean
	rm -rf modules.order
	
obj-m	+= led_drv.o

海思hi3516ev200GPIO驱动开发

如上图,编译完 会在c文件目录生成.ko驱动文件,复制到海思开发板上面,使用insmod led_drv.ko命令即可加载驱动,使用lsmod查看系统已经加载的驱动,rmmod led_drv可以卸载驱动led_drv。

海思hi3516ev200GPIO驱动开发

2、app开发

比较常规的文件读写操作就可以调用驱动,代码如下:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>



/*
  *  ledtest <dev> <on|off>
  */
void print_usage(char *file)
{
    printf("Usage:\n");
    printf("%s <dev> <on|off>\n",file);
    printf("eg. \n");
    printf("%s /dev/leds on\n", file);
    printf("%s /dev/leds off\n", file);
    printf("%s /dev/led1 on\n", file);
    printf("%s /dev/led1 off\n", file);
}


int main(int argc, char **argv)
{
    int fd;
    char* filename=NULL;
    char val;
    
	if(argc !=3)
    {
        print_usage( argv[1]);//打印用法
    }
	
    filename = argv[1];
    
    fd = open(filename, O_RDWR);//打开dev/firstdrv设备文件
    if (fd < 0)//小于0说明没有成功
    {
        printf("error, can't open %s\n", filename);
        return 0;
    }
    
    

    if(!strcmp(argv[2], "on"))
       val = (1<<7);   //此处驱动的GPIO6_7属于第7个引脚,所以需要把bit7置1
    else
       val = 0;
   
    write(fd, &val, 1);//操作LED
	printf("Set led GPIO to %d\n",val);
	
	close(fd);
    
    return 0;
}

海思hi3516ev200GPIO驱动开发

具体编译器要根据自身海思芯片所自带的编译器而定,编译成功后生成led可执行文件,复制到开发板,对应增加可以执行权限即可chmod +x led, 执行./led /dev/led off即可输出低电平,执行./led /dev/led on输出高电平。

参考文章1

参考文章2

本文地址:https://blog.csdn.net/Sweets_JIE/article/details/107966029