驱动开发(3)|rk356x驱动GPIO基础应用之点亮led灯

点亮LED灯看似是一个基础的操作,但实际上,许多高级应用也依赖于高低电平的切换。例如,脉冲宽度调制(PWM)信号可以用来精确控制电机的转速,通过改变脉冲的频率和占空比,实现对电机的精确调节;同样,波形信号的生成也能够控制墨盒的喷墨精度,从而影响打印质量。通过对GPIO高低电平的精确控制,开发者可以实现各种复杂的硬件控制任务,这些基础操作为更复杂的应用提供了基础支持。

老规矩,先看效果:

这里控制led等一秒闪一次,下面分享两种控制led灯驱动代码:

1 通过GPIO 子系统设置引脚

c 复制代码
//led1.c
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/miscdevice.h>

#define DEVICE_NAME "led_clt"

#define IOCTL_POWER_ON      _IO('led', 1)
#define IOCTL_POWER_OFF     _IO('POWER_OFF', 0)

// 定义所有GPIO引脚 (根据实际硬件连接修改)
#define LED_PIN         101


static int power_gpios[] = {
    LED_PIN
};

static const char *power_gpio_names[] = {
    "LED"
};

void led_light(unsigned int epoch)
{
    int i = 0;
    for(i = 0 ;i < epoch; i++)
    {
        gpio_set_value(LED_PIN,1);
        mdelay(1000);
        gpio_set_value(LED_PIN,0);
        mdelay(1000);
    }

}
long gpio_user_ctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    switch (cmd) 
    {
        int i;
        case IOCTL_POWER_ON:
            led_light(5);
            break;
        case IOCTL_POWER_OFF:
            //下电时序信号

            printk(KERN_EMERG "inkjet power off...");
            break;


        default:
            return -ENOTTY;
    }
    return 0;
}

static const struct file_operations power_fops = {
    .owner = THIS_MODULE,
    .unlocked_ioctl = gpio_user_ctl,  // 设置ioctl回调
    .open = nonseekable_open,
};
static struct miscdevice gpio_dev = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = DEVICE_NAME,
    .fops = &power_fops,
};
// 初始化函数
static int __init power_init(void)
{
    int i, ret = 0;
    ret = register_chrdev(0, KERN_DEBUG, &power_fops);
    if (ret < 0) 
    {
        printk(KERN_ERR "Failed to register device\n");
        return ret;
    }
    
    // 获取设备号
    printk(KERN_INFO "Device registered with major number %d\n", ret);
    
    // 申请所有GPIO
    for (i = 0; i < ARRAY_SIZE(power_gpios); i++) 
    {
        ret = gpio_request(power_gpios[i], power_gpio_names[i]);
        if (ret)
        {
            printk(KERN_ERR "Failed to request GPIO %s (%d)\n", power_gpio_names[i], power_gpios[i]);
            goto error;
        }
        gpio_direction_output(power_gpios[i], 0);
    }
    //注册设备,用于内核与用户空间简单交互
    ret = misc_register(&gpio_dev);
    if (ret) 
    {
        goto error;
        printk(KERN_ERR "Failed to register misc device\n");
        return ret;
    }
    
    // 安装驱动
    printk(KERN_INFO "Motor Drive Install Success\n");
    

    return 0;

error:
    // 释放已申请的GPIO
    for (i = i - 1; i >= 0; i--) {
        gpio_free(power_gpios[i]);
    }
    return ret;
}

// 清理退出函数
static void __exit power_exit(void)
{
    int i;
    unregister_chrdev(0, DEVICE_NAME);  // 注销字符设备
    printk(KERN_INFO "Device unregistered\n");
    
    //释放所有GPIO
    for (i = ARRAY_SIZE(power_gpios) - 1; i >= 0; i--) {
        gpio_free(power_gpios[i]);
    }
    misc_deregister(&gpio_dev);
    
    printk(KERN_INFO "Motor Drive Uninstall Success\n");
}


