一、前言

前文介绍了文件io的驱动方式,可以用于led点灯灭灯或者一些简单的不需求时序控制的ic操作,但是用于功能类ic,如AD采集芯片等时序控制需求高的,就不行了,这时候就需求高速io去实现指定的芯片手册时序逻辑,来完成ic的驱动。前文也介绍了一些高速io的驱动方式,如hx711芯片驱动,如未发布文章的AD7606驱动源码资源,都是使用高速io驱动的方式,但是经测试,io的速率还未开发到极致,是因为未直接操作底层寄存器的原因,还是经过包装,但是io速率已经满足大部分ic驱动开发,本编文章的目的也是介绍和详细写出各种方式io的速度测试方法,针对于不同的需求可以设计不同的驱动。

目前总结有io有几种驱动方式

1.应用层文件io驱动方式。优点:利用底层自带的gpio驱动,免去独立开发驱动。缺点:io驱动慢,无法适用于大部分ic,只能简单用于led操作,按键检测,和简单的ic。

2.驱动层gpio操作方式。优点:简单一些。缺点:需要搭配复杂的开发环境,io速度也不是极限,仍然感觉有限制,如无延时的操作一个io高低电平,会有500ns的保持时间,怀疑包装函数中有保护延时。

3.驱动层寄存器操作方式。优点:速度快。缺点:需要搭配复杂的开发环境,操作麻烦一些。而且在写驱动程序时需要查询芯片手册挨个引脚去对应配置地址等信息。

二、环境

宿主机:window10,Ubuntu16.04

目标及:a40i,linux3.10

三、正文

主要说明3种方式种io操作的步骤和效果对比

1.应用层文件io驱动方式

