Linux下GPIO驱动详解文章

合集下载

嵌入式Linux下GPIO驱动程序的开发及应用

嵌入式Linux下GPIO驱动程序的开发及应用

第28卷第4期增刊 2007年4月仪 器 仪 表 学 报Chinese Jour nal of Scientif ic InstrumentVol.28No.4Apr.2007 嵌入式L inux 下GPIO 驱动程序的开发及应用3何 泉,贺玉梅(北京化工大学信息科学与技术学院 北京 100029)摘 要:嵌入式Linux 是一种适用于嵌入式系统的源码开放的占先式实时多任务操作系统,是目前操作系统领域中的一个热点,其重点与难点是驱动程序的开发。

开发嵌人式Linux 下的设备驱动程序,可以更好地利用新硬件特性,提高系统访问硬件的效率,改善整个应用系统的性能。

驱动程序修改非常方便,使应用系统非常灵活。

本文简要论述了基于A TM E L 公司嵌入式ARM 处理器芯片的嵌入式Linux 的GP IO 驱动程序的开发原理及流程。

关键词:嵌入式Linux ;ARM ;驱动程序;设备文件;GPIOInvest igat ion an d a pplicat ion of GP IO dr iver in t he embedded L inuxHe Quan ,He YuMei(School of I nf orma tion Science and Tec hnology BU CT ,Beij ing 100029,China )Abstract :Embedded Linu x ,w hich i s a full y real 2time kernel and applicable to embedded syst ems ,has bec o me a hot s 2po t in t he do main of op erati ng system at present.It s out line and difficult y is to investigat e drivers.Developi ng device dri vers o n embedded Lin ux can help using t he new devices ,and imp rovi ng t he e fficiency of access to t he new devices and t he p erformance cap abilit y.As drivers can be changed easil y ,t he system is very convenient and flexi ble.Thi s p a 2p er simpl y point s o ut t he element s and flow of t he GPIO driver in t he embedded Linux based o n t he A RM proces sor of A TMEL system.Key words :embedded Li nux ;A RM ;driver ;device file ;GPIO 3基金项目国家自然科学基金(6)、北京化工大学青年教师自然科学研究基金(QN 58)资助项目1 引 言随着半导体技术的飞速发展,嵌入式产品已经广泛应用于军事、消费电子、网络通信、工业控制等各个领域,这是嵌入式系统发展的必然趋势。

GPIO驱动原理

GPIO驱动原理

GPIO设备驱动原理
在Linux系统下,字符设备和块设备的主要区别是:在对字符设备发出读/写请求时,实际的硬件I/O操作就紧接着发生了。块设备则不然,它利用一块系统内存作缓冲区,当用户进程对设备请求能满足用户的要求,就返回请求的数据;如果不能,就调用请求函数来进行实际的I/O操作。块设备是主要针对磁盘等慢速译成模块以供动态加载。由于嵌入式Linux支持静态编译和动态加载两种模式,如果考虑到精简内核的需要,这里可以使用动态加载的方法来实现驱动的装载。
设备驱动程序必须向Linux核心或者它所在的子系统提供一个标准的接口。例如,USB驱动程序向Linux核心提供了一个设备文件I/O接口,GPIO设备驱动程序向GPIO子系统提供了GPIO设备接口,接着向核心提供了文件I/O和缓冲区的接口。

linux内核的gpiolib详解

linux内核的gpiolib详解

linux内核的gpiolib详解#include <linux/init.h> // __init __exit#include <linux/module.h> // module_init module_exit#include <mach/regs-gpio.h>#include <mach/gpio-bank.h>#include <asm/io.h> //writel#include <mach/gpio.h>#include <linux/leds.h>#include <asm/string.h>#define X210_LED_OFF 1U#define X210_LED_ON 0Ustruct led_classdev cdev1;struct led_classdev cdev2;struct led_classdev cdev3;void s5pv210_led1_set(struct led_classdev *led_cdev,enum led_brightness brightness);void s5pv210_led2_set(struct led_classdev *led_cdev,enum led_brightness brightness);void s5pv210_led3_set(struct led_classdev *led_cdev,enum led_brightness brightness);static struct gpio x210_led_gpio[] ={{ S5PV210_GPJ0(3), GPIOF_OUT_INIT_HIGH, "LED1" }, /* default to OFF */{ S5PV210_GPJ0(4), GPIOF_OUT_INIT_HIGH, "LED2" }, /* default to OFF */{ S5PV210_GPJ0(5), GPIOF_OUT_INIT_HIGH, "LED3" } /* default to OFF */};void s5pv210_led1_set(struct led_classdev *led_cdev,enum led_brightness brightness){printk(KERN_INFO "s5pv210_led1_set successful %d\n",brightness);if(brightness == LED_OFF){gpio_set_value(x210_led_gpio[0].gpio,X210_LED_OFF);}else{gpio_set_value(x210_led_gpio[0].gpio,X210_LED_ON);}}void s5pv210_led2_set(struct led_classdev *led_cdev,enum led_brightness brightness){printk(KERN_INFO "s5pv210_led2_set successful %d\n",brightness);if(brightness == LED_OFF){gpio_set_value(x210_led_gpio[1].gpio,X210_LED_OFF);}else{gpio_set_value(x210_led_gpio[1].gpio,X210_LED_ON);}}void s5pv210_led3_set(struct led_classdev *led_cdev,enum led_brightness brightness){printk(KERN_INFO "s5pv210_led3_set successful %d\n",brightness);if(brightness == LED_OFF){gpio_set_value(x210_led_gpio[2].gpio,X210_LED_OFF);}else{gpio_set_value(x210_led_gpio[2].gpio,X210_LED_ON);}}static int __init s5pv210_led_init(void){int ret = -1;printk(KERN_INFO "s5pv210_led_init successful \n");cdev1.brightness_set = s5pv210_led1_set; = "led1";ret = led_classdev_register(NULL, &cdev1);if (ret < 0){printk(KERN_WARNING "led_classdev_register fail \n");goto reg_err1;}cdev2.brightness_set = s5pv210_led2_set; = "led2";ret = led_classdev_register(NULL, &cdev2);if (ret < 0){printk(KERN_WARNING "led_classdev_register fail \n");goto reg_err2;}cdev3.brightness_set = s5pv210_led3_set; = "led3";ret = led_classdev_register(NULL, &cdev3);if (ret < 0){printk(KERN_WARNING "led_classdev_register fail \n");goto reg_err3;}ret = gpio_request_array(x210_led_gpio, ARRAY_SIZE(x210_led_gpio));if (ret){goto gpio_err;}return0;gpio_err:led_classdev_unregister(&cdev3);reg_err3:led_classdev_unregister(&cdev2);reg_err2:led_classdev_unregister(&cdev1);reg_err1:return ret;}static void __exit s5pv210_led_exit(void){printk(KERN_INFO "s5pv210_led_exit successful \n");gpio_free_array(x210_led_gpio, ARRAY_SIZE(x210_led_gpio));led_classdev_unregister(&cdev1);led_classdev_unregister(&cdev2);led_classdev_unregister(&cdev3);}module_init(s5pv210_led_init);module_exit(s5pv210_led_exit);// MODULE_xxx这种宏作⽤是⽤来添加模块描述信息MODULE_LICENSE("GPL"); // 描述模块的许可证MODULE_AUTHOR("musk"); // 描述模块的作者MODULE_DESCRIPTION("x210 LED driver"); // 描述模块的介绍信息MODULE_ALIAS("led_driver"); // 描述模块的别名信息View Code⼀. 什么是gpiolib1.1. linux中从2.6.35以后就开始有gpiolib库了,gpiolib的作⽤是对所有的gpio实⾏统⼀管理,因为驱动在⼯作的时候,会出现好⼏个驱动共同使⽤同⼀个gpio的情况;这会造成混乱。