module_init(power_init);
module_exit(power_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("limingzhao");
MODULE_DESCRIPTION("motor prj");

2 直接操作硬件寄存器

c 复制代码
#include <linux/init.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/delay.h>
//msdevice
#include <linux/miscdevice.h>
#define DEV_NAME            "led_clt"

#define IOCTL_POWER_ON      _IO('led', 1)
#define IOCTL_POWER_OFF     _IO('POWER_OFF', 0)


#define GPIO1_COUNT            4
#define GPIO3_COUNT            11
#define GPIO4_COUNT            6

#define GROUP_COUNT            5

#define GPIO1_BASE (0xFE740000)
#define GPIO3_BASE (0xFE760000)
#define GPIO4_BASE (0xFE770000)

///A,B-->GPIO1_DR_L和GPIO1_DDR_L///C,D-->GPIO1_DR_H和GPIO1_DDR_H

//GPIO1A0,GPIO1A1,GPIO1B0,GPIO1B1-->GPIO1_DR_L和GPIO1_DDR_L
#define GPIO1_DR_L (GPIO1_BASE + 0x0000)
#define GPIO1_DDR_L (GPIO1_BASE + 0x0008)


//GPIO3_A0,GPIO3_A1...-->GPIO1_DR_L和GPIO1_DDR_L
#define GPIO3_DR_L (GPIO3_BASE + 0x0000)
#define GPIO3_DDR_L (GPIO3_BASE + 0x0008)

//GPIO4C3,GPIO4C5..-->GPIO2_DR_H和GPIO2_DDR_H
#define GPIO4_DR_H (GPIO4_BASE + 0x0004)
#define GPIO4_DDR_H (GPIO4_BASE + 0x000C)

static dev_t devno;
struct class *inkjet_chrdev_class;


typedef struct __PIN_INDEX{
	unsigned int  pin_index;
	unsigned long val_hig;
	unsigned long val_low;
}PIN_INDEX;

typedef struct __PIN_PARAMS{
    struct cdev dev;
	unsigned int 	__iomem *va_dr; 	// 数据寄存器,设置输出的电压
	unsigned int 	__iomem *va_ddr; 	// 数据方向寄存器,设置输入或者输出
	PIN_INDEX 		arrPin[20]; // 偏移
	unsigned int 	pin_count;

}PIN_PARAMS;

///GROUP1,GROUP3,GROUP4,The Number Of Array is Five for Simplifing Coding
static PIN_PARAMS GPIO_GROUPS[GROUP_COUNT];

void led_light(unsigned int epoch)
{
    int i = 0;
    for(i = 0 ;i < epoch; i++)
    {
        set_hig(2);
        mdelay(1000);
        set_low(2);
        mdelay(1000);
    }

}
long power_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    switch (cmd) 
    {
        int i;
        case IOCTL_POWER_ON:
			led_light(5);

            break;
        case IOCTL_POWER_OFF:

            break;

        default:
            return -ENOTTY;
    }
    return 0;
}
static struct file_operations inkjet_chrdev_fops = {
	.owner = THIS_MODULE,
	.unlocked_ioctl = power_ioctl,  // 设置ioctl回调
};
//注册设备信息,用于内核与用户空间简单交互
static struct miscdevice gpio_dev = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = DEV_NAME,
    .fops = &inkjet_chrdev_fops,
};
void set_hig(unsigned int index)
{
			/*
	引脚对应图
		   pin					index
		GPIO1_A0 				 0
		GPIO1_A1				 1
		GPIO3_A5				 2
		GPIO3_A6				 3
		GPIO3_A7				 4
		GPIO4_C3				 5
		GPIO4_C5				 6
		GPIO4_C2				 7
		GPIO3_B4				 8
		GPIO4_D2				 9
		GPIO3_B6				 10
		GPIO3_B5				 11
		GPIO3_B7				 12
		GPIO3_B1				 13
		GPIO3_A0				 14
		GPIO4_C6				 15
		GPIO4_C4				 16
		GPIO3_B3				 17
		GPIO3_B2				 18
		GPIO1_B0				 19
		GPIO1_B1				 20

	*/
	if(index == 0)
	{	//GPIO1_A0
		volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[1].va_dr);
		*reg = GPIO_GROUPS[1].arrPin[0].val_hig;
	}
	else if(index == 1)
	{	//GPIO1_A1
		volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[1].va_dr);
		*reg = GPIO_GROUPS[1].arrPin[1].val_hig;
	}
	else if(index == 2)
	{	//GPIO3_A5
		volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[3].va_dr);
		*reg = GPIO_GROUPS[3].arrPin[0].val_hig;

	}
	else if(index == 3)
	{	//GPIO3_A6
		volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[3].va_dr);
		*reg = GPIO_GROUPS[3].arrPin[1].val_hig;

	}
	else if(index == 4)
	{	//GPIO3_A7
		volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[3].va_dr);
		*reg = GPIO_GROUPS[3].arrPin[2].val_hig;
	}
	else if(index == 5)
	{	//GPIO4_C3
		volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[4].va_dr);
		*reg = GPIO_GROUPS[4].arrPin[0].val_hig;
	}
	else if(index == 6)
	{	//GPIO4_C5
		volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[4].va_dr);
		*reg = GPIO_GROUPS[4].arrPin[1].val_hig;
	}
	else if(index == 7)
	{	//GPIO4_C2
		volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[4].va_dr);
		*reg = GPIO_GROUPS[4].arrPin[2].val_hig;
	}
	else if(index == 8)
	{	//GPIO3_B4
		volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[3].va_dr);
		*reg = GPIO_GROUPS[3].arrPin[3].val_hig;
	}
	else if(index == 9)
	{	//GPIO4_D2
		volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[4].va_dr);
		*reg = GPIO_GROUPS[4].arrPin[3].val_hig;
	}
	else if(index == 10)
	{	//GPIO3_B6
		volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[3].va_dr);
		*reg = GPIO_GROUPS[3].arrPin[4].val_hig;
	}
	else if(index == 11)
	{	//GPIO3_B5
		volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[3].va_dr);
		*reg = GPIO_GROUPS[3].arrPin[5].val_hig;
	}
	else if(index == 12)
	{	//GPIO3_B7
		volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[3].va_dr);
		*reg = GPIO_GROUPS[3].arrPin[6].val_hig;
	}
	else if(index == 13)
	{	//GPIO3_B1
		volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[3].va_dr);
		*reg = GPIO_GROUPS[3].arrPin[7].val_hig;
	}
	else if(index == 14)
	{	//GPIO3_A0
		volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[3].va_dr);
		*reg = GPIO_GROUPS[3].arrPin[8].val_hig;
	}
	else if(index == 15)
	{	//GPIO4_C6
		volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[4].va_dr);
		*reg = GPIO_GROUPS[4].arrPin[4].val_hig;
	}
	else if(index == 16)
	{	//GPIO4_C4
		volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[4].va_dr);
		*reg = GPIO_GROUPS[4].arrPin[5].val_hig;
	}
	else if(index == 17)
	{	//GPIO3_B3
		volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[3].va_dr);
		*reg = GPIO_GROUPS[3].arrPin[9].val_hig;
	}
	else if(index == 18)
	{	//GPIO3_B2
		volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[3].va_dr);
		*reg = GPIO_GROUPS[3].arrPin[10].val_hig;
	}
	else if(index == 19)
	{	//GPIO1_B0
		volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[1].va_dr);
		*reg = GPIO_GROUPS[1].arrPin[2].val_hig;
	}
	else if(index == 20)
	{	//GPIO1_B1
		volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[1].va_dr);
		*reg = GPIO_GROUPS[1].arrPin[3].val_hig;
	}
	else
	{
		printk(KERN_EMERG "set_hig input index error!!\n");
	}


}
void set_low(unsigned int index)
{
				/*
	引脚对应图
		   pin					index
		GPIO1_A0 				 0
		GPIO1_A1				 1
		GPIO3_A5				 2
		GPIO3_A6				 3
		GPIO3_A7				 4
		GPIO4_C3				 5
		GPIO4_C5				 6
		GPIO4_C2				 7
		GPIO3_B4				 8
		GPIO4_D2				 9
		GPIO3_B6				 10
		GPIO3_B5				 11
		GPIO3_B7				 12
		GPIO3_B1				 13
		GPIO3_A0				 14
		GPIO4_C6				 15
		GPIO4_C4				 16
		GPIO3_B3				 17
		GPIO3_B2				 18
		GPIO1_B0				 19
		GPIO1_B1				 20

	*/

	if(index == 0)
	{	//GPIO1_A0
		volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[1].va_dr);
		*reg = GPIO_GROUPS[1].arrPin[0].val_low;
	}
	else if(index == 1)
	{	//GPIO1_A1
		volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[1].va_dr);
		*reg = GPIO_GROUPS[1].arrPin[1].val_low;
	}
	else if(index == 2)
	{	//GPIO3_A5
		volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[3].va_dr);
		*reg = GPIO_GROUPS[3].arrPin[0].val_low;

	}
	else if(index == 3)
	{	//GPIO3_A6
		volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[3].va_dr);
		*reg = GPIO_GROUPS[3].arrPin[1].val_low;

	}
	else if(index == 4)
	{	//GPIO3_A7
		volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[3].va_dr);
		*reg = GPIO_GROUPS[3].arrPin[2].val_low;
	}
	else if(index == 5)
	{	//GPIO4_C3
		volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[4].va_dr);
		*reg = GPIO_GROUPS[4].arrPin[0].val_low;
	}
	else if(index == 6)
	{	//GPIO4_C5
		volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[4].va_dr);
		*reg = GPIO_GROUPS[4].arrPin[1].val_low;
	}
	else if(index == 7)
	{	//GPIO4_C2
		volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[4].va_dr);
		*reg = GPIO_GROUPS[4].arrPin[2].val_low;
	}
	else if(index == 8)
	{	//GPIO3_B4
		volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[3].va_dr);
		*reg = GPIO_GROUPS[3].arrPin[3].val_low;
	}
	else if(index == 9)
	{	//GPIO4_D2
		volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[4].va_dr);
		*reg = GPIO_GROUPS[4].arrPin[3].val_low;
	}
	else if(index == 10)
	{	//GPIO3_B6
		volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[3].va_dr);
		*reg = GPIO_GROUPS[3].arrPin[4].val_low;
	}
	else if(index == 11)
	{	//GPIO3_B5
		volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[3].va_dr);
		*reg = GPIO_GROUPS[3].arrPin[5].val_low;
	}
	else if(index == 12)
	{	//GPIO3_B7
		volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[3].va_dr);
		*reg = GPIO_GROUPS[3].arrPin[6].val_low;
	}
	else if(index == 13)
	{	//GPIO3_B1
		volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[3].va_dr);
		*reg = GPIO_GROUPS[3].arrPin[7].val_low;
	}
	else if(index == 14)
	{	//GPIO3_A0
		volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[3].va_dr);
		*reg = GPIO_GROUPS[3].arrPin[8].val_low;
	}
	else if(index == 15)
	{	//GPIO4_C6
		volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[4].va_dr);
		*reg = GPIO_GROUPS[4].arrPin[4].val_low;
	}
	else if(index == 16)
	{	//GPIO4_C4
		volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[4].va_dr);
		*reg = GPIO_GROUPS[4].arrPin[5].val_low;
	}
	else if(index == 17)
	{	//GPIO3_B3
		volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[3].va_dr);
		*reg = GPIO_GROUPS[3].arrPin[9].val_low;
	}
	else if(index == 18)
	{	//GPIO3_B2
		volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[3].va_dr);
		*reg = GPIO_GROUPS[3].arrPin[10].val_low;
	}
	else if(index == 19)
	{	//GPIO1_B0
		volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[1].va_dr);
		*reg = GPIO_GROUPS[1].arrPin[2].val_low;
	}
	else if(index == 20)
	{	//GPIO1_B1
		volatile uint32_t *reg = (volatile uint32_t *)(GPIO_GROUPS[1].va_dr);
		*reg = GPIO_GROUPS[1].arrPin[3].val_low;
	}
	else
	{
		printk(KERN_EMERG "set_low input index error!!\n");
	}


}
void init_pin_values()
{
	int i = 0;
	int j = 0;
	
	dev_t cur_dev;
	unsigned long val = 0;

	
	////////GPIO1 GROUP SETTING//////
	GPIO_GROUPS[1].pin_count = GPIO1_COUNT;
	//GPIO1_A0
	GPIO_GROUPS[1].arrPin[0].pin_index = 0;
	//GPIO1_A1
	GPIO_GROUPS[1].arrPin[1].pin_index = 1;
	//GPIO1_B0
	GPIO_GROUPS[1].arrPin[2].pin_index = 8;
	//GPIO1_B1
	GPIO_GROUPS[1].arrPin[3].pin_index = 9;
	GPIO_GROUPS[1].va_dr = ioremap(GPIO1_DR_L, 4);
	GPIO_GROUPS[1].va_ddr = ioremap(GPIO1_DDR_L, 4);


	////////GPIO3 GROUP SETTING//////
	GPIO_GROUPS[3].pin_count = GPIO3_COUNT;
	//GPIO3_A5
	GPIO_GROUPS[3].arrPin[0].pin_index = 5;
	//GPIO3_A6
	GPIO_GROUPS[3].arrPin[1].pin_index = 6;
	//GPIO3_A7
	GPIO_GROUPS[3].arrPin[2].pin_index = 7;
	//GPIO3_B4
	GPIO_GROUPS[3].arrPin[3].pin_index = 12;
	//GPIO3_B6
	GPIO_GROUPS[3].arrPin[4].pin_index = 14;
	//GPIO3_B5
	GPIO_GROUPS[3].arrPin[5].pin_index = 13;
	//GPIO3_B7
	GPIO_GROUPS[3].arrPin[6].pin_index = 15;
	//GPIO3_B1
	GPIO_GROUPS[3].arrPin[7].pin_index = 9;
	//GPIO3_A0
	GPIO_GROUPS[3].arrPin[8].pin_index = 0;
	//GPIO3_B3
	GPIO_GROUPS[3].arrPin[9].pin_index = 11;
	//GPIO3_B2
	GPIO_GROUPS[3].arrPin[10].pin_index = 10;

	GPIO_GROUPS[3].va_dr = ioremap(GPIO3_DR_L, 4);
	GPIO_GROUPS[3].va_ddr = ioremap(GPIO3_DDR_L, 4);


	////////GPIO4 GROUP SETTING//////
	GPIO_GROUPS[4].pin_count = GPIO4_COUNT;
	//GPIO4_C3
	GPIO_GROUPS[4].arrPin[0].pin_index = 3;
	//GPIO4_C5
	GPIO_GROUPS[4].arrPin[1].pin_index = 5;
	//GPIO4_C2
	GPIO_GROUPS[4].arrPin[2].pin_index = 2;
	//GPIO4_D2
	GPIO_GROUPS[4].arrPin[3].pin_index = 10;
	//GPIO4_C6
	GPIO_GROUPS[4].arrPin[4].pin_index = 6;
	//GPIO4_C4
	GPIO_GROUPS[4].arrPin[5].pin_index = 4;
	GPIO_GROUPS[4].va_dr = ioremap(GPIO4_DR_H, 4);
	GPIO_GROUPS[4].va_ddr = ioremap(GPIO4_DDR_H, 4);

	alloc_chrdev_region(&devno, 0, GROUP_COUNT - 2, DEV_NAME);

	inkjet_chrdev_class = class_create(THIS_MODULE, "led_clt");

	for (; i < GROUP_COUNT; i++) 
	{
		if(i == 0|| i == 2)
		{
			continue;
		}
		cdev_init(&GPIO_GROUPS[i].dev, &inkjet_chrdev_fops);
		GPIO_GROUPS[i].dev.owner = THIS_MODULE;

		cur_dev = MKDEV(MAJOR(devno), MINOR(devno) + i);

		cdev_add(&GPIO_GROUPS[i].dev, cur_dev, 1);

		device_create(inkjet_chrdev_class, NULL, cur_dev, NULL,
			      DEV_NAME "%d", i);
	}

	// printk(KERN_EMERG "open\n");
	////////GPIO0 GROUP PINS EXPORT AND SAVE VALUE//////
	//五组GPIO(GPIO0-GPIO4)
	for(i = 0; i < GROUP_COUNT; i++)
	{
		if(i == 0|| i == 2)
		{
			continue;
		}
		for(j = 0; j < GPIO_GROUPS[i].pin_count; j++)
		{
			//export
			val = ioread32(GPIO_GROUPS[i].va_ddr);
			val |= ((unsigned int)0x1 << (GPIO_GROUPS[i].arrPin[j].pin_index+16));
			val |= ((unsigned int)0X1 << (GPIO_GROUPS[i].arrPin[j].pin_index));
			iowrite32(val, GPIO_GROUPS[i].va_ddr);

			//save hig and low value
			//high value
			val = ioread32(GPIO_GROUPS[i].va_dr);
			val |= ((unsigned int)0x1 << (GPIO_GROUPS[i].arrPin[j].pin_index+16));
			val &= ~((unsigned int)0x01 << (GPIO_GROUPS[i].arrPin[j].pin_index));   
			iowrite32(val, GPIO_GROUPS[i].va_dr);
			GPIO_GROUPS[i].arrPin[j].val_low = val;

			//low value
			val = ioread32(GPIO_GROUPS[i].va_dr);
			val |= ((unsigned int)0x1 << (GPIO_GROUPS[i].arrPin[j].pin_index+16));
			val |= ((unsigned int)0x1 << (GPIO_GROUPS[i].arrPin[j].pin_index));
			iowrite32(val, GPIO_GROUPS[i].va_dr);
			GPIO_GROUPS[i].arrPin[j].val_hig = val;

		}

	}

	int ret = 0;
	//注册设备,用于内核与用户空间简单交互
    ret = misc_register(&gpio_dev);
    if (ret) 
    {
        printk(KERN_ERR "Failed to register misc device\n");
        return;
    }
	

}



