GPIO实验(1)——基于rk3308b-cc-plus开发板

1.配置dts文件

添加引脚配置到开发板所使用的dts文件中

//我的路径为/home/xt/Desktop/proj/rk3308_linux_release_v1.5.0a_20221212/kernel/arch/arm64/boot/dts/rockchip/rk3308b-roc-cc-plus-amic_emmc.dts
	gpio_demo: gpio_demo {
	    status = "okay";
	    compatible = "firefly,rk3308-gpio";
	    firefly-gpio = <&gpio4 RK_PA6 GPIO_ACTIVE_HIGH>;          /* GPIO4_A6 */
	};

status让gpio引脚处于可使用状态。而compatible实现与设备节点的直接配对。接下来写的驱动程序就会通过compatible的内容来找所要使用的gpio引脚。最后的一行则是写了名称和对应的引脚编号及其状态。

2.编写调用该gpio的驱动程序

首先我们要进入该目录下/home/xt/Desktop/proj/rk3308_linux_release_v1.5.0a_20221212/kernel/drivers/gpio。然后创建一个c文件放这个驱动程序,名字叫什么都可以。我的就按照官方教程叫做gpio-firefly.c

2.1 补充知识——Linux内核模块程序结构

Linux内核的整体架构本就非常庞大,其包含的组件也非常多。而我们怎样把需要的部分都包含在内核中呢?一种方法是把所有需要的功能都编译到Linux内核中。这会导致两个问题,一是生成的内核会很大,二是如果我们要在现有的内核中新增或删除功能,将不得不重新编译内核。

Linux提供了这样的机制,这种机制被称为模块(Module)。可使得编译出的内核本身并不需要包含所有功能,而在这些功能需要被使用的时候,其对应的代码被动态地加载到内核中。

模块本身不被编译入内核映像,从而控制了内核的大小。模块一旦被加载,它就和内核中的其他部分完全一样。

#include <linux/init.h>
#include <linux/sched.h>
#include <linux/module.h>
 
MODULE_LICENSE("GPL");

/*模块加载函数:当使用insmod命令加载模块时,该函数会自动被执行,完成加载工作*/
static int __init example_init(void)
{
        printk(KERN_EMERG "example, init\n");
        return 0;
}
 
/*模块卸载函数:当使用rmmod命令卸载模块时……*/
static void __exit hello_exit(void)
{
        printk(KERN_EMERG "example, exit\n");
}

/*模块家在函数以module_init()的方式被指定*/
module_init(example_init);
module_exit(example_exit);

2.2 补充知识——驱动注册

新的linux内核开始使用设备树方式,注册的不是平台设备而是平台的驱动,平台驱动在注册时会自动匹配设备节点,匹配成功后会调用probe函数。这一行为,简化了设备驱动的开发,让内核驱动模型管理设备驱动。

简单理解就是,有了一个platform_driver的结构体,可以利用里面的所填写的信息(compatible)自动去dst找对应,完成注册


static int firefly_gpio_probe(struct platform_device *pdev){}

static struct of_device_id firefly_match_table[] = {
	{ .compatible = "firefly,rk3308-gpio",},
	{},
};

static struct platform_driver firefly_gpio_driver = {
	.driver = {
		.name = "firefly-gpio",/*再对应名字,查看是否正确*/
		.owner = THIS_MODULE,
		.of_match_table = firefly_match_table,/*首先匹配它,即根据上面结构体的compatible的内容去dts找对应节点*/
	},
	.probe = firefly_gpio_probe,/*对应成功则调用probe函数*/
};

static int firefly_gpio_init(void)
{
	return platform_driver_register(&firefly_gpio_driver);
    /*使用 platform_driver_register(&dev_driver)注册了设备驱动*/
}
module_init(firefly_gpio_init);

static void firefly_gpio_exit(void)
{
	platform_driver_unregister(&firefly_gpio_driver);
    /*退出时要删掉*/
}
module_exit(firefly_gpio_exit);

2.3 probe函数

/*定义了一个包含gpio信息的结构体*/
struct firefly_gpio_info
{
	int firefly_gpio;
	int gpio_enable_value;
};

static int firefly_gpio_probe(struct platform_device *pdev)
{
	int gpio;
	enum of_gpio_flags flag;
	struct firefly_gpio_info *gpio_info;
	struct device_node *firefly_gpio_node = pdev->dev.of_node;

	printk("Firefly GPIO Test Program Probe\n");
    
    /*简单类比一下用户空间里c语言中给指针分配空间的malloc,一个道理*/
	gpio_info = devm_kzalloc(&pdev->dev, sizeof(struct firefly_gpio_info *),GFP_KERNEL);
	if (!gpio_info)
	{
		dev_err(&pdev->dev, "devm_kzalloc failed!\n");
		return -ENOMEM;
	}
    /*通过device节点以及name申请gpio资源*/
	gpio = of_get_named_gpio_flags(firefly_gpio_node, "firefly-gpio", 0, &flag);

    /*测试gpio号是否有效*/
	if (!gpio_is_valid(gpio))
	{
		dev_err(&pdev->dev, "firefly-gpio: %d is invalid!\n", gpio);
		return -ENODEV;
	}

    /*申请使用*/
	if (gpio_request(gpio, "firefly-gpio"))
	{
		dev_err(&pdev->dev, "firefly_gpio: %d request failed!\n", gpio);
		gpio_free(gpio);
		return -ENODEV;
	}
    
    /*申请成功后,便利用gpio_direction_output给该gpio进行定义*/
	gpio_info->firefly_gpio = gpio;
	gpio_info->gpio_enable_value = (flag == OF_GPIO_ACTIVE_LOW) ? 0:1;
	gpio_direction_output(gpio_info->firefly_gpio, gpio_info->gpio_enable_value);
	printk("Firefly gpio putout\n");
	return 0;
}