linux内核gpio用法

linux内核gpio用法

linux内核gpio用法Linux内核对GPIO的使用是非常广泛的,本文将会通过几个步骤来解释如何在Linux内核中使用GPIO,包括GPIO的基本知识、配置GPIO、读取GPIO值、设置GPIO值和释放GPIO资源。

一、GPIO的基本知识GPIO(General Purpose Input/Output)是一种通用的输入/输出接口,它可以与各种设备进行连接,比如传感器、开关、LED等。

在Linux内核中,GPIO 被抽象为一个特殊的设备,可以通过相应的驱动程序进行读写操作。

每个GPIO引脚都被赋予了一个唯一的数字编号,这个编号称为GPIO号。

在不同的硬件平台上,GPIO号可能不同,因此在使用GPIO之前,需要先了解具体的GPIO号对应关系。

二、配置GPIO在使用GPIO之前,需要先配置GPIO的功能和方向,可以通过以下步骤来实现。

步骤1:加载GPIO驱动程序在Linux内核中,GPIO驱动程序以模块的形式存在,首先需要加载相应的GPIO 驱动程序。

可以使用如下命令加载GPIO驱动程序:modprobe gpio步骤2:导出GPIO引脚在Linux内核中,GPIO引脚默认是不可用的,需要先导出GPIO引脚,才能使用。

可以使用如下命令导出GPIO引脚:echo GPIO号> /sys/class/gpio/export其中,GPIO号为需要导出的GPIO引脚的编号。

步骤3:配置GPIO方向GPIO引脚有输入和输出两种方向,需要根据实际需求选择。

可以使用如下命令配置GPIO方向:echo in/out > /sys/class/gpio/gpioGPIO号/direction其中,in表示输入方向,out表示输出方向。

三、读取GPIO值配置好GPIO方向后,就可以读取GPIO引脚的值了。

可以使用如下命令读取GPIO值:cat /sys/class/gpio/gpioGPIO号/value其中,GPIO号为需要读取值的GPIO引脚的编号。

基于rk3568的linux驱动开发——gpio知识点 -回复

基于rk3568的linux驱动开发——gpio知识点 -回复

基于rk3568的linux驱动开发——gpio知识点-回复基于rk3568的Linux驱动开发——GPIO知识点GPIO(General Purpose Input/Output)是通用输入输出的意思,是嵌入式系统中的常用功能。

在rk3568芯片上,GPIO用于实现与外部设备的通信和控制,比如控制LED灯、键盘、电机等。

本文将介绍rk3568芯片上的GPIO控制器、GPIO驱动的开发以及GPIO 在Linux系统中的应用。

一、GPIO控制器在rk3568芯片中,GPIO控制器是用来控制GPIO端口的硬件模块。

每个GPIO控制器可以管理多个GPIO端口,每个GPIO端口可以被配置为输入或输出。

GPIO控制器通常包含寄存器用于配置和控制GPIO端口的功能,比如方向、电平等。

二、GPIO驱动的开发GPIO驱动是用于控制和管理GPIO功能的软件模块。

在Linux内核中,GPIO驱动通过sysfs接口暴露给用户空间,以便用户可以通过文件系统访问和控制GPIO端口。

以下是GPIO驱动的开发过程:1. 确定GPIO控制器和GPIO端口:首先需要确定要使用的GPIO控制器和GPIO端口。

在rk3568芯片手册中可以找到相应的信息。

2. 创建GPIO设备:在Linux内核中,GPIO驱动是通过GPIO子系统来管理的。

首先需要在设备树中添加GPIO设备描述,并分配一个唯一的GPIO号码。

3. 注册GPIO设备:在驱动的初始化函数中,需要调用相应的函数注册GPIO设备,以便系统能够识别和管理该设备。

4. 设置GPIO模式和方向:通过调用GPIO控制器的寄存器,可以设置GPIO端口的模式和方向。

例如,可以将GPIO端口配置为输入模式或输出模式。

5. 读取和写入GPIO值:读取GPIO值可以通过读取GPIO控制器的寄存器来实现,写入GPIO值可以通过写入GPIO控制器的寄存器来实现。

例如,可以将GPIO端口的电平设置为高或低。

基于rk3568的linux驱动开发——gpio知识点

基于rk3568的linux驱动开发——gpio知识点

基于rk3568的linux驱动开发——gpio知识点基于rk3568的Linux驱动开发——GPIO知识点一、引言GPIO(General Purpose Input/Output)通用输入/输出,是现代计算机系统中的一种常用接口,它可以根据需要配置为输入或输出。

通过GPIO 接口,我们可以与各种外设进行通信,如LED灯、按键、传感器等。

在基于Linux系统的嵌入式设备上开发驱动程序时,熟悉GPIO的使用是非常重要的一环。

本文将以RK3568芯片为例,详细介绍GPIO的相关知识点和在Linux驱动开发中的应用。

二、GPIO概述GPIO是系统中的一个基本的硬件资源,它可以通过软件的方式对其进行配置和控制。

在嵌入式设备中,通常将一部分GPIO引脚连接到外部可编程电路,以实现与外部设备的交互。

在Linux中,GPIO是以字符设备的形式存在,对应的设备驱动为"gpiolib"。

三、GPIO的驱动开发流程1. 导入头文件在驱动程序中,首先需要导入与GPIO相关的头文件。

对于基于RK3568芯片的开发,需要导入头文件"gpiolib.h"。

2. 分配GPIO资源在驱动程序中,需要使用到GPIO资源,如GPIO所在的GPIO Bank和GPIO Index等。

在RK3568芯片中,GPIO资源的分配是通过设备树(Device Tree)来进行的。

在设备树文件中,可以定义GPIO Bank和GPIO Index等信息,以及对应的GPIO方向(输入或输出)、电平(高电平或低电平)等属性。

在驱动程序中,可以通过设备树接口(Device Tree API)来获取这些GPIO资源。

3. GPIO的配置与控制在驱动程序中,首先要进行GPIO的初始化与配置。

可以通过函数"gpiod_get()"来打开指定的GPIO,并判断其是否有效。

如果成功打开GPIO,则可以使用函数"gpiod_direction_output()"或"gpiod_direction_input()"来设置GPIO的方向,分别作为输出或输入。

gpio子系统和pinctrl子系统(一)

gpio子系统和pinctrl子系统(一)

gpio⼦系统和pinctrl⼦系统(⼀)前⾔ 随着内核的发展,linux驱动框架在不断的变化。

很早很早以前,出现了gpio⼦系统,后来⼜出现了pinctrl⼦系统。

在⽹上很难看到⼀篇讲解这类⼦系统的⽂章。

就拿gpio操作来说吧,很多时候都是简单的调⽤gpio⼦系统提供的api,然后根据sdk说明⽂档写明的gpio号传参数,⾄于⾥⾯的⼯作过程对于驱动⼯程师⽽⾔就像个⿊盒⼦。

当我们⾃⼰设计的板⼦和demo板有很⼤变动时,问题就出现了。

⾸先遇到的是怎么配置pin(是基于设备树还是不基于设备树,基于设备树的话,怎么修改设备树关于pinctrl部分的内容,⾥⾯各个字段什么意思,怎么改),然后是在哪⾥配置pin(内核部分有哪些需要相应修改,还是不需要⼀点修改呢),接着就是怎么调试等等。