static __init int inkjet_chrdev_init(void)
{
	init_pin_values();

	return 0;
}

module_init(inkjet_chrdev_init);

static __exit void inkjet_chrdev_exit(void)
{
	int i;
	dev_t cur_dev;
	
	for (i = 0; i < GROUP_COUNT; i++) 
	{
		if(i == 0|| i == 2)
		{
			continue;
		}
		iounmap(GPIO_GROUPS[i].va_dr); 		// 释放模式寄存器虚拟地址
		iounmap(GPIO_GROUPS[i].va_ddr); 	// 释放输出类型寄存器虚拟地址
	}

	for (i = 0; i < GROUP_COUNT; i++) 
	{
		if(i == 0|| i == 2)
		{
			continue;
		}
		cur_dev = MKDEV(MAJOR(devno), MINOR(devno) + i);

		device_destroy(inkjet_chrdev_class, cur_dev);

		cdev_del(&GPIO_GROUPS[i].dev);

	}
	unregister_chrdev_region(devno, 1);
	class_destroy(inkjet_chrdev_class);
	//release access dev
	misc_deregister(&gpio_dev);
}

module_exit(inkjet_chrdev_exit);

MODULE_AUTHOR("limingzhao");
MODULE_LICENSE("GPL");

这里我嫌示例代码太麻烦了,自己封装了一下,set_higset_low,只封装了GPIO1、GPIO3和GPIO4,对应序号的gpio口在注释里面,方便使用。