程序如下,文件方式驱动一个io无限正反转

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char *argv[])
{while(1){system("echo 1 > /sys/class/gpio_sw/PG9/data");//usleep(10000);system("echo 0 > /sys/class/gpio_sw/PG9/data");//usleep(10000);}return 0;
}

适用逻辑分析仪测试io反转速率效果如下图所示

这里就不放图了,速度很慢的说,周期在200us以上,没得看

结论:慢

2.驱动层gpio操作方式(常规操作,非设备树,传统方式)

程序如下,底层gpio封装函数驱动gpio方式

#include <linux/init.h>
#include <linux/module.h>
#include <linux/gpio.h>
#include <linux/delay.h>
//#include <mach/platform.h> //PAD_GPIO_C#define SUNXI_PA_BASE    0
#define SUNXI_PB_BASE   32
#define SUNXI_PC_BASE   64
#define SUNXI_PD_BASE   96
#define SUNXI_PE_BASE   128
#define SUNXI_PF_BASE   160
#define SUNXI_PG_BASE   192
#define SUNXI_PH_BASE   224
#define SUNXI_PI_BASE   256
#define SUNXI_PJ_BASE   288
#define SUNXI_PK_BASE   320
#define SUNXI_PL_BASE   352
#define SUNXI_PM_BASE   384
#define SUNXI_PN_BASE   416
#define SUNXI_PO_BASE   448
#define AXP_PIN_BASE    1024
/* sunxi gpio name space */
#define GPIOA(n)    (SUNXI_PA_BASE + (n))
#define GPIOB(n)    (SUNXI_PB_BASE + (n))
#define GPIOC(n)    (SUNXI_PC_BASE + (n))
#define GPIOD(n)    (SUNXI_PD_BASE + (n))
#define GPIOE(n)    (SUNXI_PE_BASE + (n))
#define GPIOF(n)    (SUNXI_PF_BASE + (n))
#define GPIOG(n)    (SUNXI_PG_BASE + (n))
#define GPIOH(n)    (SUNXI_PH_BASE + (n))
#define GPIOI(n)    (SUNXI_PI_BASE + (n))
#define GPIOJ(n)    (SUNXI_PJ_BASE + (n))
#define GPIOK(n)    (SUNXI_PK_BASE + (n))
#define GPIOL(n)    (SUNXI_PL_BASE + (n))
#define GPIOM(n)    (SUNXI_PM_BASE + (n))
#define GPION(n)    (SUNXI_PN_BASE + (n))
#define GPIOO(n)    (SUNXI_PO_BASE + (n))
#define GPIO_AXP(n) (AXP_PIN_BASE  + (n))//声明描述LED硬件相关的数据结构
struct led_resource {int gpio; //GPIO软件编号char *name; //LED的名称
};//定义初始化LED灯的硬件信息对象
static struct led_resource led_info[] = {{.name = "SCL1",.gpio = GPIOG(2)},{.name = "SDA1",.gpio = GPIOG(0)},
};//入口:insmod
static int led_init(void)
{int i;int num=1000;for(i = 0; i < ARRAY_SIZE(led_info); i++) {int result = gpio_request(led_info[i].gpio,led_info[i].name);//先向内核申请GPIO硬件资源;if(result!=0){//判断申请的GPIO资源是否成功,失败返回提示信息printk(KERN_ERR "GPIO%d has used...led init err!\n",led_info[i].gpio);//打印错误信息return -1;}gpio_direction_output(led_info[i].gpio, 0);//设置输入、输出GPIO方向,设置为输出功能,输出0}//2.然后配置GPIO为输出功能,输出0,开灯while(num--){gpio_set_value(194, 1);gpio_set_value(192, 1);gpio_set_value(194, 0);gpio_set_value(192, 0);}printk(KERN_INFO "led init ok...\n");//打印提示信息return 0;
}//出口:rmmod
static void led_exit(void)
{int i;int num=1000;while(num--){gpio_set_value(led_info[0].gpio, 1);gpio_set_value(led_info[1].gpio, 1);gpio_set_value(led_info[0].gpio, 0);gpio_set_value(led_info[1].gpio, 0);}for(i = 0; i < ARRAY_SIZE(led_info); i++) {gpio_free(led_info[i].gpio);//释放GPIO硬件资源} printk(KERN_INFO "led exit...\n");//打印提示信息
}
module_init(led_init);//三要素 必须有
module_exit(led_exit);//三要素 必须有
MODULE_LICENSE("GPL");//三要素 必须有
MODULE_AUTHOR("kbq-1950361006@qq.com");//模块作者的声明
MODULE_DESCRIPTION("HX711 Driver");//当前模块的功能描述

使用逻辑分析仪查看测试效果如下图所示

两个io

一个io

示波器测试结果:

结论:可以发现高低电平切换延时大概有500ns左右,但是这个500ns是哪里来的暂时还未发现,应该是gpio开放接口的一种保护吧,但是有些时候更高级的ic是不能容忍500ns的延时的,所以还没到极致,还需要更快的速度,快快快

2.驱动层gpio操作方式(设备树方式,传统方式)

程序如下,调用设备树驱动方式

我的引脚为PB10

设备树添加如下

 jkbuzzer {compatible = "jk,buzzer";gpios = <&pio 1 8 1 1 1 1>;clocks = <&clk_pio>;};

具体io配置如下

 gpio = <&pio   1   1   1   1   1  0>;|      |    |   |   |   |   |  |-------------------表示有效电平|      |    |   |   |   |   |----------------------上下拉, 0关闭功能, 1上拉, 2下拉, 3保留|      |    |   |   |   |-------------------------驱动力,电流等级(0 - 3),级别越高,输出电流越大|      |    |   |   |----------------------------gpio功能类型,0输入, 1输出, 6和外部中断,7关闭功能(具体查手册)|      |    |   |------------------------------pin bank 内偏移(即组内第几个io口).|      |    |---------------------------------哪组gpio, PA(0),PB(1),PC(2),PD(3),PE(4),PF(5),PG(6),PH(7),PI(8),PJ(9),PK(10),PL(11)|      |--------------------------------------指向哪个gpio控制器,  pio / r_pio(PL组)|-----------------------------------------------------属性名字(随便命名)

程序如下

#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/sys_config.h>
#include <linux/delay.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/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>/* 1. 确定主设备号                                                                 */
static int major = 0;
static struct class *led_class;
static int 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)
{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;err = copy_from_user(&status, buf, 1);/* 根据次设备号和status控制LED */gpio_set_value(led_gpio, status);   return 1;
}static int led_drv_open (struct inode *node, struct file *file)
{/* 根据次设备号初始化LED */gpio_direction_output(led_gpio, 0);return 0;
}static int led_drv_close (struct inode *node, struct file *file)
{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结构体告诉内核:注册驱动程序*/
int myprobe(struct platform_device *pdev)
{//int err;/* 4.1 设备树中定义有: gpios=<...>;  */struct device_node *nd = pdev->dev.of_node;struct gpio_config config;printk("gpio count:%d\n", of_gpio_named_count(nd, "gpios"));led_gpio = of_get_named_gpio_flags(nd, "gpios", 0, (enum of_gpio_flags *)&config);if (!gpio_is_valid(led_gpio))printk("gpio isn't valid\n");if (gpio_request(led_gpio, pdev->name) < 0)printk("gpio request failed %d\n", led_gpio);/* 4.2 注册file_operations   */major = register_chrdev(0, "kbq_led", &led_drv);  /* /dev/led */led_class = class_create(THIS_MODULE, "led_class");if (IS_ERR(led_class)) {printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);unregister_chrdev(major, "led");gpio_free(led_gpio);return PTR_ERR(led_class);}device_create(led_class, NULL, MKDEV(major, 0), NULL, "kbq_led%d", 0); /* /dev/100ask_led0 */printk("gpio is ok\n");return 0;}int myremove(struct platform_device *pdev)
{device_destroy(led_class, MKDEV(major, 0));class_destroy(led_class);unregister_chrdev(major, "kbq_led");gpio_free(led_gpio);printk("gpio remove ...\n");return 0;
}struct of_device_id ids[] = {{.compatible = "jk,buzzer"},{},
};
/* 1. 定义platform_driver */
static struct platform_driver chip_demo_gpio_driver = {.probe      = myprobe,.remove     = myremove,.driver     = {.name   = "mydrv",.of_match_table = ids,},
};
/* 2. 在入口函数注册platform_driver */
static int __init led_init(void)
{int err;err = platform_driver_register(&chip_demo_gpio_driver); return err;
}
/* 3. 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数*     卸载platform_driver*/
static void __exit led_exit(void)
{platform_driver_unregister(&chip_demo_gpio_driver);
}
module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");

测试程序如下

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <poll.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
char *keyscan_PATH = "/dev/kbq_led0";
int main(int argc, char **argv)
{int fd;char status;/* 打开文件 */fd = open(keyscan_PATH, O_RDWR);if (fd == -1){printf("can not open file %s\n", keyscan_PATH);return -1;}if(!strcmp(argv[1], "on")){//判断第二个参数是否为onstatus=1;write(fd, &status, sizeof(status));}else if(!strcmp(argv[1], "off")){//判断第二个参数是否为offstatus=0;write(fd, &status, sizeof(status));}    printf("led=%d,,,,",status);close(fd);return 0;
}

交叉编译命令:

/root/workspace/allwinner/A40i/bsp/lichee/out/sun8iw11p1/linux/common/buildroot/host/opt/ext-toolchain/bin/arm-linux-gnueabihf-g++ led_test.c -o ledtest

结论:这个设备树的测试方式之前使用whiile循环方式也是同上结果,有500ns的电平延时,具体不知道是为什么,不知道是不是gpio_set_value的问题,用gpiod_set_value的方式还缺少头文件

但是收获是已经成功调用到设备树去驱动程序了

3.驱动层gpio操作方式(寄存器方式)

全志A40i的芯片手册中GPIO引脚说明部分如下图所示,以GPIOA为例

图1:GPIO起始地址

图2:GPIO各配配置和各组起始地址计算方式

图3:GPIO模式配置地址+默认配置值+配置引脚对应位bit

图4:GPIO输入输出配置地址

图5:GPIO驱动能力配置地址

图6:GPIO上拉下拉模式配置地址

A40i的GPIO引脚配置很少,而且整体GPIO速率不是很高,没有单独配置GPIO的速率能力,很愁人,看来想用A40i驱动高速率ic得用专用外设接口spi或者采用FPGA芯片了,啊啊啊啊

使用寄存器的测试代码如下:(配置GPIOB10)

#include <linux/module.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 <asm/io.h>/* 寄存器物理地址 */
#define GPIOB_Congure_Register  (0x01C20800+0x0028) //GPIOB8地址,input、output、disable设置
#define GPIOB_Data_Register     (0x01C20800+0x0034) //GPIOB8地址,data读取、高低电平设置
#define GPIOB_Driving_Register  (0X01C20800+0x0038) //GPIOB8地址,引脚驱动能力设置
#define GPIOB_PULL_Register     (0X01C20800+0x0040) //GPIOB8地址,上拉、下拉设置//static void __iomem *GPIOB_Congure;//用writel形式
//static void __iomem *GPIOB_Data;//用writel形式
static volatile unsigned int *GPIOB_Congure;//直接用指针形式,用此定义
static volatile unsigned int *GPIOB_Data;//直接用指针形式,用此定义
/*unsigned int Io_buff;
void led_Io_High(void __iomem *ADGPIO_DR, unsigned char GPIO_id)
{Io_buff = readl(ADGPIO_DR);Io_buff|= (1<<GPIO_id); writel(Io_buff, ADGPIO_DR);
}
void led_Io_Low(void __iomem *ADGPIO_DR, unsigned char GPIO_id)
{Io_buff = readl(ADGPIO_DR);Io_buff &= ~(1<<GPIO_id);       writel(Io_buff,ADGPIO_DR);
}*/
//入口:insmod
static int led_init(void)
{unsigned int val = 0;unsigned long number=1000;/* 初始化GPIO *//* 1、寄存器地址映射 */GPIOB_Congure = ioremap(GPIOB_Congure_Register, 4);GPIOB_Data = ioremap(GPIOB_Data_Register, 4);/* 4、设置GPIO为输出功能 */val = readl(GPIOB_Congure);val &= 0xfffffff9;//将PB8设置为0x001为output模式,其余数据与1想与,保持不变writel(val, GPIOB_Congure);while(number--){//led_Io_Low(GPIOB_Data,8);//led_Io_High(GPIOB_Data,8);*GPIOB_Data &= ~(1<<8);*GPIOB_Data |= (1<<8);}printk(KERN_INFO "led init ok...\n");//打印提示信息return 0;
}//出口:rmmod
static void led_exit(void)
{printk(KERN_INFO "led exit...\n");//打印提示信息
}module_init(led_init);//三要素 必须有
module_exit(led_exit);//三要素 必须有
MODULE_LICENSE("GPL");//三要素 必须有
MODULE_AUTHOR("kbq-1950361006@qq.com");//模块作者的声明
MODULE_DESCRIPTION("led Driver");//当前模块的功能描述

新更新代码

#include <linux/module.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 <asm/io.h>/* 寄存器物理地址 */
#define GPIOB_Congure_Register  (0x01C20800+0x0028) //GPIOB8地址,input、output、disable设置
#define GPIOB_Data_Register     (0x01C20800+0x0034) //GPIOB8地址,data读取、高低电平设置
#define GPIOB_Driving_Register  (0X01C20800+0x0038) //GPIOB8地址,引脚驱动能力设置
#define GPIOB_PULL_Register     (0X01C20800+0x0040) //GPIOB8地址,上拉、下拉设置static void __iomem *GPIOB_Congure;//用writel形式
static void __iomem *GPIOB_Data;//用writel形式
static void __iomem *GPIOB_Driving;//用writel形式
static void __iomem *GPIOB_PULL;//用writel形式
//static volatile unsigned int *GPIOB_Congure;//直接用指针形式,用此定义//volatile禁止优化
//static volatile unsigned int *GPIOB_Data;//直接用指针形式,用此定义//volatile禁止优化
unsigned int Io_buff;
void led_Io_High(void __iomem *ADGPIO_DR, unsigned char GPIO_id)
{Io_buff = readl(ADGPIO_DR);Io_buff|= (1<<GPIO_id); writel(Io_buff, ADGPIO_DR);
}
void led_Io_Low(void __iomem *ADGPIO_DR, unsigned char GPIO_id)
{Io_buff = readl(ADGPIO_DR);Io_buff &= ~(1<<GPIO_id);       writel(Io_buff,ADGPIO_DR);
}
//入口:insmod
static int led_init(void)
{unsigned int config_val = 0;unsigned int drive_val = 0;unsigned long number=10000;/* 初始化GPIO *//* 1、寄存器地址映射 */GPIOB_Congure = ioremap(GPIOB_Congure_Register, 4);GPIOB_Data = ioremap(GPIOB_Data_Register, 4);GPIOB_Driving = ioremap(GPIOB_Driving_Register, 4);/* 2、设置GPIO为输出功能 */config_val = readl(GPIOB_Congure);//读取配置printk(KERN_INFO "before config_val=%x\n",config_val);//将PB8、PB9设置为0x001为output模式,其余数据与1想与,保持不变,对应手册,一个字符就是一个io,最高位空,可以位0,默认为0x77777777//设置引脚具体数值见手册,常规000:input 001:output 010~110:见手册 111:IO disableconfig_val |= 0x000000ff;//先或上需要配置位的最高值config_val &= 0xffffff11;//在与上需要配置位的配置值,以防此驱动加载时无法向上配置printk(KERN_INFO "after config_val=%x\n",config_val);writel(config_val, GPIOB_Congure);//写入配置/* 3、设置GPIO驱动能力 *///暂不设置,保持默认level1/*drive_val = readl(GPIOB_Driving);//读取配置printk(KERN_INFO "before drive_val=%x\n",drive_val);//将PB8、PB9设置为0x11为level3驱动能力,其余数据与1想与,保持不变,对应手册,一个字符就是两个io,默认为0x555555//设置引脚具体数值见手册,常规00:level0 01:level1 02:level2 03:level3drive_val |= 0x000f0000;//先或上需要配置位的最高值drive_val &= 0xffffffff;//在与上需要配置位的配置值,以防此驱动加载时无法向上配置printk(KERN_INFO "after drive_val=%x\n",drive_val);writel(drive_val, GPIOB_Driving);//写入配置*//* 4、设置GPIO pull上下拉 *///暂不设置,保持默认无上拉下拉while(number--){led_Io_Low(GPIOB_Data,9);led_Io_High(GPIOB_Data,9);}printk(KERN_INFO "led init ok...\n");//打印提示信息return 0;
}//出口:rmmod
static void led_exit(void)
{unsigned long number=10000;while(number--){led_Io_Low(GPIOB_Data,8);led_Io_Low(GPIOB_Data,9);led_Io_High(GPIOB_Data,8);led_Io_High(GPIOB_Data,9);}printk(KERN_INFO "led exit...\n");//打印提示信息
}module_init(led_init);//三要素 必须有
module_exit(led_exit);//三要素 必须有
MODULE_LICENSE("GPL");//三要素 必须有
MODULE_AUTHOR("kbq-1950361006@qq.com");//模块作者的声明
MODULE_DESCRIPTION("led Driver");//当前模块的功能描述

读取gpio

 unsigned int Io_read=0;Io_read = readl(GPIOB_Data);   Io_read = (Io_read & (1<<9)) ? 1 : 0;printk(KERN_INFO "Io_read=%d\n",Io_read);

用逻辑分析仪得出的测试结果图如下图所示:

示波器测试结果:

可以看见,高低电平转换时间大概在200ns左右,比起使用gpio函数速度快了2.5倍,目前使用寄存器最快的方式了,再也没有更快的方式可以测试了,难道A40i普通gpio的操作速度就这样了吗,有些失望,但是又无可奈何,毕竟国产的芯片本身不多,能有好的平台去使用和学习更不多,以后有机会尝试一下RK3399。

优点:电平反转时间最快200ns,比起使用GPIO操作io速度快了2.5倍。

缺点:配置io时需要一个一个引脚的去对应寄存器,很麻烦,一不留神就会搞错。容易被其他应用申请走io。

4.驱动层gpio操作方式(传统方式+寄存器方式)

此方式结合传统方式与寄存器方式,将初始化函数使用传统方式,便于对gpio的管理,申请,比较标准,操作gpio时如果需要速率,使用寄存器方式,如果时一般芯片,使用传统库函数方式操作gpio,最推荐的是使用此方法。经测试,在使用寄存器初始化gpio后,在使用传统方式申请可将gpio申请走,所以使用寄存器申请gpio一个是特别麻烦,一个是比较危险,io容易被其他应用使用导致自身不好使。

优点:电平反转时间最快200ns,比起使用GPIO操作io速度快了2.5倍。

缺点:配置简单,安全,使用方法标准。

在不想使用设备树的情况下强烈推荐此方法(适用于不是专业搞linux驱动开发,只是偶然用到linux驱动,写一个使用的开发工程师,如果有用,请帮我留言回复get到了,你的留言是对我最大的支持和动力哦,奥里给!)

四、结语

学习、积累、开拓

A40i使用笔记:GPIO操作方式(用于测试设备io驱动性能)(传统方式、设备树方式、寄存器方式操作GPIO)相关推荐

  1. 嵌入式学习笔记——使用寄存器编程操作GPIO

    使用寄存器编程操作GPIO 前言 GPIO相关的寄存器 GPIO 端口模式寄存器 (GPIOx_MODER) (x = A..I) 位操作 GPIO 端口输出类型寄存器 (GPIOx_OTYPER) ...

  2. A40i使用笔记:调用系统自带驱动GT911触摸屏

    一.前言 在一般情况下使用电容触摸屏时,都是使用USB直接驱动,但是在前文中我就提及过遇到的问题,就是USB触摸屏和我是用平台不是特别兼容的问题,问题现象在复述一遍,大概就是使用linux核心板USB ...

  3. linux设备树sysfs,迅为-iMX6开发板-设备树内核-sys方式控制GPIO

    本文档主要讲解迅为-iMX6 开发板,通过 sys 文件的方式来控制 GPIO. 要通过 sys 控制 GPIO,需要做以下几步操作: 1 开启内核中的"GPIO_SYSFS"驱动 ...

  4. RK3399驱动开发 | 01 -RK3399 gpio的使用(用户态和设备树两种方式)

    一.RK3399的GPIO RK3399有5组GPIO,GPIO0-GPIO4,每一组GPIO成为一个GPIO bank,每组GPIO包含32个引脚,需要注意,不是所有 bank 都有全部编号,例如 ...

  5. Linux——Linux驱动之设备树下platform总线驱动编写实战(手把手教你设备树下platform总线利用GPIO控制蜂鸣器完整实现过程)

    [系列专栏]:博主结合工作实践输出的,解决实际问题的专栏,朋友们看过来! <QT开发实战> <嵌入式通用开发实战>

  6. Zynq SOC学习笔记之设备树

    一. 概述 DTS即DeviceTree Source 设备树源码,是一种描述硬件的数据结构 以树状节点的方式描述一个设备的各种硬件信息细节:CPU.GPIO.时钟.中断.内存等,形成类似文本文件dt ...

  7. Linux设备模型、平台设备驱动、设备树(device tree)、GPIO子系统以及pinctrl子系统介绍

    文章目录 一.Linux设备模型介绍 (1)设备驱动模型总体介绍 (2)设备驱动模型文件表现 (3)设备驱动模型工作原理 [1]总线 [2]设备 [3]驱动 [4]注册流程 二.平台设备驱动介绍 (1 ...

  8. 嵌入式编程笔记之六--设备树初体验

    设备树的起源 设备树(Device Tree)是一种描述硬件资源的数据结构,它由 uboot 传递给 Linux 内核,被内核解析,内核根据设备树中的硬件描述信息加载利用相应驱动资源.在引入设备树之前 ...

  9. 迅为2K1000龙芯开发板pmon 下操作 GPIO

    我们可以来学习如何在 pmon 下操作 gpio 了, 为什么要把这个需求单独拿出来讲呢? 因为有的时候我们做了一款产品, 在特定的环境下需要让 GPIO 在上电时就是就保证是一个确定的电平, 如高电 ...

最新文章

  1. 改变gazebo背景颜色
  2. Android --- 详细介绍透明式状态栏和沉浸式状态栏
  3. 【数据分析R语言系列】R和RStudio的下载和安装, R在 Ubuntu 和CentOS 系统下的安装
  4. 使用SAP云平台Portal service的前置条件
  5. 雪城大学信息安全讲义 3.2 Set-UID 程序的漏洞
  6. python 帮助 autocad_python 使用pyautocad操作AutoCAD
  7. python搭建https代理服务器_使用NGINX作为HTTPS正向代理服务器
  8. 刺激战场测试fps软件,绝地求生刺激战场通过GLTools实时显示游戏帧数方法
  9. 高程数据的色彩渲染+光照
  10. 跨站脚本攻击(XSS)
  11. android 拨号隐藏号码,技巧:手机隐藏代码大集合 知道五个以上是大神
  12. 报错Error configuring application listener of class jdbc.ContextListener 解决办法之一
  13. C++随机设置壁纸小软件
  14. ppt图片特效 c语言实现,用了这么久的PPT,才知道PPT可以一键生成特效图片!太好看了...
  15. RecyclerView条目复用导致混乱的解决方案之一
  16. 推荐电影:亚当桑德勒的《我盛大的同志婚礼》
  17. 详解ABAP Selection Screens
  18. IE浏览器自动跳转edge怎么恢复
  19. uniapp扫码调用支付宝扫码
  20. 计算机网络交换机配实验报告,交换机基本配置实验报告

热门文章

  1. 全方位讲解硬件防火墙的选择(转)
  2. python制作股票图表怎么看_Python 数据可视化实战:使用 PyQt5 和 Echarts 打造股票数据看板...
  3. 物联网WiFi/BT/ZigBee芯片
  4. 笔记本电脑如何完整并安全地清除硬盘里的所有数据?
  5. 沟通技巧系列 - 给予和接受反馈的正确姿势
  6. 【MFC】Ribbon界面开发(二)
  7. 几种API调用认证方案浅析
  8. 微信小程序-获取当前城市位置
  9. OnlineJudge平台(负载均衡)
  10. 记录:指针仪表盘视觉读取项目的学习过程