我想只有清楚了尽量多的gpio⼦系统和pinctrl⼦系统细节,才会更快更好的完成这些⼯作。

有些平台的实现没有使⽤内核提供的pinctrl⼦系统,⽽是继续采⽤在内核提供pinctrl⼦系统前⾃⼰实现的那套机制来pinmux操作,如omap,有些平台则基于pinctrl⼦系统来实现pinmux、pinconf的控制。

本⽂以gpio⼦系统为⼊⼝慢慢深⼊,最后分析pinctrl⼦系统。

如果有错误的地⽅,欢迎⼤家直接指出gpio⼦系统 gpio⼦系统帮助我们管理整个系统gpio的使⽤情况,同时通过sys⽂件系统导出了调试信息和应⽤层控制接⼝。

它内部实现主要提供了两类接⼝,⼀类给bsp⼯程师,⽤于注册gpio chip(也就是所谓的gpio控制器驱动),另⼀部分给驱动⼯程师使⽤,为驱动⼯程师屏蔽了不同gpio chip之间的区别,驱动⼯程师调⽤的api的最终操作流程会导向gpio对应的gpio chip的控制代码,也就是bsp的代码。

gpio⼦系统核⼼实现分析gpio⼦系统的内容在drivers/gpio⽂件夹下,主要⽂件有:devres.cgpiolib.cgpiolib-of.cgpiolib-acpi.cgpio-xxx.cdevres.c是针对gpio api增加的devres机制的⽀持,devres机制讲解请参考,gpiolib.c是gpio⼦系统的核⼼实现,gpiolib-of.c是对设备树的⽀持,gpiolib-acpi.c和acpi相关,不分析(acpi还未深⼊了解^_^),最后情景分析的时候,会找⼀个平台的gpio-xxx.c来分析。

linuxSPI驱动——gpio模拟spi驱动(三)

linuxSPI驱动——gpio模拟spi驱动(三)

linuxSPI驱动——gpio模拟spi驱动(三)⼀:⾸先在我的平台注册platform_device,保证能让spi-gpio.c能执⾏到probe函数。

1: struct spi_gpio_platform_data {2: unsigned sck;3: unsigned mosi;4: unsigned miso;5:6: u16 num_chipselect;7: };1: //#define NCS GPIO_PB(2) //定义SS所对应的GPIO接⼝编号2: //#define SCLK GPIO_PB(0) //定义SCLK所对应的GPIO接⼝编号3: //#define MOSI GPIO_PB(4) //定义SCLK所对应的GPIO接⼝编号4: //#define MISO GPIO_PB(1)5: static struct spi_gpio_platform_data jz_spi_gpio_data = {6: .sck = GPIO_PB(0), //GPIO_SPI_SCK,7: .mosi = GPIO_PB(4), //GPIO_SPI_MOSI,8: .miso = GPIO_PB(1), //GPIO_SPI_MISO,9: .num_chipselect = 1,10: };11:12: struct platform_device jz_spi_gpio_device = {13: .name = "spi_gpio",14: .id = 0,15: .dev = {16: .platform_data = &jz_spi_gpio_data,17: },18: };注册platform device1: platform_device_register(&jz_spi_gpio_device);⼆:注册platform_driver在spi_gpio.c⾥⾯注册platform driver1: MODULE_ALIAS("platform:" DRIVER_NAME);2:3: static struct platform_driver spi_gpio_driver = {4: = DRIVER_NAME,5: .driver.owner = THIS_MODULE,6: .remove = __exit_p(spi_gpio_remove),7: };8:9: static int __init spi_gpio_init(void)10: {11: return platform_driver_probe(&spi_gpio_driver, spi_gpio_probe);12: }13: module_init(spi_gpio_init);14:15: static void __exit spi_gpio_exit(void)16: {17: platform_driver_unregister(&spi_gpio_driver);18: }19: module_exit(spi_gpio_exit);20:21:22: MODULE_DESCRIPTION("SPI master driver using generic bitbanged GPIO ");23: MODULE_AUTHOR("David Brownell");24: MODULE_LICENSE("GPL");三:具体算法分析1: struct spi_gpio {2: struct spi_bitbang bitbang; /* gpio 模拟spi算法相关的结构 */3: struct spi_gpio_platform_data pdata; /* spi platform data 对应模拟spi的四个gpio编号 */4: struct platform_device *pdev; /* 对应注册的 platform device */5: };1:2: static int __init spi_gpio_probe(struct platform_device *pdev)3: {4: int status;5: struct spi_master *master;6: struct spi_gpio *spi_gpio;7: struct spi_gpio_platform_data *pdata;8: u16 master_flags = 0;9:10: pdata = pdev->dev.platform_data; /* 存放spi的四根gpio */11: #ifdef GENERIC_BITBANG12: if (!pdata || !pdata->num_chipselect)13: return -ENODEV;14: #endif15:16: /* 申请注册四个gpio */17: status = spi_gpio_request(pdata, dev_name(&pdev->dev), &master_flags);18: if (status < 0) {19: return status;20: }21:22: /* alloc a spi master ,master->dev->p->driver_data = &master[1]*/23: master = spi_alloc_master(&pdev->dev, sizeof *spi_gpio);24: if (!master) {25: status = -ENOMEM;26: goto gpio_free;27: }28: /* spi_gpio指向⼀块空间, 即指向mstaer[1]29: pdev->dev->p->driver_data = spi_gpio;30: 初始化spi_gpio31: */32: spi_gpio = spi_master_get_devdata(master);33: platform_set_drvdata(pdev, spi_gpio);34:35: spi_gpio->pdev = pdev;36: if (pdata)37: spi_gpio->pdata = *pdata;38:39: master->flags = master_flags;40: master->bus_num = pdev->id;41: master->num_chipselect = SPI_N_CHIPSEL;42: master->setup = spi_gpio_setup; /* setup ⽐如cs引脚申请 */43: master->cleanup = spi_gpio_cleanup;44: /* spi_gpio->bitbang.master = master */45: spi_gpio->bitbang.master = spi_master_get(master);46: spi_gpio->bitbang.chipselect = spi_gpio_chipselect;47: /* spi_gpio->bitbang.txrx_word 数组函数四个元素指针,分别指向spi四种mode算法函数 */ 48: if ((master_flags & (SPI_MASTER_NO_TX | SPI_MASTER_NO_RX)) == 0) {49: spi_gpio->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_txrx_word_mode0;50: spi_gpio->bitbang.txrx_word[SPI_MODE_1] = spi_gpio_txrx_word_mode1;51: spi_gpio->bitbang.txrx_word[SPI_MODE_2] = spi_gpio_txrx_word_mode2;52: spi_gpio->bitbang.txrx_word[SPI_MODE_3] = spi_gpio_txrx_word_mode3;53: } else {54: spi_gpio->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_spec_txrx_word_mode0;55: spi_gpio->bitbang.txrx_word[SPI_MODE_1] = spi_gpio_spec_txrx_word_mode1;56: spi_gpio->bitbang.txrx_word[SPI_MODE_2] = spi_gpio_spec_txrx_word_mode2;57: spi_gpio->bitbang.txrx_word[SPI_MODE_3] = spi_gpio_spec_txrx_word_mode3;58: }59: /* spi_gpio->bitbang.setup_transfer初始化传输的bits_per_word和speed */60: spi_gpio->bitbang.setup_transfer = spi_bitbang_setup_transfer;61: spi_gpio->bitbang.flags = SPI_CS_HIGH;62: /* spi_gpio->bitbang相关算法接⼝初始化 */63: status = spi_bitbang_start(&spi_gpio->bitbang);64: if (status < 0) {65: spi_master_put(spi_gpio->bitbang.master);66: gpio_free:67: if (SPI_MISO_GPIO != SPI_GPIO_NO_MISO)68: gpio_free(SPI_MISO_GPIO);69: if (SPI_MOSI_GPIO != SPI_GPIO_NO_MOSI)70: gpio_free(SPI_MOSI_GPIO);71: gpio_free(SPI_SCK_GPIO);72: spi_master_put(master);73: }74:75: return status;76: }四:总之最终让spi_gpi0整个对象存放了整个gpio模拟spi的算法结构;⽽pdev->dev->p->driver_data = spi_gpio; platform device和 platform driver两者match结果是:root@CarRadio:/# ls /sys/bus/platform/devices/spi_gpio.0/driver modalias power spi0.0 spi_master subsystem ueventroot@CarRadio:/# ls /sys/bus/platform/devices/spi_gpio.0/driver/spi_gpio.0 uevent。