3 makefile部分

bash 复制代码
KERNEL_DIR=/home/path/to/kernel/

ARCH=arm64
CROSS_COMPILE=aarch64-linux-gnu-
export  ARCH  CROSS_COMPILE

KBUILD_CFLAGS += -O0 -Wall 
obj-m := led1.o

all:
	$(MAKE) -C $(KERNEL_DIR) M=$(CURDIR) modules

.PHONE:clean

clean:
	$(MAKE) -C $(KERNEL_DIR) M=$(CURDIR) clean	

注:这里的KERNEL_DIR改成你自己编译的内核路径,如果不知道怎么编译的可以看我写的驱动开发(1)部分

这里的驱动代码和makefile放虚拟机里面(x86_64),编译成ko文件后放入驱动板里面安装,如图所示:

我这里的led1.c和led2.c分别对应本文段落1和本文段部落2的代码,这两种方法的优劣势上篇文章已经讲明白了。唯一的一点是上次纠正我上篇文章中的错误:上篇文章说通过直接操作寄存器的方式拉高再拉低,寄存器只能到达160ns左右是错误的,因为我之前用的示波器精度不够,这里直接操作寄存器的驱动代码完全能达到50ns级别的延时,不过我还是没用rk3568来直接操控,想要精确操控波形,感兴趣的可以研究一下FPGA开发板。

