首页 > 其他分享 >全志H3-nanopi-duo2开发板GPIO驱动开发

全志H3-nanopi-duo2开发板GPIO驱动开发

时间:2023-09-16 11:57:46浏览次数:41  
标签:__ led H3 boot 全志 开发板 static gpio include

原文:https://blog.csdn.net/weixin_52668204/article/details/130563421

1:获取对应开发板duo2的内核源码
从官网获取
[friendlyarm的nanopi-duo2](https://wiki.friendlyelec.com/wiki/index.php/NanoPi_Duo2/zh#.E5.AE.9A.E5.88.B6.E5.91.BD.E4.BB.A4.E8.A1.8C.E7.9A.84.E6.AC.A2.E8.BF.8E.E4.BF.A1.E6.81.AF.EF.BC.88.E6.96.87.E5.AD.97LOGO.EF.BC.89)
此网页里面有duo2的很多资料,用户使用,uboot,kernel等等
需要从中下载linux-4.14内核源码,以下是官网维基中的部分内容,
用来作为参考
下载Linux内核源码,并切换分支:

$ git clone https://github.com/friendlyarm/linux.git -b sunxi-4.14.y --depth 1

编译和更新Linux内核:

$ apt-get install u-boot-tools
$ cd linux
$ touch .scmversion
$ make sunxi_defconfig ARCH=arm CROSS_COMPILE=arm-linux-
$ make zImage dtbs ARCH=arm CROSS_COMPILE=arm-linux-

[ 注意: 这里我只需要编译驱动模块,不需要编译内核,上一篇文章有编译驱动模块的步骤]
编译完成后会在arch/arm/boot/目录下生成zImage,并且在arch/arm/boot/dts/目录下生成dtb文件,dtb文件是设备树二进制文件。

假设SD卡的boot分区挂载在/media/SD/boot/,更新SD卡上的zImage和dtb文件:

$ cp arch/arm/boot/zImage /media/SD/boot/
$ cp arch/arm/boot/dts/sun8i-*-nanopi-*.dtb /media/SD/boot/
1
2
也可以用scp命令通过网络更新:

$ scp arch/arm/boot/zImage [email protected]:/boot
$ scp arch/arm/boot/dts/sun8i-*-nanopi-*.dtb [email protected]:/boot
1
2
2:进入源码目录(确保交叉编译工具链和环境变量配置正确)
2.1:源码根目录新建my_make内容为:
#!/bin/sh
export CROSS_COMPILE=$HOME/pan/arm_gcc/bin/arm-cortexa9-linux-gnueabihf-
export ARCH=arm

然后source ./my_make

2.2:执行一下命令:
apt-get install u-boot-tools
touch .scmversion
make sunxi_defconfig //获取默认配置
make dtbs //编译设备树文件

执行make dtbs没有报错,说明环境变量和交叉编译都没问题

3: 修改设备树文件
duo2板子对应此文件:

arch\arm\boot\dts\sun8i-h3-nanopi-duo2.dts
1
设备树文件怎么修改,取决于要使用什么硬件或者说哪个引脚;
这里我要使用PA11引脚用来控制继电器,输出高低电平即可


在官方的设备树文件里面,此引脚被用作I2C引脚,被占用了
需要让占用的节点 status = “disabled”;

//这是pinctrl子节点,可以看到使用了引脚PA11
...
i2c0_pins: i2c0 {
pins = "PA11", "PA12";
function = "i2c0";
};
...
/*----------------------*/
//这是client节点
...
&i2c0 {
status = "okay"; //这里修改为disabled,禁用此节点I2C
rtc@68 {
compatible = "dallas,ds1307";
reg = <0x68>;
};
};
...

3.1: 添加自己的GPIO节点
在sun8i-h3-nanopi-duo2.dts中添加pinctrl子节点PA11引脚的复用功能

/{ //根节点
...
}
//此内容书写位置平行于根节点
&pio {
gpio_pin: gpio { //在pinctrl追加复用功能,设置gpio复用
pins = "PA11";
function = "gpio_out";
};
};

在sun8i-h3-nanopi-duo2.dts中,在根节点内部添加client节点

/{ //根节点
...
...
my_gpio{
compatible = "gin,gpio";
pinctrl-names = "default";
pinctrl-0 = <&gpio_pin>; //选择复用功能
mydvc-gpios = <&pio 0 11 GPIO_ACTIVE_HIGH>; /* PA11 第0组第11个引脚*/
status = "okay";
};
}
...
...
&pio {
gpio_pin: gpio { //在pinctrl追加复用功能,设置gpio复用
pins = "PA11";
function = "gpio_out";
};
};

3.2: make dtbs 编译设备树
make dtbs
//得到:sun8i-h3-nanopi-duo2.dtb
1
2
把dtb文件放入开发板目录下
挂载SD卡的boot分区

//挂载
sudo mount /dev/mmcblk0p1 /media/SD/boot/
//拷贝
sudo cp ./sun8i-h3-nanopi-duo2.dtb /media/SD/boot/
//取消挂载
sudo umount /media/SD/boot/
//重启
sudo reboot
//查看自己的节点信息,成功之后就会看到my_gpio节点,如下图效果
ls /sys/devices/platform/

 

4:编写驱动程序
4.1: 驱动代码内容
直接使用韦东山老师的课程led驱动源码,简单修改了一下下
1
驱动代码的编译步骤记录与我的上一篇文章

#include <linux/module.h>
#include <linux/platform_device.h>

#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/gpio/consumer.h>
#include <linux/of.h>


/* 1. 确定主设备号 */
static int major = 0;
static struct class *led_class;
static struct gpio_desc *led_gpio;


/* 3. 实现对应的open/read/write等函数,填入file_operations结构体 */
static ssize_t led_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
return 0;
}