介绍gpio的八种工作模式特点及应用场景

介绍gpio的八种工作模式特点及应用场景

标题:深度探讨GPIO的八种工作模式特点及应用场景在嵌入式系统中,GPIO(General Purpose Input/Output)是非常重要的接口,它可以在数字电路中扮演着非常重要的作用。

GPIO的工作模式多种多样,每种模式都有其特点和应用场景。

在本文中,我将深度探讨GPIO的八种工作模式特点以及在实际应用中的各种场景。

1. 输入模式- 简介:输入模式是最基础的GPIO工作模式,用于将外部信号输入到嵌入式系统中。

- 特点:具有高电平或低电平的状态,并能够接收外部传感器、开关等设备的信号。

- 应用场景:用于接收按钮、传感器等外部设备的输入信号,如温度传感器、光敏电阻等。

2. 输出模式- 简介:输出模式是将嵌入式系统中的数字信号输出到外部设备中。

- 特点:可以输出高电平或低电平的数字信号,控制外部设备的状态。

- 应用场景:用于控制LED灯、蜂鸣器、继电器等外部设备,实现各种实际应用。

3. 推挽输出- 简介:推挽输出是一种特殊的输出模式,可以输出较大的电流。

- 特点:输出信号可以直接驱动负载,不需要外部电路,具有较高的可靠性。

- 应用场景:用于驱动电机、舵机等高电流负载的驱动,如智能小车、机械臂等项目。

4. 开漏输出- 简介:开漏输出是一种适合于多路设备共享总线的输出模式。

- 特点:可用于实现多设备共享总线,并且可以实现硬件控制的通信协议。

- 应用场景:用于I2C、SPI等多设备共享总线的通信协议,以及控制LED显示器、LCD屏幕等设备。

5. 三态输出- 简介:三态输出是一种可以对外输出、内部拉高或拉低的输出模式。

- 特点:可以使输出引脚处于高阻态,避免对总线的冲突。

- 应用场景:多设备共享总线的通信协议中,避免总线冲突,保证通信的准确性。

6. 模拟输入- 简介:模拟输入模式是用于接收模拟信号的输入模式。

- 特点:可以接收模拟信号,并将其转换成数字信号,进行后续的处理。

- 应用场景:用于接收模拟传感器信号,如声音传感器、光线传感器等,进行模拟信号处理。

Linux下的gpio,gpiod教程

Linux下的gpio,gpiod教程

GPIO 应该是每个嵌入式设备都避免不了的。

最近在做项目的时候,也遇到这方面的问题,所以简单总结一下:现在内核里面多了gpiod的来控制gpio口,相对于原来的形式,使用gpiod的好处是我们申请后不进行free也没有什么问题。

但是你要是使用原来的方式后,一定要记得释放。

不释放的话可能会有问题。

#旧的GPIO使用实例DTS文件驱动文件调用# 新的GPIOD文档#头文件我们需要包含头文件#include <linux/gpio/consumer.h>看头文件里面包含的函数列表desc_to_gpiodevm_get_gpiod_from_chidevm_gpiod_getdevm_gpiod_get_arraydevm_gpiod_get_array_opdevm_gpiod_get_indexdevm_gpiod_get_index_opdevm_gpiod_get_optionaldevm_gpiod_putdevm_gpiod_put_arrayfwnode_get_named_gpiodgpio_to_descgpiod_cansleepgpiod_countgpiod_direction_inputgpiod_direction_outputgpiod_direction_output_gpiod_exportgpiod_export_linkgpiod_getgpiod_get_arraygpiod_get_array_optionagpiod_get_directiongpiod_get_indexgpiod_get_index_optionagpiod_get_optionalgpiod_get_raw_valuegpiod_get_raw_value_cangpiod_get_valuegpiod_get_value_cansleegpiod_is_active_lowgpiod_putgpiod_put_arraygpiod_set_array_valuegpiod_set_array_value_cgpiod_set_debouncegpiod_set_raw_array_valgpiod_set_raw_array_valgpiod_set_raw_valuegpiod_set_raw_value_cangpiod_set_valuegpiod_set_value_cansleegpiod_to_irqgpiod_unexport#获取gpio描述符和释放使用一下两个函数获取GPIO设备,多个设备时需要附带index参数。

linux gpio select编程

linux gpio select编程

linux gpio select编程全文共四篇示例,供读者参考第一篇示例:Linux GPIO是一种用于控制硬件设备的接口,它允许开发人员通过软件来控制嵌入式设备上的输入输出引脚。

GPIO在嵌入式系统中非常常见,因为它可以用来连接各种传感器、执行器以及其他外围设备。

在Linux系统下,开发人员可以通过文件系统访问GPIO接口,以实现对硬件设备的控制。

在Linux系统中,开发人员可以使用多种编程语言来访问GPIO接口,其中一个常见的方式是使用C语言编程。

在C语言中,可以通过打开/sys/class/gpio文件夹下的相应文件来操作GPIO引脚。

但是有时候,我们需要同时监听多个GPIO引脚的状态变化,并且需要在有变化时进行相应的处理。

这就需要使用select系统调用来实现。

在使用select系统调用进行GPIO编程之前,首先需要将GPIO引脚设置为输入模式,并且需要打开相应的GPIO文件。

如果我们要监听GPIO引脚17和18的状态变化,首先需要在/sys/class/gpio文件夹下分别创建gpio17和gpio18文件夹,并在其中创建direction文件,将其设置为"in",代表输入模式。

然后打开对应的value文件,即可实现对GPIO引脚17和18的状态监听。

接下来,我们可以编写一个C程序,使用select系统调用来监听GPIO引脚17和18的状态变化,并在有变化时进行相应的处理。

以下是一个简单的示例代码:```c#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <fcntl.h>#include <sys/select.h>#define GPIO17_FILE "/sys/class/gpio/gpio17/value"#define GPIO18_FILE "/sys/class/gpio/gpio18/value"// 打开GPIO文件gpio17_fd = open(GPIO17_FILE, O_RDONLY);gpio18_fd = open(GPIO18_FILE, O_RDONLY);while (1){// 监视GPIO文件FD_ZERO(&rfds);FD_SET(gpio17_fd, &rfds);FD_SET(gpio18_fd, &rfds);// 设置超时时间_sec = 5;_usec = 0;// 等待GPIO状态变化retval = select(2, &rfds, NULL, NULL, &tv); // 处理GPIO状态变化if (retval > 0){if (FD_ISSET(gpio17_fd, &rfds)){read(gpio17_fd, &value, 1);printf("GPIO17 value: %c\n", value);}if (FD_ISSET(gpio18_fd, &rfds)){read(gpio18_fd, &value, 1);printf("GPIO18 value: %c\n", value);}}}return 0;}```在这段代码中,我们打开了GPIO引脚17和18的value文件,并使用select系统调用来监听它们的状态变化。