4 用户层代码

c 复制代码
//call_led.c
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/ioctl.h>

// 定义IOCTL命令
#define IOCTL_POWER_ON      _IO('led', 1)
#define IOCTL_POWER_OFF     _IO('POWER_OFF', 0)

#define DEVICE_NAME "/dev/led_clt"

int main() 
{
    int fd;
    int ret;

    // 打开设备文件
    fd = open(DEVICE_NAME, O_RDWR);
    if (fd < 0) {
        perror("Failed to open device");
        return -1;
    }

    // 调用IOCTL_POWER_ON
    ret = ioctl(fd, IOCTL_POWER_ON);
    if (ret < 0) {
        perror("Failed to send IOCTL_POWER_ON");
        close(fd);
        return -1;
    }

    printf("Motor started\n");
    sleep(5);
    ret = ioctl(fd, IOCTL_POWER_ON);
    if (ret < 0) {
        perror("Failed to send IOCTL_POWER_ON");
        close(fd);
        return -1;
    }
    sleep(5);
    // 关闭设备文件
    close(fd);
    return 0;
}

这里是通过操作led_clt设备,来控制led灯电平高低,linux果然是万物皆文件,都是通过open、read、write基本操作函数。

这里可以看到 ret = ioctl(fd, IOCTL_POWER_ON);调用了两次,也就是led灯先闪烁5次,延时5秒然后再闪烁5次。

