i.MX6ULL Linux开发板 :pinctrl 子系统-----led灯闪烁实验

pinctrl 子系统-----led灯闪烁实验

Linux 设备驱动理论看了有一段时间了,根据理论自己琢磨了一个从设备树到顶部进程的小实验 ----led闪烁实验

pinctrl 子系统的添加

如果从头开始时,首先第一步就是了解硬件信息
led

在这里插入图片描述
根据三张图我们得知:

LED_R 的阴极连接到 i.MX6ULL 芯片上 GPIO1_IO04 引脚, LED_G 连接到 CSI_HSYNC,LED_B
连接到 CSI_VSYNC。而 CSI_HSYNC 和 CSI_VSYNC 作为摄像头的某一功能被复用为 GPIO

LED 灯原理图的标号具体引脚名GPIO 端口及引脚编号
R 灯GPIO_4GPIO1_IO04GPIO1_IO04
G 灯CSI_HSYNCCSI_HSYNCGPIO4_IO20
B 灯CSI_VSYNCCSI_VSYNCGPIO4_IO19

pinctrl 子系统主要用于管理芯片的引脚,也就是将上述的硬件信息抽象出来放到Linux里,也就是告诉系统,我这个系统的配置寄存器在哪里,要配置成什么样,(输出?输入…)?

我们打开厂商写好的引脚功能文件imx6ul-pinfunc.h,查找如下
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

led引脚配置地址别名
GPIO1_IO04MX6UL_PAD_GPIO1_IO04__GPIO1_IO04
CSI_HSYNCMX6UL_PAD_CSI_HSYNC__GPIO4_IO20
CSI_VSYNCMX6UL_PAD_CSI_VSYNC__GPIO4_IO19

属性配置:
在这里插入图片描述
在这里插入图片描述
由上图知道如下信息

寄存器位数功能我们选择的功能
31-17保留0x0000
160:关闭迟滞;1:使能迟滞0
15-14不同电阻上下拉00
13使能输出状态保存 0:保持;1:上拉0
120:关闭拉保持;1:使能拉/保持1
110:禁止漏极开路1:使能漏极开路
10-8保留000
7-6速度10
5:3输出使能110
2-1保留00
00:低速;1:高速1

综上:0x000010B1
故根据子系统格式为

pinctrl_rgb_led:rgb_led{
			fsl,pins = <
				MX6UL_PAD_GPIO1_IO04__GPIO1_IO04 0x000010B1
				MX6UL_PAD_CSI_HSYNC__GPIO4_IO20 0x000010B1
				MX6UL_PAD_CSI_VSYNC__GPIO4_IO19 0x000010B1
			>;
		};

添加到 imx6ull-mmc-npi.dts 如下,表明我们引脚基础配置已经配置好。
在这里插入图片描述

设备树节点的添加

然后我们再添加一个设备节点 也就是告诉Linux ,我们有一个RGB灯。使用pinctrl_rgb_led子系统配置

/* 添加 rgb_led 节点 */
	rgb_led{
			pinctrl-names = "default";
			compatible = "fire,rgb-led";//与平台驱动做匹配 
			pinctrl-0 = <&pinctrl_rgb_led>;
			rgb_led_red = <&gpio1 4 GPIO_ACTIVE_LOW>;//低电平有效
			rgb_led_green = <&gpio4 20 GPIO_ACTIVE_LOW>;
			rgb_led_blue = <&gpio4 19 GPIO_ACTIVE_LOW>;
			status = "okay";
		};
#ebf_linux_kernel 目录下进行编译
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- dtbs
#或
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- npi_v7_defconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- dtbs

./arch/arm/boot/dts”目录下生成“imx6ull-mmc-npi.dtb”文件,将其替换掉板子/usr/lib/linux-image-4.19.35-imx6/ 目录下的 imx6ull-mmc-npi.dtb 文件并输入 sudo reboot 重启开发板
在这里插入图片描述在这里插入图片描述

我们开始写驱动与测试进程

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>