gpioset gpioget用法

gpioset gpioget用法

GPIO(General Purpose Input/Output)是一种通用输入输出接口,可以用于连接不同外部设备,如传感器、执行器、LED等。

在嵌入式系统中,我们经常需要使用GPIO来控制外部设备的状态,这就需要使用一些工具来对GPIO进行设置和获取。

在Linux系统中,我们可以使用gpioset和gpioget这两个命令来实现对GPIO的设置和获取。

本文将介绍gpioset和gpioget的用法及相关注意事项。

一、gpioset的用法gpioset命令用于设置GPIO的状态,可以将GPIO设置为高电平、低电平或者反转电平。

其基本用法如下:1. 设置GPIO为高电平:gpioset <chip设备编号> <引脚编号>=12. 设置GPIO为低电平:gpioset <chip设备编号> <引脚编号>=03. 反转GPIO电平:gpioset <chip设备编号> <引脚编号>=2其中,<chip设备编号>为GPIO设备在系统中的编号,<引脚编号>为具体引脚的编号。

通过这些简单的命令,我们可以轻松地控制GPIO 的状态。

需要注意的是,使用gpioset命令设置GPIO状态时,需要保证所选的GPIO引脚是可编程的,并且拥有足够的权限。

否则,可能会出现权限不足的错误,导致操作失败。

二、gpioget的用法gpioget命令用于获取GPIO的状态,可以用来查看某个特定GPIO引脚当前的状态(高电平或低电平)。

其基本用法如下:1. 获取GPIO状态:gpioget <chip设备编号> <引脚编号>通过这个命令,我们可以查看指定GPIO引脚的当前状态,并据此进行相应的处理。

同样地,使用gpioget命令时也需要注意设备编号和引脚编号的选择,以及对GPIO的访问权限。

三、常见问题及解决方法在使用gpioset和gpioget命令时,可能会遇到一些常见的问题,下面进行逐一介绍及解决方法。

linuxgpio模拟i2c的使用用GPIO模拟I2C总线

linuxgpio模拟i2c的使用用GPIO模拟I2C总线

linuxgpio模拟i2c的使用用GPIO模拟I2C总线这个结构专门用于数据传输相关的addr为I2C设备地址,flags 为一些标志位,len为数据的长度,buf为数据。

这里宏定义的一些标志还是需要了解一下。

I2C_M_TEN表示10位设备地址I2C_M_RD读标志I2C_M_NOSTART无起始信号标志I2C_M_IGNORE_NAK忽略应答信号标志回到for,这里的num代表有几个struct i2c_msg,进入for语句,接下来是个if语句,判断这个设备是否定义了I2C_M_NOSTART 标志,这个标志主要用于写操作时,不必重新发送起始信号和设备地址,但是对于读操作就不同了,要调用i2c_repstart这个函数去重新发送起始信号,调用bit_doAddress函数去重新构造设备地址字节,来看这个函数。

1.static int bit_doAddress(struct i2c_adapter *i2c_adap, stru ct i2c_msg *msg)2.{3.unsigned short flags = msg->flags;4.unsigned short nak_ok = msg->flags & I2C_M_IGNORE_ NAK;5.struct i2c_algo_bit_data *adap = i2c_adap->algo_data;6.7.unsigned char addr;8.int ret, retries;9.10.retries = nak_ok ? 0 : i2c_adap->retries;11.12.if (flags & I2C_M_TEN) {13./* a ten bit address */14.addr = 0xf0 | ((msg->addr >> 7) & 0x03);15.bit_dbg(2, &i2c_adap->dev, "addr0: %d\n", addr);16./* try extended address code...*/17.ret = try_address(i2c_adap, addr, retries);18.if ((ret != 1) && !nak_ok) {19.dev_err(&i2c_adap->dev,20."died at extended address code\n");21.return -EREMOTEIO;22.}23./* the remaining 8 bit address */24.ret = i2c_outb(i2c_adap, msg->addr & 0x7f);25.if ((ret != 1) && !nak_ok) {26./* the chip did not ack / xmission error occurred */27.dev_err(&i2c_adap->dev, "died at 2nd address code\n ");28.return -EREMOTEIO;29.}30.if (flags & I2C_M_RD) {31.bit_dbg(3, &i2c_adap->dev, "emitting repeated "32."start condition\n");33.i2c_repstart(adap);34./* okay, now switch into reading mode */35.addr |= 0x01;36.ret = try_address(i2c_adap, addr, retries);37.if ((ret != 1) && !nak_ok) {38.dev_err(&i2c_adap->dev,39."died at repeated address code\n");40.return -EREMOTEIO;41.}42.}43.} else { /* normal 7bit address */44.addr = msg->addr << 1;45.if (flags & I2C_M_RD)46.addr |= 1;47.if (flags & I2C_M_REV_DIR_ADDR)48.addr ^= 1;49.ret = try_address(i2c_adap, addr, retries);50.if ((ret != 1) && !nak_ok)51.return -ENXIO;52.}53.54.return 0;55.}这里先做了一个判断,10位设备地址和7位设备地址分别做不同的处理,通常一条I2C总线上不会挂那么多I2C设备,所以10位地址不常用,直接看对7位地址的处理。

基于rk3568的linux驱动开发——gpio知识点 -回复

基于rk3568的linux驱动开发——gpio知识点 -回复

基于rk3568的linux驱动开发——gpio知识点-回复什么是波形单位换算?在物理学中,波是一种传播能量和信息的方式。

波动现象广泛存在于我们生活的各个方面,比如光、声音、水波等等。

而波的传播过程中,我们往往需要对波的性质进行度量和换算,这就需要用到波形单位换算。

波形单位换算是一种将不同的波长、频率、速度等物理量互相转换的方法,帮助我们更好地理解和处理波动现象。

波形单位的基本概念在进行波形单位换算之前,我们首先需要了解一些基本概念。

其中最重要的三个概念是波长、频率和波速。

波长(λ)是指在一个完整的波周期中,波的传播距离。

以正弦波为例,波长就是峰值或谷值之间的距离。

频率(f)是指波的周期性,也就是波动过程中的重复次数。

频率用赫兹(Hz)作为单位,表示每秒钟内波动的周期数。

波速(v)是指波动传播的速度,也可以理解为波动能量在单位时间内传播的距离。

波速和波长、频率有着密切的关系,可以用以下公式表示:v = f * λ。

波形单位换算的步骤进行波形单位换算时,我们可以根据不同的物理量之间的关系,通过一系列的换算步骤来完成。

步骤1:确定已知量和要求量在进行波形单位换算时,首先需要明确已知量和要求量。

已知量是我们已知的物理量,而要求量是我们需要计算或转换的物理量。

例如,已知波长为100米,要求计算对应的频率。

步骤2:查找单位换算公式根据已知量和要求量的性质,我们可以查找相应的单位换算公式。

对于波长和频率的转换,我们可以使用波速公式进行计算。

波速公式:v = f * λ步骤3:进行单位换算计算根据波速公式,可以得到频率的计算公式:f = v / λ。

将已知量带入公式中,得到频率的计算表达式,然后进行计算。

例如,在已知波长为100米的情况下,需要计算对应的频率,假设波速为300000000米/秒。