/* write(fd, &val, 1); */
static ssize_t led_drv_write (struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
int err;
char status;

printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
err = copy_from_user(&status, buf, 1);

/* 根据次设备号和status控制LED */
gpiod_set_value(led_gpio, status);

return 1;
}

static int led_drv_open (struct inode *node, struct file *file)
{
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
/* 根据次设备号初始化LED,输出模式,初始低电平 */
gpiod_direction_output(led_gpio, 0);

return 0;
}

static int led_drv_close (struct inode *node, struct file *file)
{
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
return 0;
}

/* 定义自己的file_operations结构体 */
static struct file_operations led_drv = {
.owner = THIS_MODULE,
.open = led_drv_open,
.read = led_drv_read,
.write = led_drv_write,
.release = led_drv_close,
};

/* 4. 从platform_device获得GPIO
* 把file_operations结构体告诉内核:注册驱动程序
*/
static int chip_demo_gpio_probe(struct platform_device *pdev)
{
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);

/* 4.1 设备树中定义有: led-gpios=<...>; */
led_gpio = gpiod_get(&pdev->dev, "mydvc", 0);
if (IS_ERR(led_gpio)) {
dev_err(&pdev->dev, "Failed to get GPIO for led\n");
return PTR_ERR(led_gpio);
}else{
printk("get GPIO ");
}

/* 4.2 注册file_operations */
major = register_chrdev(0, "Gin_gpio", &led_drv); /* /dev/led */

led_class = class_create(THIS_MODULE, "Gin_gpio_class");
if (IS_ERR(led_class)) {
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
unregister_chrdev(major, "led");
gpiod_put(led_gpio);
return PTR_ERR(led_class);
}

device_create(led_class, NULL, MKDEV(major, 0), NULL, "Gin_gpio%d", 0); /* /dev/Gin_gpio */

return 0;

}

static int chip_demo_gpio_remove(struct platform_device *pdev)
{
device_destroy(led_class, MKDEV(major, 0));
class_destroy(led_class);
unregister_chrdev(major, "Gin_gpio");
gpiod_put(led_gpio);

return 0;
}


static const struct of_device_id Gin_gpio_dvc_id[] = {
{ .compatible = "gin,gpio" },
{ },
};

/* 1. 定义platform_driver */
static struct platform_driver chip_demo_gpio_driver = {
.probe = chip_demo_gpio_probe,
.remove = chip_demo_gpio_remove,
.driver = {
.name = "Gin_gpio",
.of_match_table = Gin_gpio_dvc_id,
},
};

/* 2. 在入口函数注册platform_driver */
static int __init led_init(void)
{
int err;

printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);

err = platform_driver_register(&chip_demo_gpio_driver);

return err;
}

/* 3. 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数
* 卸载platform_driver
*/
static void __exit led_exit(void)
{
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);

platform_driver_unregister(&chip_demo_gpio_driver);
}


/* 7. 其他完善:提供设备信息,自动创建设备节点*/

module_init(led_init);
module_exit(led_exit);

MODULE_LICENSE("GPL")

4.2:编译驱动模块
进入menuconfig ,找到自己的驱动,设置成M,模块方式编译
保存退出
make -j8 models
得到my_driver.ko
拷贝到开发板,安装驱动
sudo insmod my_driver.ko
安装成功之后,在/dev/下有Gin_gpio0设备
1
2
3
4
5
6
7


5: 应用测试程序
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>


void ctrl_gpio(int fd,int state){
char status;
/* 3. 写文件 */
if (state)
{
status = 1;
write(fd, &status, 1);
}
else
{
status = 0;
write(fd, &status, 1);
}
}

/*
* ./ledtest /dev/100ask_led0 on
* ./ledtest /dev/100ask_led0 off
*/
int main(int argc, char **argv)
{
int fd;
int count = 0;

/* 1. 判断参数 */
if (argc != 2)
{
printf("Usage: %s <dev> <on | off>\n", argv[0]);
return -1;
}

/* 2. 打开文件 */
fd = open(argv[1], O_RDWR);
if (fd == -1)
{
printf("can not open file %s\n", argv[1]);
return -1;
}
while (count++ < 10)
{
if((count % 2) == 0){
ctrl_gpio(fd,1);
}else{
ctrl_gpio(fd,0);
}
sleep(2);
}

close(fd);

return 0;
}