#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <asm/mach/map.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <asm/io.h>
#include <linux/device.h>

#include <linux/platform_device.h>




/*------------------字符设备内容----------------------*/
#define DEV_NAME            "rgb-leds"
#define DEV_CNT                 (1)

//定义字符设备的设备号
static dev_t led_devno;
//定义字符设备结构体chr_dev
static struct cdev led_chr_dev;


struct class *class_led;	//保存创建的类
struct device *device;	    // 保存创建的设备
struct device_node	*rgb_led_device_node; //RGB led的设备树节点
int leds_rgb[3];//保存获取得到的红绿蓝灯引脚编号



/*字符设备操作函数集,open函数*/
static int led_chr_dev_open(struct inode *inode, struct file *filp)
{
	printk("\n open form driver \n");
    return 0;
}

/*字符设备操作函数集,write函数*/
static ssize_t led_chr_dev_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{
	unsigned char write_data[2] = {0}; //用于保存接收到的数据
	int error = -1;
	

	if(cnt<2)
	return -1;
    error = copy_from_user(&write_data, buf, cnt);
	printk("\n write_data %d %d  \n",write_data[0],write_data[1]);
	if(error < 0) {
		return -1;
	}
	if(write_data[0]>0&&write_data[0]<4)
	{
		if(write_data[1] == 0 ||write_data[1] == 1)
		gpio_direction_output(leds_rgb[write_data[0]-1],write_data[1]);
	}

#if 0
    /*设置 GPIO1_04 输出电平*/
	if(write_data & 0x04)
	{
		gpio_direction_output(rgb_led_red, 0);  // GPIO1_04引脚输出低电平,红灯亮
	}
	else
	{
		gpio_direction_output(rgb_led_red, 1);    // GPIO1_04引脚输出高电平,红灯灭
	}


    /*设置 GPIO4_20 输出电平*/
	if(write_data & 0x02)
	{
		gpio_direction_output(rgb_led_green, 0);  // GPIO4_20引脚输出低电平,绿灯亮
	}
	else
	{
		gpio_direction_output(rgb_led_green, 1);    // GPIO4_20引脚输出高电平,绿灯灭
	}


    /*设置 GPIO4_19 输出电平*/
	if(write_data & 0x01)
	{
		gpio_direction_output(rgb_led_blue, 0);  // GPIO4_19引脚输出低电平,蓝灯亮
	}
	else
	{
		gpio_direction_output(rgb_led_blue, 1);    // GPIO4_19引脚输出高电平,蓝灯灭
	}
#endif

	return 0;
}


/*字符设备操作函数集*/
static struct file_operations  led_chr_dev_fops = 
{
	.owner = THIS_MODULE,
    .open = led_chr_dev_open,
	.write = led_chr_dev_write,
};