则可以使用公式:f = 300000000 / 100,计算得到频率为3,000,000赫兹。

通过这一系列的换算步骤,我们可以将波长转换为频率,从而更好地理解和处理波动现象。

linux gpio get value 说明

linux gpio get value 说明

linux gpio get value 说明GPIO(General Purpose Input/Output)是一种通用输入/输出端口,广泛应用于嵌入式系统和微控制器中。

在Linux系统中,GPIO可以通过sysfs接口进行访问和控制。

通过sysfs接口,用户空间程序可以读取或设置GPIO的值,从而实现与硬件设备的交互。

在Linux中,GPIO的值通常通过/sys/class/gpio目录下的文件来表示。

每个GPIO引脚都对应一个目录,目录名通常是gpioX,其中X是GPIO引脚的编号。

在这个目录下,有几个重要的文件用于获取和设置GPIO的值:direction:该文件用于设置GPIO的方向,即输入(input)或输出(output)。

当GPIO 作为输入时,可以通过读取value文件来获取其当前的值;当GPIO作为输出时,可以通过写入value文件来设置其输出的值。

value:该文件用于获取或设置GPIO的值。

当GPIO方向为输入时,读取该文件可以得到当前引脚的状态(高电平或低电平)。

当GPIO方向为输出时,向该文件写入1或0可以分别设置引脚为高电平或低电平。

使用Linux GPIO接口获取GPIO值的步骤如下:导出GPIO引脚:首先,需要将GPIO引脚导出到用户空间,以便通过sysfs接口进行访问。

这可以通过向/sys/class/gpio/export文件写入GPIO编号来实现。

设置GPIO方向:在导出GPIO引脚后,需要设置其方向为输入。

这可以通过向对应GPIO 目录下的direction文件写入in来实现。

读取GPIO值:设置好GPIO方向后,就可以通过读取对应GPIO目录下的value文件来获取其当前的值。

该文件的内容将是一个0或1,表示GPIO引脚当前的状态。

需要注意的是,Linux GPIO接口的具体实现可能因不同的硬件平台和内核版本而有所差异。

因此,在使用时,建议参考相关的硬件和内核文档,以确保正确地获取和设置GPIO 的值。

基于rk3568的linux驱动开发——gpio知识点 -回复

基于rk3568的linux驱动开发——gpio知识点 -回复

基于rk3568的linux驱动开发——gpio知识点-回复题目:基于rk3568的Linux驱动开发——GPIO知识点引言:GPIO(General Purpose Input Output)是一种通用的输入输出引脚,它不属于任何特定的总线协议,可以通过软件来进行控制。

在Linux驱动开发中,GPIO起着重要的作用。

本文将以基于rk3568的Linux驱动开发为背景,深入探讨GPIO相关的知识点。

一、什么是GPIO?GPIO是一种通用的、数字的、非线性的输入输出引脚。

通常用于将处理器与外部硬件设备连接起来,实现信息的输入输出。

GPIO可以根据需要实现输入模式和输出模式的切换,灵活性很高。

二、rk3568的GPIO引脚配置rk3568是一款嵌入式处理器,支持GPIO功能。

在开始开发GPIO驱动之前,我们需要了解rk3568的GPIO引脚配置。

rk3568有多个GPIO组,每个组内有多个GPIO引脚。

通过GPIO引脚配置,我们可以控制GPIO 引脚的功能,如输入、输出、上拉、下拉等。

三、Linux GPIO子系统Linux操作系统提供了一个GPIO子系统,用于管理和控制GPIO。

对于每个GPIO引脚,Linux内核都为其分配了一个唯一的GPIO号码。

我们可以通过GPIO号码来操作和控制相关引脚。

四、驱动中的GPIO操作在Linux驱动中,我们可以通过GPIO接口进行GPIO操作。

下面是一些常用的GPIO操作函数:1. gpio_request(gpio, label):请求一个GPIO引脚用于驱动。

2. gpio_direction_input(gpio):将GPIO引脚配置为输入模式。

3. gpio_direction_output(gpio, value):将GPIO引脚配置为输出模式,并设置输出值。

4. gpio_get_value(gpio):读取GPIO引脚当前的值。

5. gpio_set_value(gpio, value):设置GPIO引脚的输出值。

linux gpio_direction_output参数

linux gpio_direction_output参数

linux gpio_direction_output参数下载提示:该文档是本店铺精心编制而成的,希望大家下载后,能够帮助大家解决实际问题。

文档下载后可定制修改,请根据实际需要进行调整和使用,谢谢!本店铺为大家提供各种类型的实用资料,如教育随笔、日记赏析、句子摘抄、古诗大全、经典美文、话题作文、工作总结、词语解析、文案摘录、其他资料等等,想了解不同资料格式和写法,敬请关注!Download tips: This document is carefully compiled by this editor. I hope that after you download it, it can help you solve practical problems. The document can be customized and modified after downloading, please adjust and use it according to actual needs, thank you! In addition, this shop provides you with various types of practical materials, such as educational essays, diary appreciation, sentence excerpts, ancient poems, classic articles, topic composition, work summary, word parsing, copy excerpts, other materials and so on, want to know different data formats and writing methods, please pay attention!Linux GPIO 方向输出参数详解导言在嵌入式系统中,GPIO(通用输入/输出)是一种非常重要的资源,用于与外部设备进行通信。

linux gpio使用方法

linux gpio使用方法

linux gpio使用方法摘要:1.Linux GPIO概述2.配置GPIO引脚3.读取和控制GPIO状态4.示例:GPIO应用5.总结与建议正文:**一、Linux GPIO概述**Linux GPIO(通用输入输出)是一种在操作系统中操作硬件设备的方法。

在Linux系统中,GPIO通常指的是硬件平台上可用的输入输出引脚。

通过GPIO,开发者可以实现对各种硬件设备的管理和控制,如LED、开关、传感器等。

GPIO在Linux系统中的使用方法丰富多样,具有较高的灵活性。

**二、配置GPIO引脚**要在Linux系统中使用GPIO,首先需要配置GPIO引脚。

常用的配置工具有sysfs、gpiochip和wiringPi。

以下以sysfs为例进行说明:1.导出GPIO引脚:`echo 1 > /sys/class/gpio/export/GPIO_引脚编号`2.设置GPIO引脚方向(输入或输出):`echo "in" >/sys/class/gpio/direction/GPIO_引脚编号`3.读取GPIO状态:`cat /sys/class/gpio/value/GPIO_引脚编号`4.设置GPIO状态(高或低):`echo 1 > /sys/class/gpio/value/GPIO_引脚编号`5.取消导出GPIO引脚:`echo 0 > /sys/class/gpio/export/GPIO_引脚编号`**三、读取和控制GPIO状态**GPIO引脚配置完成后,可以通过读取和控制GPIO状态来实现对硬件设备的操作。

以下是一些常用的GPIO操作命令:1.读取GPIO引脚状态:`cat /sys/class/gpio/value/GPIO_引脚编号`2.设置GPIO引脚状态(高或低):`echo 1 >/sys/class/gpio/value/GPIO_引脚编号`、`echo 0 >/sys/class/gpio/value/GPIO_引脚编号`**四、示例:GPIO应用**以下以LED灯为例,展示GPIO在Linux系统中的实际应用:1.配置GPIO引脚:导出GPIO引脚、设置为输出模式2.控制LED灯:通过设置GPIO引脚状态来控制LED灯的开启与关闭3.循环控制LED灯:使用while循环,实现LED灯的闪烁**五、总结与建议**Linux GPIO为开发者提供了一种便捷的硬件控制方法。