5 安装卸载驱动命令

bash 复制代码
# install
insmod led1.ko
# uninstall
rmmod led1.c

6 使用引脚

这里使用的引脚是GPIO3_A5,如图所示:

板子具体位置:

总结

这篇文章主要分享了在RK3568平台上控制GPIO的两种常见方式,并通过LED灯的实验测试,验证了这两种方法的效果。首先介绍了通过编程接口操作GPIO的基本原理和步骤,包括如何设置输入输出模式、读取和写入数据。后续这一系列将暂时停更,主要想先写CV和NLP算法方面的文章。

相关推荐
努力做小白9 小时前
Linux驱动11 --- buildroot&杂项驱动开发方法
linux·运维·驱动开发·单片机·嵌入式硬件
哈哈浩丶9 小时前
Linux驱动开发1:设备驱动模块加载与卸载
linux·运维·驱动开发
哈哈浩丶15 小时前
Linux驱动开发2:字符设备驱动
linux·运维·驱动开发
Narnat4 天前
Rk3568驱动开发_阻塞IO_15
驱动开发
sukalot4 天前
window显示驱动开发—BGRA 扫描输出支持
驱动开发
专一的咸鱼哥4 天前
Linux驱动开发(platform 设备驱动)
linux·运维·驱动开发
牧以南歌〆6 天前
在Ubuntu主机中修改ARM Linux开发板的根文件系统
linux·arm开发·驱动开发·ubuntu
Narnat6 天前
Rk3568驱动开发_中断_14
驱动开发
mmoyula7 天前
【RK3568 驱动开发:实现一个最基础的网络设备】
android·linux·驱动开发