2.4 合起来的版本

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>

struct firefly_gpio_info
{
	int firefly_gpio;
	int gpio_enable_value;
};

static int firefly_gpio_probe(struct platform_device *pdev)
{
	int gpio;
	enum of_gpio_flags flag;
	struct firefly_gpio_info *gpio_info;
	struct device_node *firefly_gpio_node = pdev->dev.of_node;

	printk("Firefly GPIO Test Program Probe\n");

	gpio_info = devm_kzalloc(&pdev->dev, sizeof(struct firefly_gpio_info *),GFP_KERNEL);
	if (!gpio_info)
	{
		dev_err(&pdev->dev, "devm_kzalloc failed!\n");
		return -ENOMEM;
	}

	gpio = of_get_named_gpio_flags(firefly_gpio_node, "firefly-gpio", 0, &flag);
	if (!gpio_is_valid(gpio))
	{
		dev_err(&pdev->dev, "firefly-gpio: %d is invalid!\n", gpio);
		return -ENODEV;
	}
	if (gpio_request(gpio, "firefly-gpio"))
	{
		dev_err(&pdev->dev, "firefly_gpio: %d request failed!\n", gpio);
		gpio_free(gpio);
		return -ENODEV;
	}

	gpio_info->firefly_gpio = gpio;
	gpio_info->gpio_enable_value = (flag == OF_GPIO_ACTIVE_LOW) ? 0:1;
	gpio_direction_output(gpio_info->firefly_gpio, gpio_info->gpio_enable_value);
	printk("Firefly gpio putout\n");



	return 0;
}

static struct of_device_id firefly_match_table[] = {
	{ .compatible = "firefly,rk3308-gpio",},
	{},
};

static struct platform_driver firefly_gpio_driver = {
	.driver = {
		.name = "firefly-gpio",
		.owner = THIS_MODULE,
		.of_match_table = firefly_match_table,
	},
	.probe = firefly_gpio_probe,
};

static int firefly_gpio_init(void)
{
	return platform_driver_register(&firefly_gpio_driver);
}
module_init(firefly_gpio_init);

static void firefly_gpio_exit(void)
{
	platform_driver_unregister(&firefly_gpio_driver);
}
module_exit(firefly_gpio_exit);

MODULE_AUTHOR("linjc <service@t-firefly.com>");
MODULE_DESCRIPTION("Firefly GPIO driver");
MODULE_ALIAS("platform:firefly-gpio");
MODULE_LICENSE("GPL");

3.Kconfig与makefile文件

注意!!必须添加该内容,否则c文件不会被编译且加入内核!

内核编译需要.config文件,来告诉内核是否需要编译进内核。而Kconfig会帮助内核发现我们写的模块,Makefile则是告诉编译器来编译生成这个模块。

3.1 Kconfig

说明了模块的名称、用途、依赖的模块名、说明等。

config GPIO_FIREFLY
	tristate "Firefly GPIO Demo support"
    default y
	help
	  Sample code of gpio
endif

3.2 makefile

obj-$(CONFIG_GPIO_FIREFLY)	+= gpio-firefly.o

4. 烧录进开发板,检查是否成功

具体烧录方法根据开发板来定,可在官方手册看到。

利用 cat /sys/kernel/debug/gpio命令可以看到引脚是否被启用以及其状态。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: DLT-RK3288B开发板是一款基于RK3288芯片的高性能、低功耗开发板,支持4K视频解码和编码,采用6层PCB设计,具备强大的图形处理能力,适用于人工智能、虚拟现实等领域的开发。 该开发板配备了2GB DDR3 RAM和16GB eMMC内存,在存储和运行性能上表现出色。它支持多种外接设备,如HDMI、Ethernet、USB2.0、USB3.0、RS232、LVDS等接口,使其广泛适用于智能家居、智能电子设备、数字标牌等场景。 除此之外,该开发板还支持Android、Linux、Ubuntu等多种操作系统,具备完善的驱动和软件支持,便于用户进行应用开发。 此外,该开发板还提供了开发板的原理图、数据手册、示例代码和固件等资料,使开发者能够快速上手操作和进行产品开发。 综合来看,DLT-RK3288B开发板结构坚实,性能稳定,功能丰富,适合中小型企业、个人开发者进行软硬件开发,是一款非常优秀的开发板。 ### 回答2: dlt-rk3288b开发板是一款基于Rockchip RK3288芯片的高性能开发板。该板具有强大的性能和极高的功能扩展性,可用于各种应用场景。 该开发板的资料包括硬件资料和软件资料。硬件资料包括原理图、PCB设计、BOM清单、3D模型等,可供用户用于二次开发和定制化生产。软件资料包括系统镜像、驱动程序、SDK等,可供用户快速上手开发和应用。 该开发板支持多种操作系统,如Android、Linux等。用户可根据自己的需求选择适合的操作系统来运行。开发板的性能强大,支持高清视频播放、图像处理、人工智能等多种应用场景。 此外,dlt-rk3288b开发板还具有丰富的接口,包括HDMI、USB、以太网、GPIO、SPI、UART等,可支持各种外围设备的连接和交互。 总之,dlt-rk3288b开发板资料完备,功能强大,可实现多种应用场景。该开发板是开发人员和工程师进行开发和应用的理想选择。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值