ZedBoard_Linux开发_---_GPIO驱动详解ZedBoard 安装 Ubuntu11.04

ZedBoard_Linux开发_---_GPIO驱动详解ZedBoard 安装 Ubuntu11.04

ZedBoard Linux开发--- GPIO驱动详解下载LOFTER客户端本来这是要作为ZedBoard Linux的第一个学习实例,不过由于一开始实在找不到内核中针对ZedBoard GPIO具体操作的代码在哪里,所以只能先从OLED开始看起,在学习完OLED驱动之后有了不少发现,比如OLED驱动中就有使用GPIO的操作,后来发现这些操作都被Linux内核中的GPIOLIB库管理着,相关的文档在Documentation/gpio.txt中有介绍,通读一遍之后就会有不少发现的,相关的GPIOLIB库文件位于drivers/gpio/gpio-lib.c文件中,不过这部分文件只是提供了库函数,而真正在ZedBoard启动时进行GPIO注册管理的文件是drivers/gpio/gpio-xilinxps.c,可以在这个文件中找到这样一个宏定义:这里一共注册了118个GPIO口,看看Datasheet就知道这里的意思应该是MIO[0:53]+EMIO[54:117],也就是54个MIO加上64个EMIO,看到这里我还是有一些疑问,因为并不是所有的IO口都作为GPIO 来使用的,有很大一部分是进行IO复用的,下面是我在XPS中的MIO配置截图:可以看到MIO中真正作为GPIO口使用的也就只有MIO[0,7,9:15,50:51],我当时就有疑问:如果我在Linux中申请了这一部分被复用的GPIO,这会不会与正在复用的那些功能起冲突?(至少在MCU中有很多复用功能是在配置了GPIO方向之后才能正常复用的)后来看来一下zynq的UG585手册,找到了下面这张图才解决了问题:可以看到所有GPIO与其他复用的功能最后都是经过MIO网络路由到外部的GPIO端口的,也就是说即使在相应的GPIO寄存器中配置了GPIO的功能,那么这部分功能也不会生效!而配置这些复用功能的寄存器是在slcr(System Level Control Registers)寄存器中操作的,可以在UG585上找到这些寄存器具体的参数:而在Digilent Linux内核中,slcr相关的文件可以在linux-digilent/arch/arm/mach-zynq/slcr.c中找到。

gpio-keys 使用方法

gpio-keys 使用方法

gpio-keys 使用方法gpio-keys是Linux内核中的一个子系统,用于处理嵌入式系统中的GPIO按键输入。

它允许开发人员将GPIO引脚配置为输入,并在按键按下或释放时生成相应的键事件。

下面我将从配置、驱动和使用方面来介绍gpio-keys的使用方法。

首先,要使用gpio-keys,你需要确保你的Linux内核已经启用了相应的配置选项。

在内核配置中,你需要启用CONFIG_INPUT_GPIO_KEYS选项。

这个选项通常位于"Device Drivers" -> "Input device support" -> "Keyboards"下。

启用这个选项后,重新编译内核并将其烧录到你的嵌入式设备上。

接下来,你需要在设备树中配置GPIO按键的引脚信息。

你需要指定GPIO引脚的编号、按键的名称以及按键事件的类型(按下或释放)。

这些信息将被用于注册gpio-keys设备,并在按键事件发生时生成输入事件。

在Linux系统启动时,内核会根据设备树中的配置信息注册gpio-keys设备。

一旦设备注册成功,你就可以在用户空间中使用输入事件接口来监控GPIO按键的状态变化了。

你可以使用evtest工具来测试gpio-keys设备是否正常工作,并查看按键事件的生成情况。

除了设备树中的配置外,你还可以在驱动程序中动态注册gpio-keys设备。

这在某些情况下可能更为灵活,但需要在驱动程序中编写相应的注册和初始化代码。

总的来说,要使用gpio-keys,你需要在内核中启用相应的配置选项,配置设备树以注册gpio-keys设备,并在用户空间中使用输入事件接口来监控GPIO按键的状态变化。

希望这些信息能够帮助你更好地理解和使用gpio-keys子系统。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