编译之后执行 ./test /dev/Gin_gpio0
效果就是PA11引脚拉高拉低
————————————————
版权声明:本文为CSDN博主「漏洞百出」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_52668204/article/details/130563421

标签:__,led,H3,boot,全志,开发板,static,gpio,include
From: https://www.cnblogs.com/bruce1992/p/17706522.html

相关文章

  • Xines广州星嵌全新FPGA开发板—OMAPL138/C6748 DSP+ARM+FPGA
    1  开发板简介    XQ138F-EVM是一款基于广州星嵌TIOMAP-L138(浮点DSPC6748+ARM9)+XilinxSpartan-6FPGA核心板SOM-XQ138F设计的开发板,它为用户提供了SOM-XQ138F核心板的测试平台,用于快速评估SOM-XQ138F核心板的整体性能。 XQ138F-EVM底板采用沉金无铅工艺的四层板设......
  • 关于配置MCU从FLASH某一位置开始运行——以CH32V203为例
    正常MCU运行时,都是从FLASH0起始地址开始运行,有时因为某些需要,需要配置从非0地址开始运行。以CH32V203为例(适用于其他CH32V系列),主要修改配置如下:主要集中在ld文件的修改:1、修改FLASH的分配,将FLASH分配成2块区域,如下图/*CH32V20x_D6-CH32V203K8-CH32V203C8-CH32V203G8-CH32V......
  • 明德扬“学生竞赛计划”-MP805开发板免费使用
    为了鼓励同学们踊跃去参加有关FPGA的比赛,明德扬特此推出“学生竞赛支持计划’支持在比赛的同学,只要在比赛的同学出示 比赛证明都可以在比赛期间免费使用明德扬MP805开发板,联系老师参与此次活动吧......
  • 多屏异显方案-瑞芯微RK3568开发板
    HD-RK3568核心板基于瑞芯微RK3568设计,支持HDMI、MIPI、eDP、LVDS四种显示接口,适配多种显示方案,满足医疗电子、电力电子、工业自动化、车载中控等多种行业应用。RK3568内置VOP控制器,支持三路视频同时输出,其显示通路连接关系如下:l三屏异显l双屏异显| 本文示例屏幕分别为:HDMI(1920*......
  • CH32V208与CH582芯片的区别
    目录CH32V208和CH582都是沁恒的支持BLE5.0+的MCU,下面介绍两者的区别。选型方面:①CH32V208比CH582的ram和零等待flash更多。使用CH582,对速度有要求的代码,需要放到ram中运行;使用V208,对速度有要求的代码可以放到零等待flash中,不会占用ram的资源,V208的零等待falsh和ram都跑主频。......
  • 瑞芯微RK3568开发板多屏同显方案
    HD-RK3568核心板基于瑞芯微RK3568设计,支持HDMI、MIPI、eDP、LVDS四种显示接口,适配多种显示方案,满足医疗电子、电力电子、工业自动化、车载中控等多种行业应用。 RK3568内置VOP控制器,支持三路视频同时输出,其显示通路连接关系如下:  三屏同显    双屏同显......
  • RK3568开发笔记(九):开发板buildroot固件调通RS485口,运行项目中RS485协议调试工具Demo
    前言  上一篇已经将Qt移植过去了,此时我们移植整体应用不是什么问题了,那么现在应用对外得接口使用了RS485接口,板载了一个RS485,于是需要调通,兼容这个开发板得RS485。 补充  看起来很简单,弄起来不懂得就是不懂,懂得虽然懂还得花时间去研究一下开发板特性,与厂家沟通下,......
  • 迅为RK3399开发板创建android工程
    打开 AndroidStudio 软件,点击“StartanewAndroidStudioproject”新建一个 NativeC++工程(因为我们要调用本地库,所以要创建这个 C++实例工程),点击“Next”2.填写创建信息,如下图所示。最后点击“finish”,等待几分钟,创建工程完成。3.在开始写代码前先编译一下刚刚创建的工程,确......
  • RK3568开发笔记(八):开发板烧写buildroot固件(支持hdmi屏),搭建Qt交叉编译开发环境,编译一个D
    前言  前面发现开发板用ubuntu固件发现空间不够,本篇使用buildroot固件,来实现目标板运行qt界面应用。<br>烧写buildroot固件  这部分更详细的参照《RK3568开发笔记(六):开发板烧写ubuntu固件(支持mipi屏)》的步骤,本质上烧写都是一样的,只是不同的update.img。步骤一:下载镜像  ......
  • RK3568开发笔记(八):开发板烧写buildroot固件(支持hdmi屏),搭建Qt交叉编译开发环境,编译一个D
    前言  前面发现开发板用ubuntu固件发现空间不够,本篇使用buildroot固件,来实现目标板运行qt界面应用。 烧写buildroot固件  这部分更详细的参照《RK3568开发笔记(六):开发板烧写ubuntu固件(支持mipi屏)》的步骤,本质上烧写都是一样的,只是不同的update.img。步骤一:下载......