/*----------------平台驱动函数集-----------------*/
static int led_probe(struct platform_device *pdv)
{
	
	int ret = 0;  //用于保存申请设备号的结果
    
	printk(KERN_EMERG "\t  match successed  \n");

    /*获取RGB的设备树节点*/
    rgb_led_device_node = of_find_node_by_path("/rgb_led");
    if(rgb_led_device_node == NULL)
    {
        printk(KERN_EMERG "\t  get rgb_led failed!  \n");
    }

    leds_rgb[0] = of_get_named_gpio(rgb_led_device_node, "rgb_led_red", 0);
   	leds_rgb[1] = of_get_named_gpio(rgb_led_device_node, "rgb_led_green", 0);
    leds_rgb[2] = of_get_named_gpio(rgb_led_device_node, "rgb_led_blue", 0);

    printk("rgb_led_red = %d,\n rgb_led_green = %d,\n rgb_led_blue = %d,\n", leds_rgb[0],\
    leds_rgb[1],leds_rgb[2]);

    gpio_direction_output(leds_rgb[0], 1);
    gpio_direction_output(leds_rgb[1], 1);
    gpio_direction_output(leds_rgb[2], 1);


	/*---------------------注册 字符设备部分-----------------*/

	//第一步
    //采用动态分配的方式,获取设备编号,次设备号为0,
    //设备名称为rgb-leds,可通过命令cat  /proc/devices查看
    //DEV_CNT为1,当前只申请一个设备编号
    ret = alloc_chrdev_region(&led_devno, 0, DEV_CNT, DEV_NAME);
    if(ret < 0){
        printk("fail to alloc led_devno\n");
        goto alloc_err;
    }
    //第二步
    //关联字符设备结构体cdev与文件操作结构体file_operations
	led_chr_dev.owner = THIS_MODULE;
    cdev_init(&led_chr_dev, &led_chr_dev_fops);
    //第三步
    //添加设备至cdev_map散列表中
    ret = cdev_add(&led_chr_dev, led_devno, DEV_CNT);
    if(ret < 0)
    {
        printk("fail to add cdev\n");
        goto add_err;
    }

	//第四步
	/*创建类 */
	class_led = class_create(THIS_MODULE, DEV_NAME);

	/*创建设备*/
	device = device_create(class_led, NULL, led_devno, NULL, DEV_NAME);

	return 0;

add_err:
    //添加设备失败时,需要注销设备号
    unregister_chrdev_region(led_devno, DEV_CNT);
	printk("\n error! \n");
alloc_err:

	return -1;

}




static const struct of_device_id rgb_led[] = {
{ .compatible = "fire,rgb-led"},
  { /* sentinel */ }
};

/*定义平台设备结构体*/
struct platform_driver led_platform_driver = {
	.probe = led_probe,
	.driver = {
		.name = "rgb-leds-platform",
		.owner = THIS_MODULE,
		.of_match_table = rgb_led,
	}
};



/*
*驱动初始化函数
*/
static int __init led_platform_driver_init(void)
{
	int DriverState;
	
	DriverState = platform_driver_register(&led_platform_driver);
	
	printk(KERN_EMERG "\tDriverState is %d\n",DriverState);
	return 0;
}


/*
*驱动注销函数
*/
static void __exit led_platform_driver_exit(void)
{
	printk(KERN_EMERG "HELLO WORLD exit!\n");
	device_destroy(class_led,led_devno);      
    class_destroy(class_led);//删除类	
	platform_driver_unregister(&led_platform_driver);	
}


module_init(led_platform_driver_init);
module_exit(led_platform_driver_exit);

MODULE_LICENSE("GPL");


#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
int main(int argc, char *argv[])
{
	int error = -1;
    printf("led_tiny test\n");

    /*打开文件*/
    int fd = open("/dev/rgb-leds", O_RDWR);
    if(fd < 0)
    {
		printf("open file : %s failed !\n", argv[0]);
		return -1;
	}

    unsigned char commend[2]= {1,0};

    /*判断命令的有效性*/
while(1)
{
    /*写入命令*/
     error = write(fd,&commend,sizeof(commend));
    if(error < 0)
    {
        printf("write file error! \n");
        close(fd);
		fd = -1;
		break;
        /*判断是否关闭成功*/
    }
	sleep(5);
	commend[1]= !commend[1];
    if(write(fd,&commend,sizeof(commend)) < 0)
    {
        printf("write file error! \n");
        close(fd);
		fd = -1;
		break;
        /*判断是否关闭成功*/
    }
	 commend[1]= !commend[1];
	commend[0] == 3?commend[0]= 1:commend[0]++;
	sleep(5);
}

    /*关闭文件*/
	if(fd>0)
    error = close(fd);
    if(error < 0)
    {
        printf("close file error! \n");
    }
    
    return 0;
}

在这里插入图片描述

sudo insmod rgb-leds.ko
sudo ./rgb_leds_app

在这里插入图片描述

效果

图片已加速 实际为5s闪烁
https://qcloudcos.xunjiepdf.com/xunjievideo/temp/202201131001/96a8e694e611414889d2c531058ed7ad/petal_20220113_100202_2.gif

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值