/Linux/2011-09/43084.htm打算跟着友善之臂的《mini2440 Linux移植开发指南》见/Linux/2011-06/37904.htm 来做个LED驱动,虽然LED的原理简单得不能再简单了,但是要把kernel中针对于s3c24**的GPIO的一些数据结构,还有函数搞清楚也不是那么轻松的事,所以本文主要简单地说明下LED驱动中的相关数据结构以及函数/宏的定义,并对驱动加以验证***************************************************************************注意:在/arch/arm/mach-s3c2410/include/mach/gpio-fns.h源代码中有如下说明:16/* These functions are in the to-be-removed category and it is strongly17 * encouraged not to use these in new code. They will be marked deprecated18 * very soon.19 *20 * Most of the functionality can be either replaced by the gpiocfg calls21 * for the s3c platform or by the generic GPIOlib API.22 *23 * As of 2.6.35-rc, these will be removed, with the few drivers using them24 * either replaced or given a wrapper until the calls can be removed.25*/该头文件包括:static inline void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int cfg)该函数直接使用linux/arch/arm/plat-s3c/gpio-config.c中的int s3c_gpio_cfgpin(unsigned int pin, unsigned int config)即可***************************************************************************首先看一下设备初始化程序:85 /*86 * 设备初始化87 */88 static int __init dev_init(void)89 {90 int ret;91 int i;92 for (i = 0; i < 4; i++) {93 //设置LED 对应的端口寄存器为输出(OUTPUT)94 if (s3c_gpio_cfgpin(led_table[i], led_cfg_table[i])<0)printk(KERN_INFO "config pin %d failed", i);95 printk(KERN_INFO "config pin %d failed", i);95 //设置LED 对应的端口寄存器为低电平输出,在模块加载> 结束后,四个LED 应该是全部都是发光96 状态97 s3c2410_gpio_setpin(led_table[i], 0);98 }99 ret = misc_register(&misc); //注册设备100 printk (DEVICE_NAME"/tinitialized/n"); //打印初始化信息101 return ret;102 }可以看到,这里涉及到两个函数,分别是s3c2410_gpio_cfgpin,s3c2410_gpio_setpin,这两个函数分别对四个LED进行配置,从函数名来看,cfgpin对引脚寄存器状态进行配置,而setpin 应该是对寄存器数据值进行配置,我们在分析函数之前先弄清楚传入的参数到底是什么。

led_table[i]28 //LED 对应的GPIO 端口列表29 static unsigned long led_table [] = {30 S3C2410_GPB(5),31 S3C2410_GPB(6),32 S3C2410_GPB(7),33 S3C2410_GPB(8),34 };这里S3C2410_GPB宏定义在mach/gpio-nrs.h中/* GPIO bank sizes */#define S3C2410_GPIO_A_NR (32)#define S3C2410_GPIO_B_NR (32)#define S3C2410_GPIO_C_NR (32)#define S3C2410_GPIO_D_NR (32)#define S3C2410_GPIO_E_NR (32)#define S3C2410_GPIO_F_NR (32)#define S3C2410_GPIO_G_NR (32)#define S3C2410_GPIO_H_NR (32)#define S3C2410_GPIO_J_NR (32) /* technically 16. */#define S3C2410_GPIO_K_NR (32) /* technically 16. */#define S3C2410_GPIO_L_NR (32) /* technically 15. */#define S3C2410_GPIO_M_NR (32) /* technically 2. */#if CONFIG_S3C_GPIO_SPACE != 0#error CONFIG_S3C_GPIO_SPACE cannot be zero at the moment#endif#define S3C2410_GPIO_NEXT(__gpio) /((__gpio##_START) + (__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 0)//这里的CONFIG_S3C_GPIO_SPAC是内核配置选项,在.config中可以找到,我的配置为:CONFIG_S3C_GPIO_SPACE = 0enum s3c_gpio_number {S3C2410_GPIO_A_START = 0,S3C2410_GPIO_B_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_A),S3C2410_GPIO_C_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_B),S3C2410_GPIO_D_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_C),S3C2410_GPIO_E_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_D),S3C2410_GPIO_F_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_E),S3C2410_GPIO_G_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_F),S3C2410_GPIO_H_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_G),S3C2410_GPIO_J_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_H),S3C2410_GPIO_K_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_J),S3C2410_GPIO_L_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_K),S3C2410_GPIO_M_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_L),};#define S3C2410_GPB(_nr) (S3C2410_GPIO_B_START + (_nr))因此,以S3C2410_GPB(5)为例,其宏展开为:S3C2410_GPIO_NEXT(S3C2410_GPIO_A) +5 =>(S3C2410_GPIO_A_START + S3C2410_GPIO_A_NR + CONFIG_S3C_GPIO_SPACE + 0) + 5 =>很显然,S3C2410_GPB(5)就是从GPA的首地址+GPA个数+GPB的offset就是当前GPB的IO偏移量,即0+32+5=37, 同理S3C2410_GPB(0) 相当于3230 S3C2410_GPB(5) 相当于3731 S3C2410_GPB(6) 相当于3832 S3C2410_GPB(7) 相当于3933 S3C2410_GPB(8) 相当于40***************************************************************************led_cfg_table[i]36 //LED 对应端口将要输出的状态列表37 static unsigned int led_cfg_table [] = {38 S3C2410_GPIO_OUTPUT,39 S3C2410_GPIO_OUTPUT,40 S3C2410_GPIO_OUTPUT,41 S3C2410_GPIO_OUTPUT,42 };S3C2410_GPIO_OUTPUT定义在mach/regs-gpio.h#define S3C2410_GPIO_LEA VE (0xFFFFFFFF) // 最后两位是设置,11表示RESERVE#define S3C2410_GPIO_INPUT (0xFFFFFFF0) /* not available on A */ // 最后两位是设置,00表示INPUT#define S3C2410_GPIO_OUTPUT (0xFFFFFFF1) // 最后两位是设置,01表示OUTPUT#define S3C2410_GPIO_IRQ (0xFFFFFFF2) /* not available for all */#define S3C2410_GPIO_SFN2 (0xFFFFFFF2) /* bank A => addr/cs/nand */#define S3C2410_GPIO_SFN3 (0xFFFFFFF3) /* not available on A */***************************************************************************根据前面的分析,s3c2410传入了当前GPIO的偏移地址,以及OUTPUT状态现在我们深入前面的两个函数:定义在linux/arch/arm/plat-s3c/gpio-config.cint s3c_gpio_cfgpin(unsigned int pin, unsigned int config){struct s3c_gpio_chip *chip = s3c_gpiolib_getchip(pin); //得到对应GPIO结构体首指针,里面包含了该GPIO的各种参数unsigned long flags;int offset;int ret;if (!chip)return -EINVAL; // 没找到的话,返回invalidoffset = pin - chip->chip.base; // 否则offset等于该GPIO引脚相对于GPX(0)的偏移量,每个偏移1s3c_gpio_lock(chip, flags); // 自旋锁锁住该GPIO,通过chip指针指向lock,看下面的define和图ret = s3c_gpio_do_setcfg(chip, offset, config); //设置该GPIO状态寄存器的数值为config s3c_gpio_unlock(chip, flags); // 解锁// 自旋锁操作/* locking wrappers to deal with multiple access to the same gpio bank *///#define s3c_gpio_lock(_oc, _fl) spin_lock_irqsave(&(_oc)->lock, _fl)//#define s3c_gpio_unlock(_oc, _fl) spin_unlock_irqrestore(&(_oc)->lock, _fl)//s3c_gpio_do_setcfg操作static inline int s3c_gpio_do_setcfg(struct s3c_gpio_chip *chip,unsigned int off, unsigned int config){return (chip->config->set_config)(chip, off, config);}//这里的set_config是一个函数指针,由后面的分析知道,如果针对GPA,该函数指针指向s3c_gpio_setcfg_s3c24xx_a , 如果针对GPX应该是指向s3c_gpio_setcfg_s3c24xx——但发现,如果是其他GPX,根本没有定义set_config!!! (这个问题已经解决,见后文s3c24xx_gpiolib_init函数,事实上,其余的config的确指向s3c_gpio_do_setcfg函数)struct s3c_gpio_cfg s3c24xx_gpiocfg_default = {.set_config = s3c_gpio_setcfg_s3c24xx,.get_config = s3c_gpio_getcfg_s3c24xx,};int s3c_gpio_setcfg_s3c24xx_a(struct s3c_gpio_chip *chip, unsigned int off, unsigned int cfg) {void __iomem *reg = chip->base; // GPXCON的物理基地址unsigned int shift = off; // 每个GPA对应一位u32 con;if (s3c_gpio_is_cfg_special(cfg)) { //OUTPUT状态是否为(0xfffffffX),是,返回1 cfg &= 0xf; // cfg = 0xX/* Map output to 0, and SFN2 to 1 */ 本实验不会运行到这cfg -= 1;if (cfg > 1)return -EINV AL;cfg <<= shift;}con = __raw_readl(reg); // 先读出该GPXCON的值,32位con &= ~(0x1 << shift); //con |= cfg; //__raw_writel(con, reg); // 将新值写入GPXCONPS:#define __raw_writeb(v,a) (__chk_io_ptr(a), *(volatile unsigned char __force *)(a) = (v)) #define __raw_writew(v,a) (__chk_io_ptr(a), *(volatile unsigned short __force *)(a) = (v)) #define __raw_writel(v,a) (__chk_io_ptr(a), *(volatile unsigned int __force *)(a) = (v))#define __raw_readb(a) (__chk_io_ptr(a), *(volatile unsigned char __force *)(a))#define __raw_readw(a) (__chk_io_ptr(a), *(volatile unsigned short __force *)(a))#define __raw_readl(a) (__chk_io_ptr(a), *(volatile unsigned int __force *)(a))return 0;}如果针对GPX情况int s3c_gpio_setcfg_s3c24xx(struct s3c_gpio_chip *chip,unsigned int off, unsigned int cfg){void __iomem *reg = chip->base;unsigned int shift = off * 2; // 每个GPX对应2位u32 con;if (s3c_gpio_is_cfg_special(cfg)) {cfg &= 0xf;if (cfg > 3)return -EINV AL;cfg <<= shift; // 将cfg的0,1两位左移offset}con = __raw_readl(reg); // 读对应的GPXCON值con &= ~(0x3 << shift); // 将GPXCON(pin)的两bits请0con |= cfg; // 设置config值__raw_writel(con, reg); // 写入新的GPXCONreturn 0;}return ret;} // end s3c_gpio_cfgpin这里涉及到了一个重要的数据结构,s3c_gpio_chip,此数据结构比较复杂,我贴出这个数据结构的结构图:、这个重要的数据结构中可以记录每个GPIO所需要的所有数据,后面会遇到的s3c24xx_gpios[]结构体就是该结构体的集合,描述了芯片中所有的GPIO端口,之后我们需要时时回头看看这个结构。

相关文档
最新文档