搜档网
当前位置:搜档网 › Linux内核文档:GPIO接口

Linux内核文档:GPIO接口

Linux内核文档:GPIO接口
Linux内核文档:GPIO接口

原文:Documentation/gpio.txt

翻译:tekkamanninja@https://www.sodocs.net/doc/2c17929907.html,

翻译完成时间:2012年2月18日星期六

V1.0

目录

什么是GPIO? (3)

GPIO公约 (3)

标识GPIO (3)

使用 GPIO (4)

访问自旋锁安全的GPIO (4)

访问可能休眠的GPIO (5)

声明和释放GPIO (5)

GPIO映射到IRQ (7)

模拟开漏信号 (7)

GPIO实现者的框架 (可选) (8)

控制器驱动: gpio_chip (8)

平台支持 (8)

板级支持 (9)

用户空间的Sysfs接口(可选) (9)

Sysfs中的路径 (9)

从内核代码中导出 (10)

本文档提供了一个在Linux下访问GPIO的公约概述。

这些函数以gpio_* 作为前缀。其他的函数不允许使用这样的前缀或相关的__gpio_* 前缀。

什么是GPIO?

"通用输入/输出口"(GPIO)是一个灵活的由软件控制的数字信号。他们可由多种芯片提供,且对于从事嵌入式和定制硬件的Linux开发者来说是比较熟悉。每个GPIO都代表一个连接到特定引脚或球栅阵列(BGA)封装中“球珠”的一个位。电路板原理图显示了GPIO与外部硬件的连接关系。驱动可以编写成通用代码,以使板级启动代码可传递引脚配置数据给驱动。

片上系统(SOC) 处理器对GPIO有很大的依赖。在某些情况下,每个非专用引脚都可配置为GPIO,且大多数芯片都最少有一些GPIO。可编程逻辑器件(类似FPGA) 可以方便地提供GPIO。像电源管理和音频编解码器这样的多功能芯片经常留有一些这样的引脚来帮助那些引脚匮乏的SOC。同时还有通过I2C或SPI串行总线连接的"GPIO扩展器"芯片。大多数PC的南桥有一些拥有GPIO能力的引脚(只有BIOS固件才知道如何使用他们)。

GPIO的实际功能因系统而异。通常的用法有:

- 输出值可写(高电平=1, 低电平=0)。一些芯片也有如何驱动这些值的选项,例如只允许输出一个值、支持“线与”及其他取值类似的模式(值得注意的是“开漏”信号)。

- 输入值可读(1、0)。一些芯片支持引脚在配置为“输出”时回读,这对于类似“线与”的情况(以支持双向信号)是非常有用的。GPIO 控制器可能有输入去毛刺/消抖逻辑,这有时需要软件控制。

- 输入通常可作为IRQ信号,一般是沿触发,但有时是电平触发。这样的IRQ 可能配置为系统唤醒事件,以将系统从低功耗状态下唤醒。

- 通常一个GPIO根据不同产品电路板的需求,可以配置为输入或输出,也有仅支持单向的。

- 大部分GPIO 可以在持有自旋锁时访问,但是通常由串行总线扩展的GPIO不允许持有自旋锁。但某些系统也支持这种类型。

对于给定的电路板,每个GPIO都用于某个特定的目的,如监控MMC/SD卡的插入/移除、检测卡的写保护状态、驱动LED、配置收发器、模拟串行总线、复位硬件看门狗、感知开关状态等等。

GPIO公约

注意,这个叫做“公约”,因为这不是强制性的,不遵循这个公约是无伤大雅的,因为此时可移植性并不重要。GPIO常用于板级特定的电路逻辑,甚至可能随着电路板的版本而改变,且不可能在不同走线的板子上使用。仅有在很少的功能上才具有可移植性,其他功能是平台特定。这也是由于“胶合”的逻辑造成的。

此外,这不需要任何的执行框架,只是一个接口。某个平台可能通过一个简单的访问芯片寄存器的内联函数来实现它,其他平台可能通过委托一系列不同的GPIO控制器的抽象函数来实现它。(有一些可选的代码能支持这种策略的实现,本文档后面会介绍,但作为GPIO接口的客户端驱动程序必须与它的实现无关。)

也就是说,如果在他们的平台上支持这个公约,驱动应该尽可能的使用它。平台必须在Kconfig中声明对GENERIC_GPIO 的支持(布尔型true),并提供一个 文件。那些调用标准GPIO函数的驱动应该在Kconfig 入口中声明依赖GENERIC_GPIO。当驱动包含文件:

#include

GPIO函数是可用,无论是“真实代码”还是经优化过的语句。

如果你遵守这个公约,当你的代码完成后,对其他的开发者来说会更容易看懂和维护。

注意,这些操作包含所用平台的I/O 屏障代码,驱动无须显式地调用他们。

标识GPIO

GPIO是通过无符号整型来标识的,范围是0到MAX_INT。保留“负”数用于其他目的,例如标识信号“在这个板子上不可用”或指示错误。未接触底层硬件的代码会忽略这些整数。

平台会定义这些整数的用法,且通常使用#define 来定义GPIO ,这样板级特定的启动代码可以直接关联相应的原理图。相对来说,驱动应该仅使用启动代码传递过来的GPIO 编号,使用platform_data 保存板级特定引脚配置数据(同时还有其他须要的板级特定数据),避免可能出现的问题。

例如一个平台使用编号32-159 来标识GPIO,而在另一个平台使用编号0-63 标识一组GPIO 控制器,64-79 标识另一类GPIO 控制器, 且在一个含有FPGA的特定板子上使用80-95 。编号不一定要连续,那些平台中,也可以使用编号2000-2063 来标识一个I2C接口的GPIO扩展器中的GPIO。

如果你要初始化一个带有无效GPIO编号的结构体,可以使用一些负编码(比如"-EINV AL"),那将永远不会是有效。来测试这样一个结构体中的编号是否关联一个GPIO,你可使用以下断言:

int gpio_is_valid(int number);

如果编号不存在,则请求和释放GPIO的函数将拒绝执行相关操作(见下文)。其他编号也可能被拒绝,比如一个编号可能存在,但暂时在给定的板子上不可用。

一个平台是否支持多个GPIO控制器是平台特定的实现问题,就像是否可以在GPIO编号空间中有“空洞”和是否可以在运行时添加新的控制器一样。这些问题会影响其他事情,包括相邻的GPIO编号是否存在等。

使用 GPIO

对于一个GPIO,系统应该做的第一件事情就是通过gpio_request() 函数分配他,见下文。

而接下来要做的是标识它的方向,这通常是在板级启动代码中为GPIO设置一个platform_device时做的。

/* 设置为输入或输出, 返回0 或负的错误代码*/

int gpio_direction_input(unsigned gpio);

int gpio_direction_output(unsigned gpio, int value);

返回值为零代表成功,否则返回一个负的错误代码。这个返回值需要检查,因为get/set(获取/设置)函数调用没法返回错误,且有可能是配置错误。通常,你应该在进程上下文中调用这些函数。然而,对于自旋锁安全的GPIO,在板子启动的早期、进程启动前使用他们也是可以的。

对于作为输出的GPIO,为其提供初始输出值,对于避免在系统启动期间出现信号毛刺是很有帮助的。

为了与传统的GPIO接口兼容, 在设置一个GPIO方向时,如果它还未被申请,则隐含了申请那个GPIO的操作(见下文)。这种兼容性正在从可选的gpiolib框架中移除。

如果这个GPIO编码不存在或特定的GPIO不能用于那种模式,则方向设置可能失败。依赖启动固件来正确地设置方向通常是一个坏主意,因为它可能除了启动Linux,并没有做更多的验证工作。(类似地, 板子的启动代码可能需要将这个复用的引脚设置为GPIO,并正确地配置上拉/下拉电阻。)

访问自旋锁安全的GPIO

大多数GPIO控制器可以通过内存读/写指令来访问。这些指令不会休眠,可以安全地在硬(非线程)中断例程和类似的上下文中完成。

对于那些用gpio_cansleep()测试总是返回失败的GPIO(见下文),使用以下的函数访问:

/* GPIO 输入:返回零或非零*/

int gpio_get_value(unsigned gpio);

/* GPIO 输入*/

void gpio_set_value(unsigned gpio, int value);

返回值是布尔值,零表示低电平,非零表示高电平。当读取一个输出引脚的值时,返回值应该是引脚上的值。这个值不总是和输出值相符,因为存在开漏输出信号和输出潜伏期的问题。

以上的get/set函数不会对早期已经通过gpio_direction_*()报告“无效的GPIO”返回错误。此外,还需要注意的是并不是所有平台都可以从输出引脚中读取数据的,那些引脚也不总是返回零。且对那些无法安全访问(可能会休眠)的GPIO(见下文)使用这些函数是错误的。

在GPIO编号(还有输出、值)为常数的情况下,鼓励通过平台特定的实现来优化这两个函数来访问GPIO值。这种情况(读写一个硬件寄存器)下只需要几条指令是很正常的,且无须自旋锁。这种优化函数比起那些在子程序上花费许多指令的函数可以使得模拟接口(译者注:例如GPIO模拟I2C、1-wire或SPI)的应用(在空间和时间上都)更具效率。

访问可能休眠的GPIO

某些GPIO控制器必须通过基于总线(如I2C或SPI)的消息访问。读或写这些GPIO值的命令需要等待其信息排到队首才发送命令,再获得其反馈。期间需要休眠,这不能在IRQ例程(中断上下文)中执行。

支持此类GPIO的平台通过以下函数返回非零值来区分出这种GPIO。(此函数需要一个之前通过gpio_request分配到的有效的GPIO编号):

int gpio_cansleep(unsigned gpio);

为了访问这种GPIO,内核定义了一套不同的函数:

/* GPIO 输入:返回零或非零,可能会休眠*/

int gpio_get_value_cansleep(unsigned gpio);

/* GPIO 输入,可能会休眠*/

void gpio_set_value_cansleep(unsigned gpio, int value);

访问这样的GPIO需要一个允许休眠的上下文,例如线程IRQ处理例程,并用以上的访问函数替换那些没有cansleep()后缀的自旋锁安全访问函数。

除了这些访问函数可能休眠,且它们操作的GPIO不能在硬件IRQ处理例程中访问的事实,这些处理例程实际上和自旋锁安全的函数是一样的。

** 除此之外** 调用设置和配置此类GPIO的函数也必须在允许休眠的上下文中,因为它们可能也需要访问GPIO控制器芯片:(这些设置函数通常在板级启动代码或者驱动探测/断开代码中,所以这是一个容易满足的约束条件。) gpio_direction_input()

gpio_direction_output()

gpio_request()

## gpio_request_one()

## gpio_request_array()

## gpio_free_array()

gpio_free()

gpio_set_debounce()

声明和释放GPIO

为了有助于捕获系统配置错误,定义了两个函数。

/* 申请GPIO, 返回0或负的错误代码.

* 非空标签可能有助于诊断.

*/

int gpio_request(unsigned gpio, const char *label);

/* 释放之前声明的GPIO */

void gpio_free(unsigned gpio);

将无效的GPIO编码传递给gpio_request()会导致失败,申请一个已使用这个函数声明过的GPIO也会失败。gpio_request()的返回值必须检查。你应该在进程上下文中调用这些函数。然而,对于自旋锁安全的GPIO,在板子启动的早期、进入进程之前是可以申请的。

这个函数完成两个基本的目标。一是标识那些实际上已作为GPIO使用的信号线,这样便于更好地诊断;系统可能需要服务几百个潜在的GPIO,但是对于任何一个给定的电路板通常只有一些被使用。另一个目的是捕获冲突,查明错误:如两个或更多驱动错误地认为他们已经独占了某个信号线,或是错误地认为移除一个管理着某个已激活信号的驱动是安全的。也就是说,申请GPIO的作用类似一种锁机制。

某些平台可能也使用GPIO作为电源管理(例如通过关闭未使用芯片区和简单地关闭未使用时钟)激活信号。

注意:申请一个GPIO并没有以任何方式配置它,只不过标识那个GPIO处于使用状态。必须有另外的代码来处理引脚配置(如控制GPIO使用的引脚、上拉/下拉)。

并且注意在释放GPIO前,你必须停止使用它。

考虑到大多数情况下声明GPIO之后就会立即配置它们,所以定义了以下三个辅助函数:

/* 申请一个GPIO信号, 同时通过特定的'flags'初始化配置,

* 其他和gpio_request()的参数和返回值相同

*

*/

int gpio_request_one(unsigned gpio, unsigned long flags, const char *label);

/* 在单个函数中申请多个GPIO

*/

int gpio_request_array(struct gpio *array, size_t num);

/* 在单个函数中释放多个GPIO

*/

void gpio_free_array(struct gpio *array, size_t num);

这里'flags' 当前定义可指定以下属性:

* GPIOF_DIR_IN - 配置方向为输入

* GPIOF_DIR_OUT - 配置方向为输出

* GPIOF_INIT_LOW - 在作为输出时,初始值为低电平

* GPIOF_INIT_HIGH - 在作为输出时,初始值为高电平

因为GPIOF_INIT_* 仅有在配置为输出的时候才存在,所以有效的组合为:

* GPIOF_IN - 配置为输入

* GPIOF_OUT_INIT_LOW - 配置为输出,并初始化为低电平

* GPIOF_OUT_INIT_HIGH - 配置为输出,并初始化为高电平

将来这些标志可能扩展到支持更多的属性,比如开漏状态。

更进一步,为了更简单地声明/释放多个GPIO,'struct gpio'被引进来封装所有这三个领域:

struct gpio {

unsigned gpio;

unsigned long flags;

const char *label;

};

一个典型的使用案例:

static struct gpio leds_gpios[] = {

{ 32, GPIOF_OUT_INIT_HIGH, "Power LED" }, /* default to ON */

{ 33, GPIOF_OUT_INIT_LOW, "Green LED" }, /* default to OFF */

{ 34, GPIOF_OUT_INIT_LOW, "Red LED" }, /* default to OFF */

{ 35, GPIOF_OUT_INIT_LOW, "Blue LED" }, /* default to OFF */

{ ... },

};

err = gpio_request_one(31, GPIOF_IN, "Reset Button");

if (err)

...

err = gpio_request_array(leds_gpios, ARRAY_SIZE(leds_gpios));

if (err)

...

gpio_free_array(leds_gpios, ARRAY_SIZE(leds_gpios));

GPIO映射到IRQ

GPIO编号是无符号整数;IRQ编号也是。这些构成了两个逻辑上不同的命名空间(GPIO 0不一定使用IRQ 0)。你可以通过以下函数在它们之间实现映射:

/* 映射GPIO编号到IRQ编号*/

int gpio_to_irq(unsigned gpio);

/* 映射IRQ编号到GPIO编号(尽量避免使用) */

int irq_to_gpio(unsigned irq);

它们的返回值为对应命名空间的相关编号,或是负的错误代码(如果无法映射)。(例如,某些GPIO无法做为IRQ使用。)以下的编号错误是未经检测的:使用一个未通过gpio_direction_input()配置为输入的GPIO编号,或者使用一个并非来源于

gpio_to_irq()的IRQ编号。

这两个映射函数可能会在信号编号的加减计算过程上花些时间。它们不可休眠。

gpio_to_irq()返回的非错误值可以传递给request_irq()或者free_irq()。它们通常通过板级特定的初始化代码存放到平台设备的IRQ资源中。注意:IRQ触发选项是IRQ接口的一部分,比如IRQF_TRIGGER_FALLING,系统唤醒能力也是如此。

irq_to_gpio()返回的非错误值大多数通常可以被gpio_get_value()所使用,比如在IRQ是沿触发时初始化或更新驱动状态。注意某些平台不支持反映射,所以你应该尽量避免使用它。

模拟开漏信号

有时在只有低电平信号作为实际驱动结果(译者注:多个输出连接于一点,逻辑电平结果为所有输出的逻辑与)的时候,共享的信号线需要使用“开漏”信号。(该术语适用于CMOS管;而TTL用“集电极开路”。)一个上拉电阻使信号为高电平。这有时被称为“线与”。实际上,从负逻辑(低电平为真)的角度来看,这是一个“线或”。

一个开漏信号的常见例子是共享的低电平使能IRQ信号线。此外,有时双向数据总线信号也使用漏极开路信号。

某些GPIO 控制器直接支持开漏输出,还有许多不支持。当你需要开漏信号但你的硬件又不直接支持的时候,一个常用的方法是用任何即可作输入也可作输出的GPIO引脚来模拟:

LOW: gpio_direction_output(gpio, 0) ... 这代码驱动信号并覆盖上拉配置

HIGH: gpio_direction_input(gpio) ... 这代码关闭输出,所以上拉电阻(或其他的一些器件)控制了信号。

如果你将信号线“驱动”为高电平,但是gpio_get_value(gpio)报告了一个低电平(在适当的上升时间后),你就可以知道是其他的一些组件将共享信号线拉低了。这不一定是错误的。一个常见的例子就是I2C时钟的延长:一个需要较慢时钟的从设备延迟SCK的上升沿,而I2C主设备相应地调整其信号传输速率。

这些公约忽略了什么?

这些公约忽略的最大一件事就是引脚复用,因为这属于高度芯片特定的属性且没有可移植性。某个平台可能不需要明确的复用信息;有的对于任意给定的引脚可能只有两个功能选项;有的可能每个引脚有八个功能选项;有的可能可以将几个引脚中的任何一个作为给定的GPIO。(是的,这些例子都来自于当前运行Linux的系统。)

在某些系统中,与引脚复用相关的是配置和使能集成的上、下拉模式。并不是所有平台都支持这种模式,或者不会以相同的方式来支持这种模式;且任何给定的电路板可能使用外置的上拉(或下拉)电阻,这时芯片上的就不应该使用。(当一个电路需要5kOhm的拉动电阻,芯片上的100 kOhm电阻就不能做到。)同样的,驱动能力(2 mA vs 20 mA)和电压(1.8V vs 3.3V)是平台特定问题,就像模型一样在可配置引脚和GPIO之间(没)有一一对应的关系。

还有其他一些系统特定的机制没有在这里指出,例如上述的输入去毛刺和线与输出选项。硬件可能支持批量读或写GPIO,

一般有几个这样的区块。)某些系统可以通过输出GPIO触发IRQ,或者从并非以GPIO管理的引脚取值。这些机制的相关代码没有必要具有可移植性。

当前,动态定义GPIO并不是标准的,例如作为配置一个带有某些GPIO扩展器的附加电路板的副作用。GPIO实现者的框架 (可选)

前面提到了, 有一个可选的实现框架,让平台使用相同的编程接口,更加简单地支持不同种类的GPIO控制器。这个框架称为"gpiolib"。

作为一个辅助调试功能,如果debugfs可用,就会有一个/sys/kernel/debug/gpio 文件。通过这个框架,它可以列出所有注册的控制器,以及当前正在使用中的GPIO的状态。

控制器驱动: gpio_chip

在框架中每个GPIO 控制器都包装为一个"struct gpio_chip" ,他包含了该类型的每个控制器的常用信息:

- 设置GPIO方向的方法

- 用于访问GPIO值的方法

- 告知调用其方法是否可能休眠的标志

- 可选的debugfs信息导出方法(显示类似上拉配置一样的额外状态)

- 诊断标签

也包含了来自device.platform_data的每个实例的数据:它第一个GPIO的编号和它可用的GPIO的数量。

实现gpio_chip 的代码应该支持多控制器实例,可能使用驱动模型。那些代码要配置每个gpio_chip,并发起

gpiochip_add()。卸载一个GPIO 控制器很少见,但在必要的时候可以使用gpiochip_remove()。

大部分gpio_chip 是一个实例特定结构体的一部分,而并不将GPIO接口单独暴露出来,比如编址、电源管理等。类似编解码器这样的芯片会有复杂的非GPIO状态。

任何一个debugfs信息导出方法通常应该忽略还未申请作为GPIO的信号线。他们可以使用gpiochip_is_requested()测试,当这个GPIO已经申请过了就返回相关的标签,否则返回NULL。

平台支持

为了支持这个框架,一个平台的Kconfig 文件将会"select"(选择)ARCH_REQUIRE_GPIOLIB 或

ARCH_WANT_OPTIONAL_GPIOLIB ,并让它的 包含 ,并定义三个方法:gpio_get_value()、gpio_set_value()和gpio_cansleep()。

它也应该提供一个ARCH_NR_GPIOS的定义值,这样可以更好地反映该平台GPIO的实际数量,节省静态表的空间。(这个定义值应该包含片上系统内建GPIO和GPIO扩展器中的数据。)

ARCH_REQUIRE_GPIOLIB 意味着gpiolib核心在这个构架中将总是编译进内核。

ARCH_WANT_OPTIONAL_GPIOLIB 意味着gpiolib核心默认关闭,且用户可以使能它,并将其编译进内核(可选)。

如果这些选项都没被选择,该平台就不通过GPIO-lib支持GPIO,且代码不可以被用户使能。

以下这些方法的实现可以直接使用框架代码,并总是通过gpio_chip调度:

#define gpio_get_value __gpio_get_value

#define gpio_set_value __gpio_set_value

#define gpio_cansleep __gpio_cansleep

这些定义可以用更理想的实现方法替代,那就是使用经过逻辑优化的内联函数来访问基于特定片上系统的GPIO。例如,若引用GPIO的(寄存器地址)是常量“12”,读取或设置它可能只需少则两或三个指令,且不会休眠。当这样的优化无法实现时,那些函数必须使用框架提供的代码,那就至少要几十条指令才可以实现。对于用GPIO模拟的I/O接口, 如此精简指令是很有意义的。

对于片上系统,平台特定代码为片上GPIO每个区(bank)定义并注册gpio_chip实例。那些GPIO应该根据芯片厂商的文档进行编码/标签,并直接和电路板原理图对应。他们应该开始于零并终止于平台特定的限制。这些GPIO(代码)通常从arch_initcall()或者更早的地方集成进平台初始化代码,使这些GPIO总是可用,且他们通常可以作为IRQ使用。

板级支持

对于外部GPIO 控制器(例如I2C或SPI扩展器、专用芯片、多功能器件、FPGA或CPLD),大多数常用板级特定代码都可以注册控制器设备,并保证他们的驱动知道gpiochip_add()所使用的GPIO编号。他们的起始编号通常跟在平台特定的GPIO 编号之后。

例如板级启动代码应该创建结构体指明芯片公开的GPIO范围,并使用platform_data将其传递给每个GPIO扩展器芯片。然后芯片驱动中的probe()例程可以将这个数据传递给gpiochip_add()。

初始化顺序很重要。例如,如果一个设备依赖基于I2C的(扩展)GPIO,那么它的probe()例程就应该在那个GPIO有效以后才可以被调用。这意味着设备应该在GPIO可以工作之后才可被注册。解决这类依赖的的一种方法是让这种gpio_chip控制器向板级特定代码提供setup()和teardown()回调函数。一旦所有必须的资源可用之后,这些板级特定的回调函数将会注册设备,并可以在这些GPIO控制器设备变成无效时移除它们。

用户空间的Sysfs接口(可选)

使用"gpiolib"实现框架的平台可以选择配置一个GPIO的sysfs用户接口。这不同于debugfs接口,因为它提供的是对GPIO 方向和值的控制,而不只显示一个GPIO的状态摘要。此外,它可以出现在没有调试支持的产品级系统中。

例如,通过适当的系统硬件文档,用户空间可以知道GIOP #23控制Flash存储器的写保护(用于保护其中Bootloader分区)。产品的系统升级可能需要临时解除这个保护:首先导入一个GPIO,改变其输出状态,然后在重新使能写保护前升级代码。通常情况下,GPIO #23是不会被触及的,并且内核也不需要知道他。

根据适当的硬件文档,某些系统的用户空间GPIO可以用于确定系统配置数据,这些数据是标准内核不知道的。在某些任务中,简单的用户空间GPIO驱动可能是系统真正需要的。

注意:标准内核驱动中已经存在通用的“LED和按键”GPIO任务,分别是:"leds-gpio" 和"gpio_keys"。请使用这些来替代直接访问GPIO,因为集成在内核框架中的这类驱动比你在用户空间的代码更好。

Sysfs中的路径

在/sys/class/gpio中有3类入口:

- 用于在用户空间控制GPIO的控制接口;

- GPIOs 本身;以及

- GPIO 控制器("gpio_chip" 实例)。

除了这些标准的文件,还包含“device”符号链接。

控制接口是只写的:

/sys/class/gpio/

"export" ... 用户空间可以通过写其编号到这个文件,要求内核导出一个GPIO的控制到用户空间。

例如: 如果内核代码没有申请GPIO #19,"echo 19 > export" 将会为GPIO #19创建一个"gpio19" 节点。

"unexport" ... 导出到用户空间的逆操作。

例如: "echo 19 > unexport" 将会移除使用"export"文件导出的"gpio19" 节点。

GPIO信号的路径类似/sys/class/gpio/gpio42/ (对于GPIO #42来说),并有如下的读/写属性:

/sys/class/gpio/gpioN/

"direction" ... 读取得到"in" 或"out"。这个值通常运行写入。写入"out" 时,其引脚的默认输出为低电平。为了确

保无故障运行,"low" 或"high" 的电平值应该写入GPIO的配置,作为初始输出值。

注意:如果内核不支持改变GPIO的方向,或者在导出时内核代码没有明确允许用户空间可以重新配置GPIO

方向,那么这个熟悉将不存在。

"value" ... 读取得到0 (低电平) 或1 (高电平)。如果GPIO配置为输出,这个值允许写操作。任何非零值都以高电

平看待。

如果引脚可以配置为中断信号,且如果已经配置了产生中断的模式(见"edge"的描述),你可以对这个文件使

用轮询操作(poll(2)),且轮询操作会在任何中断触发时返回。如果你使用轮询操作(poll(2)),请在events

中设置POLLPRI 和POLLERR。如果你使用轮询操作(select(2)),请在exceptfds设置你期望的文件描述符。

在轮询操作(poll(2))返回之后,既可以通过lseek(2)操作读取sysfs文件的开始部分,也可以关闭这个文件

并重新打开它来读取数据。

"edge" ... 读取得到"none"、"rising"、"falling"或者"both"。将这些字符串写入这个文件可以选择沿触发模式,会使

得轮询操作(select(2))在"value"文件中返回。

这个文件仅有在这个引脚可以配置为可产生中断输入引脚时,才存在。

"active_low" ... 读取得到0 (假) 或1 (真)。写入任何非零值可以翻转这个属性的(读写)值。已存在或之后通过

"edge"属性设置了"rising" 和"falling" 沿触发模式的轮询操作(poll(2))将会遵循这个设置。

GPIO 控制器的路径类似/sys/class/gpio/gpiochip42/ (对于从#42 GPIO开始实现控制的控制器),并有着以下只读属性:/sys/class/gpio/gpiochipN/

"base" ... 与以上的N相同,代表此芯片管理的第一个GPIO的编号

"label" ... 用于诊断(并不总是只有唯一值)

"ngpio" ... 此控制器所管理的GPIO数量(而GPIO编号从N 到N + ngpio - 1)

大多数情况下,电路板的文档应当标明每个GPIO的使用目的。但是那些编号并不总是固定的,例如在扩展卡上的GPIO 会根据所使用的主板或所在堆叠架构中其他的板子而有所不同。在这种情况下,你可能需要使用gpiochip节点(尽可能地结合电路图)来确定给定信号所用的GPIO编号。

从内核代码中导出

内核代码可以明确地管理那些已通过gpio_request()申请的GPIO的导出:

/* 导出GPIO到用户空间*/

int gpio_export(unsigned gpio, bool direction_may_change);

/* gpio_export()的逆操作*/

void gpio_unexport();

/* 创建一个sysfs连接到已导出的GPIO节点*/

int gpio_export_link(struct device *dev, const char *name,

unsigned gpio)

/* 改变sysfs中的一个GPIO节点的极性*/

int gpio_sysfs_set_active_low(unsigned gpio, int value);

在一个内核驱动申请一个GPIO之后,它可以通过gpio_export()使其在sysfs接口中可见。该驱动可以控制信号方向是否可修改。这有助于防止用户空间代码无意间破坏重要的系统状态。

这个明确的导出有助于(通过使某些实验更容易来)调试,也可以提供一个始终存在的接口,与文档配合作为一个板级支持包的一部分。

在GPIO被导出之后,gpio_export_link()允许在sysfs文件系统的任何地方创建一个到这个GPIO sysfs节点的符号链接。这样驱动就可以通过一个描述性的名字,在sysfs中他们所拥有的设备下提供一个(到这个GPIO sysfs节点的)接口。

驱动可以使用gpio_sysfs_set_active_low() 来在用户空间隐藏电路板之间GPIO 线的极性差异。这个仅对sysfs接口起作用。极性的改变可以在gpio_export()前后进行,且之前使能的轮询操作(poll(2))支持(上升或下降沿)将会被重新配置来遵循这个设置。

Linux内核崩溃原因分析及错误跟踪技术

Linux内核崩溃原因分析及错误跟踪技术 随着嵌入式Linux系统的广泛应用,对系统的可靠性提出了更高的要求,尤其是涉及到生命财产等重要领域,要求系统达到安全完整性等级3级以上[1],故障率(每小时出现危险故障的可能性)为10-7以下,相当于系统的平均故障间隔时间(MTBF)至少要达到1141年以上,因此提高系统可靠性已成为一项艰巨的任务。对某公司在工业领域14 878个控制器系统的应用调查表明,从2004年初到2007年9月底,随着硬软件的不断改进,根据错误报告统计的故障率已降低到2004年的五分之一以下,但查找错误的时间却增加到原来的3倍以上。 这种解决问题所需时间呈上升的趋势固然有软件问题,但缺乏必要的手段以辅助解决问题才是主要的原因。通过对故障的统计跟踪发现,难以解决的软件错误和从发现到解决耗时较长的软件错误都集中在操作系统的核心部分,这其中又有很大比例集中在驱动程序部分[2]。因此,错误跟踪技术被看成是提高系统安全完整性等级的一个重要措施[1],大多数现代操作系统均为发展提供了操作系统内核“崩溃转储”机制,即在软件系统宕机时,将内存内容保存到磁盘[3],或者通过网络发送到故障服务器[3],或者直接启动内核调试器[4]等,以供事后分析改进。 基于Linux操作系统内核的崩溃转储机制近年来有以下几种: (1) LKCD(Linux Kernel Crash Dump)机制[3]; (2) KDUMP(Linux Kernel Dump)机制[4]; (3) KDB机制[5]; (4) KGDB机制[6]。 综合上述几种机制可以发现,这四种机制之间有以下三个共同点: (1) 适用于为运算资源丰富、存储空间充足的应用场合; (2) 发生系统崩溃后恢复时间无严格要求; (3) 主要针对较通用的硬件平台,如X86平台。 在嵌入式应用场合想要直接使用上列机制中的某一种,却遇到以下三个难点无法解决: (1) 存储空间不足 嵌入式系统一般采用Flash作为存储器,而Flash容量有限,且可能远远小于嵌入式系统中的内存容量。因此将全部内存内容保存到Flash不可行。

关于Linux 内核中五个主要子系统的介绍

关于Linux 内核中五个主要子系统的介绍 发布时间:2008.01.02 06:23来源:赛迪网作者:sixth 1.进程调度(SCHED):控制进程对CPU的访问。当需要选择下一个进程运行时,由调度程序选择最值得运行的进程。可运行进程实际上是仅等待CPU资源的进程,如果某个进程在等待其它资源,则该进程是不可运行进程。Linux使用了比较简单的基于优先级的进程调度算法选择新的进程。 2.内存管理(MM)允许多个进程安全的共享主内存区域。Linux的内存管理支持虚拟内存,即在计算机中运行的程序,其代码,数据,堆栈的总量可以超过实际内存的大小,操作系统只是把当前使用的程序块保留在内存中,其余的程序块则保留在磁盘中。必要时,操作系统负责在磁盘和内存间交换程序块。内存管理从逻辑上分为硬件无关部分和硬件有关部分。硬件无关部分提供了进程的映射和逻辑内存的对换;硬件相关的部分为内存管理硬件提供了虚拟接口。 3.虚拟文件系统(VirtualFileSystem,VFS)隐藏了各种硬件的具体细节,为所有的设备提供了统一的接口,VFS提供了多达数十种不同的文件系统。虚拟文件系统可以分为逻辑文件系统和设备驱动程序。逻辑文件系统指Linux所支持的文件系统,如ext2,fat等,设备驱动程序指为每一种硬件控制器所编写的设备驱动程序模块。 4.网络接口(NET)提供了对各种网络标准的存取和各种网络硬件的支持。网络接口可分为网络协议和网络驱动程序。网络协议部分负责实现每一种可能的网络传输协议。网络设备驱动程序负责与硬件设备通讯,每一种可能的硬件设备都有相应的设备驱动程序。 5.进程间通讯(IPC) 支持进程间各种通信机制。处于中心位置的进程调度,所有其它的子系统都依赖它,因为每个子系统都需要挂起或恢复进程。一般情况下,当一个进程等待硬件操作完成时,它被挂起;当操作真正完成时,进程被恢复执行。例如,当一个进程通过网络发送一条消息时,网络接口需要挂起发送进程,直到硬件成功地完成消息的发送,当消息被成功的发送出去以后,网络接口给进程返回一个代码,表示操作的成功或失败。其他子系统以相似的理由依赖于进程调度。

I2C 接口实现通用 IO 扩展

Altera 公司 1AN-494-1.0 应用笔记494 利用MAX II CPLD 的I 2C 总线接 口实现GPIO 引脚扩展 引言本设计实例展示了Altera ? MAX ? II CPLD 通过工业标准I 2C 总线提供通 用I/O (GPIO) 引脚扩展的能力。为了减小封装尺寸和引脚数量,很多微 处理器系统限制了通用I/O 的数量。然而,如果系统有I 2C 接口,那么 本设计可以通过I 2C 总线来加入更多的 GPIO 引脚。借助于MAX II CPLD ,增加的这些GPIO 引脚要比微处理器的I/O 引脚功耗低。 GPIO 引脚扩展和I 2C 在某些情况下,可能需要通过较长的PCB 走线来访问系统中的GPIO 引 脚(例如蜂窝电话中不同部分的连接)。I 2C 接口是2线系统,本设计通 过普通的2线走线,在远端提供多个输入和输出引脚。这提高了设计灵活 性以及整个系统的物理紧凑性,还减小了封装尺寸和引脚数量。 可以通过这些通用输出引脚来连接并控制风扇控制器、LED 状态显示和 状态指示器等设备。同样的,复位引脚和按钮开关等设备可以直接连接到 CPLD 的通用输入上,实现各种应用。图1.通过I 2C 总线实现GPIO 引脚扩展 2007年12月,1.0版

利用MAX II CPLD的I2C总线接口实现GPIO引脚扩展 GPIO引脚扩展的I2C接口MAX II CPLD用作I2C总线从机,在其I2C接口上有两个引脚:I2C时钟SCL和I2C 数据线SDA。作为 I2C主机的主系统和MAX II(用作 I2C从机)进行通信。CPLD为主系统提供8个通用输入端口和8个通用输出端口。GPIO引脚并行接收 I2C总线串行发送的数据。这样,可以同时读写所有8个通用I/O。 I2C接口 对于I2C接口,CPLD(I2C从机)提供一个符合常用I2C 协议的内置7位地址。主机发送起始信号,然后是7位地址和一个R/W位。当I2C总线上广播的地址和从机设备的地址匹配时,根据主机发送的读或者写信号,设备发送一个ACK (应答)信号,然后是数据。随后是另一个ACK信号。以此不断进行数据交换,直到主机发送Stop (P)信号。 图2.I2C信号格式 表1.I2C接口引脚说明 信号目的方向SCL I2C时钟输出SDA I2C串行数据双向 2Altera公司

Linux内核结构详解教程

Linux内核结构详解教程 ─────Linux内核教程 linux内核就像人的心脏,灵魂,指挥中心。 内核是一个操作系统的核心,它负责管理系统的进程,内存,设备驱动程序,文件和网络系统,决定着系统的性能和稳定性。内核以独占的方式执行最底层任务,保证系统正常运行。协调多个并发进程,管理进程使用的内存,使它们相互之间不产生冲突,满足进程访问磁盘的请求等等. 严格说Linux并不能称做一个完整的操作系统.我们安装时通常所说的Linux,是有很多集合组成的.应称为GNU/Linux. 一个Linux内核很少1.2M左右,一张软盘就能放下. 内容基础,语言简短简洁 红联Linux论坛是致力于Linux技术讨论的站点,目前网站收录的文章及教程基本能满足不同水平的朋友学习。 红联Linux门户: https://www.sodocs.net/doc/2c17929907.html, 红联Linux论坛: https://www.sodocs.net/doc/2c17929907.html,/bbs 红联Linux 论坛大全,所有致力点都体现在这 https://www.sodocs.net/doc/2c17929907.html,/bbs/rf/linux/07.htm

目录 Linux内核结构详解 Linux内核主要五个子系统详解 各个子系统之间的依赖关系 系统数据结构 Linux的具体结构 Linux内核源代码 Linux 内核源代码的结构 从何处开始阅读源代码 海量Linux技术文章

Linux内核结构详解 发布时间:2006-11-16 19:05:29 Linux内核主要由五个子系统组成:进程调度,内存管理,虚拟文件系统,网络接口,进程间通信。

Linux内核主要五个子系统详解 发布时间:2006-11-16 19:05:54 1.进程调度(SCHED):控制进程对CPU的访问。当需要选择下一个进程运行时,由调度程序选择最值得运行的进程。可运行进程实际上是仅等待CPU资源的进程,如果某个进程在等待其它资源,则该进程是不可运行进程。Linux使用了比较简单的基于优先级的进程调度算法选择新的进程。 2.内存管理(MM)允许多个进程安全的共享主内存区域。Linux的内存管理支持虚拟内存,即在计算机中运行的程序,其代码,数据,堆栈的总量可以超过实际内存的大小,操作系统只是把当前使用的程序块保留在内存中,其余的程序块则保留在磁盘中。必要时,操作系统负责在磁盘和内存间交换程序块。内存管理从逻辑上分为硬件无关部分和硬件有关部分。硬件无关部分提供了进程的映射和逻辑内存的对换;硬件相关的部分为内存管理硬件提供了虚拟接口。 3.虚拟文件系统(VirtualFileSystem,VFS)隐藏了各种硬件的具体细节,为所有的设备提供了统一的接口,VFS提供了多达数十种不同的文件系统。虚拟文件系统可以分为逻辑文件系统和设备驱动程序。逻辑文件系统指Linux所支持的文件系统,如ext2,fat等,设备驱动程序指为每一种硬件控制器所编写的设备驱动程序模块。 4.网络接口(NET)提供了对各种网络标准的存取和各种网络硬件的支持。网络接口可分为网络协议和网络驱动程序。网络协议部分负责实现每一种可能的网络传输协议。网络设备驱动程序负责与硬件设备通讯,每一种可能的硬件设备都有相应的设备驱动程序。 5.进程间通讯(IPC) 支持进程间各种通信机制。 处于中心位置的进程调度,所有其它的子系统都依赖它,因为每个子系统都需要挂起或恢复进程。一般情况下,当一个进程等待硬件操作完成时,它被挂起;当操作真正完成时,进程被恢复执行。例如,当一个进程通过网络发送一条消息时,网络接口需要挂起发送进程,直到硬件成功地完成消息的发送,当消息被成功的发送出去以后,网络接口给进程返回一个代码,表示操作的成功或失败。其他子系统以相似的理由依赖于进程调度。

linux内核GPIO模拟I2C实例

linux内核GPIO模拟I2C实例 2010-10-11 作者:cvip302814 来源:cvip302814的blog 前言: 在许多情况下,我们并没有足够的I2C总线,本文主在介绍如何利用Linux 内核中的i2c-gpio模块,利用2条GPIO线模拟i2c总线,并挂载设备。 思路: 先通过对i2c-gpio所定义的结构体初始化(包括初始化i2c的2条线,频率,timeout等)并将i2c-gpio模块编译进内核,实现用GPIO_X,GPIO_Y 2条GPIO线注册新的i2c总线。此时这个模块对i2c设备是透明的,及挂在这2条GPIO线的i2c设备可以直接使用Linux内核通用的i2c设备注册,传输和注销等方法。 步骤: 首先确认在注册i2c-gpio模块前,所要用到的2条GPIO口是没有被系统其它地方所调用的。 在每个系统平台启动时,都会打开一系列的设备,他们通常实现在arch/目录下相应的平台子目录中的例如setup.c,devices.c文件中,在这里我们进行i2c总线的注册以及设备的挂载。i2c-gpio定义的结构在 include/linux/i2c-gpio.h中: /** * struct i2c_gpio_platform_data - Platform-dependent data for i2c-gpio * @sda_pin: GPIO pin ID to use for SDA * @scl_pin: GPIO pin ID to use for SCL * @udelay: signal toggle delay. SCL frequency is (500 / udelay) kHz * @timeout: clock stretching timeout in jiffies. If the slave keeps * SCL low for longer than this, the transfer will time out. * @sda_is_open_drain: SDA is configured as open drain, i.e. the pin * isn't actively driven high when setting the output value high. * gpio_get_value() must return the actual pin state even if the * pin is configured as an output. * @scl_is_open_drain: SCL is set up as open drain. Same requirements * as for sda_is_open_drain apply. * @scl_is_output_only: SCL output drivers cannot be turned off. */ struct i2c_gpio_platform_data { unsigned int sda_pin;

对GPIO的理解

对通用输入输出GPIO的深入理解 一.GPIO简介 I/O(Input/Output)接口是一颗微控制器必须具备的最基本外设功能。通常在ARM里,所有I/O都是通用的,称为GPIO(General Purpose Input/Output)。每个GPIO端口包含8个管脚,如PA端口是PA0~PA7。GPIO 模块支持多个可编程输入/输出管脚(具体取决于与GPIO复用的外设的使用情况)。GPIO模块包含以下特性: 1)可编程控制GPIO中断 ---屏蔽中断发生 ---边沿触发(上升沿、下降沿、双边沿) ---电平触发(高电平、低电平) 2)输入/输出可承受5V 3)在读和写操作中通过地址线进行位屏蔽 4)可编程控制GPIO管脚配置: ---弱上拉或弱下拉电阻 ---2mA、4mA、8mA驱动,以及带驱动转换速率(Slew Rate)控制的8mA 驱动 ---开漏使能 ---数字输入使能 二.GPIO的各种模式 GPIO管脚可以被配置为多种工作模式,其中有3种比较常用:高阻输入、推挽输出、开漏输出 1. 高阻输入(Input) 图1.1 GPIO高阻输入模式结构示意图 为减少信息传输线的数目,大多数计算机中的信息传输线采用总线形式,

即凡要传输的同类信息都在同一组传输线,且信息是分 时传送的。在计算机中一般有三组总线,即数据总线、地址总线和控制总线。为防止信息相互干扰,要求凡挂到总线上的寄存器或存储器等,它的输入输出端不仅能 呈现0、1两个信息状态,而且还应能呈现第三个状态----高阻抗状态,即此时好像它们的输出被开关断开,对总线状态不起作用,此时总线可由其他器件占用。三态缓冲器即可实现上述功能,它除具有输入输出端之外,还有一控制端。 如图1.1所示,为GPIO管脚在高阻输入模式下的等效结构示意图。这是一个管脚的情况,其它管脚的结构也是同样的。输入模式的结构比较简单,就是一个带有施密特触发输入(Schmitt-triggered input)的三态缓冲器(U1),并具有很高的输入等效阻抗。施密特触发输入的作用是能将缓慢变化的或者是畸变的输入脉冲信号整形成比较理想的矩形脉冲信号。执行GPIO管脚读操作时,在读脉冲(Read Pulse)的作用下会把管脚(Pin)的当前电平状态读到内部总线上(Internal Bus)。在不执行读操作时,外部管脚与内部总线之间是隔离的。 2. 推挽输出(Output) 图1.2 GPIO推挽输出模式结构示意图 推挽输出原理:在功率放大器电路中大量采用推挽放大器电路,这种电路中用两只三极管构成一级放大器电路, 两只三极管分别放大输入信号的正半周和负半周,即用一只三极管放大信号的正半周,用另一只三极管放大信号的负半周,两只三极管输出的半周信号在放大器负载 上合并后得到一个完整周期的输出信号。 推挽放大器电路中,一只三极管工作在导通、放大状态时,另一只三极管处于截止状态,当输入信号变化到另一个半周后,原先导通、放大的三极管进入截止,而原先截止的三极管进入导通、放大状态,两只三极管在不断地交替导通放大和截止变化,所以称为推挽放大器(https://www.sodocs.net/doc/2c17929907.html,)。

Linux下GPIO驱动详解文章

https://www.sodocs.net/doc/2c17929907.html,/Linux/2011-09/43084.htm 打算跟着友善之臂的《mini2440 Linux移植开发指南》见https://www.sodocs.net/doc/2c17929907.html,/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 strongly 17 * encouraged not to use these in new code. They will be marked deprecated 18 * very soon. 19 * 20 * Most of the functionality can be either replaced by the gpiocfg calls 21 * 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 them 24 * 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) 即可

LINUX内核源文件介绍以及头文件介绍

LINUX 内核源文件介绍以及头文件介绍 LINUX 内核源文件介绍以及头文件介绍.txt两人之间的感情就像织毛衣,建立的时候一针一线,小心而漫长,拆除的时候只要轻轻一拉。。。。*******************LINUX 内核(0.11)源文件介绍****************** 1、内核源文件放置目录: | |————boot 系统引导汇编程序目录 | |————fs 文件系统目录 | |————include 头文件目录 | |————init 内核初始化程序目录 | |————kernel 内存进程调度、信号处理、系统调用等程序的目录 | |————lib 内核库函数目录 | |————mm 内存管理程序目录 | |————tools 生成内核Image文件的工具程序目录 | |————Makefile文件 | 2、引导启动程序目录boot 包含3个汇编语言文件,是内核源文件中最先被编译的程序。 功能:当计算机家电时引导内核启动,将内核代码加载到内存中,并完成系统初始化工作。 boot | |————bootsect.s 磁盘引导块程序,编译后会驻留在磁盘的第一个扇区中| |————setup.s 读取机器的硬件配置参数,并把内核模式system移动到适当的内存位置处 |

|————head.s 会被编译连接在system模块的最前部分,主要进行硬件设备的探测配置和内存管理页面的配置工作 | 3、文件系统目录fs 包含17个C语言程序 fs | |——buffer.c 管理高速缓冲区 | |——file_table.c 在0.11仅定义了一个文件句柄(描述符)结构数组 | |——ioctl.c 将引用kernel/chr_dev/tty.c中的函数,实现字符设备的IO 控制功能 | |——exec.c 主要包含一个执行程序函数do_execve() | |——fcntl.c 实现文件I/O控制的系统调用函数 | |——read_write.c 实现文件读/写和定位的三个系统调用函数 | |——stat.c 实现了两个获取文件状态的系统调用函数 | |——open.c 主要包含实现修改文件属性和创建与关闭文件的系统调用函数 | |——char_dev.c 主要包含字符设备读写函数rw_char() | |——pipe.c 包含管道读写函数和创建管道的系统调用函数 | |——file_dev.c 包含基于i节点和描述符结构的文件读写函数。 | |——namei.c 主要包括文件系统中目录名和文件名的操作函数和系统调用函数 | |——block_dev.c 包含块数据读和写函数 | |——inode.c 包含针对文件系统i节点操作的函数 | |——truncate.c 用于在删除文件时释放文件所占用的设备数据空间 | |——bitmap.c 用于处理文件系统中i节点和逻辑数据块的位图 |

(完整版)linux内核技术

一、教学目的 SMP、多核系统、高性能浮点处理器和新型总线等创新技术,带动操作系统不断发展。本课程使硕士生了解linux的基本原理和结构特征,提高应用现代操作系统的水平、能开发特定的内核功能、设备驱动程序和复杂应用软件的能力。 二、教学内容与要求 1掌握处理器在进程地址空间上的三种运行位置,了解内核编程不能使用C库函数和FPU,以及可能产生内存故障、核心栈溢出和四种内核竞争情形的原因。(2学时)2熟悉进程描述符的组织,进程上下文和进程状态转换,和fork,exec,wait,exit,clone,linux线程和内核线程的实现原理和应用。了解COW和避免出现孤儿进程技术。 (4小时) 3介绍支持SMP的O(1)调度,用户和内核抢占和进程上下文切换,了解优先级复算,睡眠和唤醒机制,SMP的负载均衡。(4小时) 4掌握在x86体系结构上系统调用的具体实现原理,接口参数传递,用户地址空间和核心地址空间之间的数据传输,和增加新的系统功能的方法。(2小时)5熟悉在x86体系结构上Linux中断和异常的处理原理,中断注册、共享、控制,和中断上下文的意义,中断和设备驱动程序的关系,以及设备驱动程序结构和用户接口。 (4小时) 6中断处理程序被分解为top half和bottom half的原因,介绍linux的softirq,tasklet,ksoftirqd和work queue,分析进程与top half,bottom half的竞争情形和同步。(4小时)7掌握内核同步原理和方法:原子操作,自旋锁,(读—写)信号量,完成变量,bkl,seqlock和延迟内核抢占。了解指令“路障”。(4小时) 8介绍系统时钟和硬件定时器,单处理器和多处理器上的linux计时体系结构,定时的时间插补原理,单处理器和多处理器上的时钟中断处理,动态定时器的数据结构和算法原理,定时器竞争情形,延迟函数。Time,gettimeofday,adjtimex,setitimer,alarm 的实现原理和应用。(4小时) 9熟悉进程地址空间的区和页,分配和释放物理页,物理地址与逻辑地址、虚地址之间的映射,slub分配原理和方法,高端物理内存的映射。(4小时) 10介绍VFS原理,超级块,inode结构和方法,dentry结构和方法,file结构和方法,以及进程打开文件表,linux中的文件系统。(2小时) 11讲解块设备缓冲,bio结构,I/O请求队列,和有最终期限的块I/O调度算法。(2小时) 12熟悉进程地址空间的分区,mm_struct结构,vm_area_struct结构和操作,,进程的页表文件映射接口mmap原理和方法。(2小时) 13熟悉页cache和radix_tree,缓冲区cache,和pdflush内核线程原理。(2小时) 三、教学方式 教学方式:课堂讲授 考试方式:堂上考试、考查都采用笔试。

ARM-Linux下的GPIO中断程序.

ARM-Linux下的GPIO中断程序 [日期:2011-03-22] 来源:Linux社区作者:cskywit 今日为了调试ARM板上的GPIO引脚中断效果,以便在后续项目使用ARM与ZLG7290按键LED中断芯片连接中随意选择空闲的GPIO引脚来作为ZLG7290的中断信号线,特意编写了一个小的Linux GPIO中断驱动程序下载到开发板上做实验。经验证,这种软件中断方式也还差强人意。下面贴出自己编写的不成熟的代码,见笑(<-_->)。 实验的硬件电路为ARM GPIO的PB17连接一个共阴LED,PB18与PB19连接,PB18由中断驱动设置为低电平触发,PB19由GPIO驱动程序控制,上层应用程序通过驱动控制PB19高低电平变化,从而引发PB18发生中断,中断程序中控制PB17的LED亮和灭。 Linux中断驱动部分: /* * PB18_IRQTest.c * This is a test program for sam9260, using PB19(J5_18 pin) input a signal to PB18(J5_16 pin), * PB18 receive this signal as IRQ and make the LED linking on PB17((J5_14 pin)) turn on or turn off * * @Author: Cun Tian Rui * @Date :March.18.2011 */ #include #include #include #include #include #include #include #include #include #include #include #include #include

(完整)STM32中使用GPIO的总结(超强),推荐文档

STM32 GPIO使用 操作步骤: 1.使能GPIO对应的外设时钟 例如://使能GPIOA、GPIOB、GPIOC对应的外设时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB| RCC_APB2Periph_GPIOC , ENABLE); 2.声明一个GPIO_InitStructure结构体 例如: GPIO_InitTypeDef GPIO_InitStructure; 3.选择待设置的GPIO管脚 例如:/* 选择待设置的GPIO第7、8、9管脚位,中间加“|”符号 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9; 4.设置选中GPIO管脚的速率 例如:/* 设置选中GPIO管脚的速率为最高速率2MHz */ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; //最高速率2MHz 5.设置选中GPIO管脚的模式 例如:/* 设置选中GPIO管脚的模式为开漏输出模式*/ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; //开漏输出模式 6. 根据GPIO_InitStructure中指定的参数初始化外设GPIOX 例如:/* 根据GPIO_InitStructure中指定的参数初始化外设GPIOC */ GPIO_Init(GPIOC, &GPIO_InitStructure); 7.其他应用 例:将端口GPIOA的第10、15脚置1(高电平) GPIO_SetBits(GPIOA, GPIO_Pin_10 | GPIO_Pin_15); 例:将端口GPIOA的第10、15脚置0(低电平) GPIO_ResetBits(GPIOA, GPIO_Pin_10 | GPIO_Pin_15);

Linux kernel内核升级全过程,教你一次成功

序言 由于开发环境需要在linux-2.6内核上进行,于是准备对我的虚拟机上的Linux系统升级。没想到这一弄就花了两天时间( 反复装系统,辛苦啊~~),总算把Linux系统从2.4.20-8内核成功升级到了2.6.18内核。 网上虽然有很多介绍Linux内核升级的文章,不过要么过时,下载链接失效;要么表达不清,不知所云;更可气的是很多 文章在转载过程中命令行都有错误。刚开始我就是在这些“攻略”的指点下来升级的,以致于浪费了很多时间。 现在,费尽周折,升级成功,心情很爽,趁性也来写个“升级攻略”吧!于是特意又在虚拟机上重新安装一个Linux系统 ,再来一次完美的升级,边升级边记录这些步骤,写成一篇Linux内核升级记实录(可不是回忆录啊!),和大家一起分享 ~~! 一、准备工作 首先说明,下面带#号的行都是要输入的命令行,且本文提到的所有命令行都在终端里输入。 启动Linux系统,并用根用户登录,进入终端模式下。 1、查看Linux内核版本 # uname -a 如果屏幕显示的是2.6.x,说明你的已经是2.6的内核,也用不着看下文了,该干什么干什么去吧!~~~如果显示的是 2.4.x,那恭喜你,闯关通过,赶快进行下一步。 2、下载2.6内核源码 下载地址:https://www.sodocs.net/doc/2c17929907.html,/pub/linux/kernel/v2.6/linux-2.6.18.tar.bz2 3、下载内核升级工具 (1)下载module-init-tools-3.2.tar.bz2 https://www.sodocs.net/doc/2c17929907.html,/pub/linux/utils/kernel/module-init-tools/module-init-tools-3.2.tar.bz2 (2)下载mkinitrd-4.1.18-2.i386.rpm https://www.sodocs.net/doc/2c17929907.html,/fedora/linux/3/i386/RPMS.core/mkinitrd-4.1.18-2.i386.rpm (3)下载lvm2-2.00.25-1.01.i386.rpm https://www.sodocs.net/doc/2c17929907.html,/fedora/linux/3/i386/RPMS.core/lvm2-2.00.25-1.01.i386.rpm (4)下载device-mapper-1.00.19-2.i386.rpm https://www.sodocs.net/doc/2c17929907.html,/fedora/linux/3/i386/RPMS.core/device-mapper-1.00.19-2.i386.rpm (2.6.18内核和这4个升级工具我都有备份,如果以上下载地址失效,请到https://www.sodocs.net/doc/2c17929907.html,/guestbook留下你的邮箱,我给你发过去)

Linux内核目录文件简介

Linux V0.11目录文件简介 ●Makefile文件:该文件是编译辅助工具软件make的参数配置文件。 ●boot目录:功能是当计算机加电时引导内核启动,将内核代码加载到内存中,并做一些进入入32位保护运行方式前的系统初始化工作。 ①Bootsect.s:磁盘引导块程序,驻留磁盘第一个扇区。0x7C00 ②Setup.s:读取机器的硬件配置参数,并把内核模块system移动到适当的内存位置处。 ③Head.s:被编译连接在system模块的最前部分,主要进行硬件设备的探测设置和内存管理页面的初始设置工作。 ●fs目录:文件系统实现程序的目录。 1、file_table.c文件中,目前仅定义了一个文件句柄(描述符)结构数组。 2、ioctl.c文件将引用kernel/chr_dev/tty.c中的函数,实现字符设备的io控制功能。 3、exec.c程序主要包含一个执行程序函数do_execve(),它是所有exec()函数簇中的主要函数。 4、fcntl.c程序用于实现文件i/o控制的系统调用函数。 5、read_write.c程序用于实现文件读/写和定位三个系统调用函数。 6、stat.c程序中实现了两个获取文件状态的系统调用函数。 7、open.c程序主要包含实现修改文件属性和创建与关闭文件的系统调用函数。 8、char_dev.c主要包含字符设备读写函数rw_char()。 9、pipe.c程序中包含管道读写函数和创建管道的系统调用。 10、file_dev.c程序中包含基于i节点和描述符结构的文件读写函数。 11、namei.c程序主要包括文件系统中目录名和文件名的操作函数和系统调用函数。 12、block_dev.c程序包含块数据读和写函数。 13、inode.c程序中包含针对文件系统i节点操作的函数。 14、truncate.c程序用于在删除文件时释放文件所占用的设备数据空间。 15、bitmap.c程序用于处理文件系统中i节点和逻辑数据块的位图。 16、super.c程序中包含对文件系统超级块的处理函数。 17、buffer.c程序主要用于对内存高速缓冲区进行处理。 ·虚框中的ll_rw_block是块设备的底层读函数,它并不在fs目录中,而是 kernel/blk_dev/ll_rw_block.c中的块设备读写驱动函数。放在这里只是让我们清楚的看到,文件系统对于块设备中数据的读写,都需要通过高速缓冲区与块设备的驱动程序 (ll_rw_block())来操作来进行,文件系统程序集本身并不直接与块设备的驱动程序打交道。

嵌入式系统GPIO 输入输出实验报告

实验四GPIO 输入实验 一、实验目的 1、能够使用GPIO的输入模式读取开关信号。 2、掌握GPIO相关寄存器的用法和设置。 3、掌握用C语言编写程序控制GPIO。 二、实验环境 PC机一台 ADS 1.2集成开发环境一套 EasyARM2131教学实验平台一套 三、实验内容 1.实验通过跳线JP8 连接KEY1与P0.16,程序检测按键KEY1 的状态,控制蜂 鸣器BEEP 的鸣叫。按下KEY1,蜂鸣器鸣叫,松开后停止蜂鸣。(调通实验后,改为KEY3键进行输入)。 2.当检测到KEY1有按键输入时点亮发光二极管LED4并控制蜂鸣器响,软件延时 后关掉发光管并停止蜂鸣,然后循环这一过程直到检测按键没有输入。(键输入改为键KEY4,发光管改为LED6)。 3.结合实验三,当按下按键Key1时,启动跑马灯程序并控制蜂鸣器响,软件延时 后关掉发光管并停止蜂鸣,然后循环这一过程直到检测按键再次按下。 四、实验原理 当P0 口用于GPIO输入时(如按键输入),内部无上拉电阻,需要加上拉电阻,电路图参见图 4.2。 进行GPIO 输入实验时,先要设置IODIR 使接口线成为输入方式,然后读取IOPIN 的值即可。

图 4.2按键电路原理图 实验通过跳线JP8 连接KEY1_P0.16,程序检测按键KEY1 的状态,控制蜂鸣器BEEP 的鸣叫。按下KEY1,蜂鸣器鸣叫,松开后停止蜂鸣。 在这个实验中,需要将按键KEY1 输入口P0.16 设为输入口而蜂鸣器控制口P0.7 设置为输出口。蜂鸣器电路如图 4.3 所示,当跳线JP6 连接蜂鸣器时,P0.7 控制蜂鸣器,低电平时蜂鸣器鸣叫。LED灯电路如图4.4所示,低电平时灯亮。 图 4.3 蜂鸣器控制电路

Linux内核文档:GPIO接口

原文:Documentation/gpio.txt 翻译:tekkamanninja@https://www.sodocs.net/doc/2c17929907.html, 翻译完成时间:2012年2月18日星期六 V1.0

目录 什么是GPIO? (3) GPIO公约 (3) 标识GPIO (3) 使用 GPIO (4) 访问自旋锁安全的GPIO (4) 访问可能休眠的GPIO (5) 声明和释放GPIO (5) GPIO映射到IRQ (7) 模拟开漏信号 (7) GPIO实现者的框架 (可选) (8) 控制器驱动: gpio_chip (8) 平台支持 (8) 板级支持 (9) 用户空间的Sysfs接口(可选) (9) Sysfs中的路径 (9) 从内核代码中导出 (10)

本文档提供了一个在Linux下访问GPIO的公约概述。 这些函数以gpio_* 作为前缀。其他的函数不允许使用这样的前缀或相关的__gpio_* 前缀。 什么是GPIO? "通用输入/输出口"(GPIO)是一个灵活的由软件控制的数字信号。他们可由多种芯片提供,且对于从事嵌入式和定制硬件的Linux开发者来说是比较熟悉。每个GPIO都代表一个连接到特定引脚或球栅阵列(BGA)封装中“球珠”的一个位。电路板原理图显示了GPIO与外部硬件的连接关系。驱动可以编写成通用代码,以使板级启动代码可传递引脚配置数据给驱动。 片上系统(SOC) 处理器对GPIO有很大的依赖。在某些情况下,每个非专用引脚都可配置为GPIO,且大多数芯片都最少有一些GPIO。可编程逻辑器件(类似FPGA) 可以方便地提供GPIO。像电源管理和音频编解码器这样的多功能芯片经常留有一些这样的引脚来帮助那些引脚匮乏的SOC。同时还有通过I2C或SPI串行总线连接的"GPIO扩展器"芯片。大多数PC的南桥有一些拥有GPIO能力的引脚(只有BIOS固件才知道如何使用他们)。 GPIO的实际功能因系统而异。通常的用法有: - 输出值可写(高电平=1, 低电平=0)。一些芯片也有如何驱动这些值的选项,例如只允许输出一个值、支持“线与”及其他取值类似的模式(值得注意的是“开漏”信号)。 - 输入值可读(1、0)。一些芯片支持引脚在配置为“输出”时回读,这对于类似“线与”的情况(以支持双向信号)是非常有用的。GPIO 控制器可能有输入去毛刺/消抖逻辑,这有时需要软件控制。 - 输入通常可作为IRQ信号,一般是沿触发,但有时是电平触发。这样的IRQ 可能配置为系统唤醒事件,以将系统从低功耗状态下唤醒。 - 通常一个GPIO根据不同产品电路板的需求,可以配置为输入或输出,也有仅支持单向的。 - 大部分GPIO 可以在持有自旋锁时访问,但是通常由串行总线扩展的GPIO不允许持有自旋锁。但某些系统也支持这种类型。 对于给定的电路板,每个GPIO都用于某个特定的目的,如监控MMC/SD卡的插入/移除、检测卡的写保护状态、驱动LED、配置收发器、模拟串行总线、复位硬件看门狗、感知开关状态等等。 GPIO公约 注意,这个叫做“公约”,因为这不是强制性的,不遵循这个公约是无伤大雅的,因为此时可移植性并不重要。GPIO常用于板级特定的电路逻辑,甚至可能随着电路板的版本而改变,且不可能在不同走线的板子上使用。仅有在很少的功能上才具有可移植性,其他功能是平台特定。这也是由于“胶合”的逻辑造成的。 此外,这不需要任何的执行框架,只是一个接口。某个平台可能通过一个简单的访问芯片寄存器的内联函数来实现它,其他平台可能通过委托一系列不同的GPIO控制器的抽象函数来实现它。(有一些可选的代码能支持这种策略的实现,本文档后面会介绍,但作为GPIO接口的客户端驱动程序必须与它的实现无关。) 也就是说,如果在他们的平台上支持这个公约,驱动应该尽可能的使用它。平台必须在Kconfig中声明对GENERIC_GPIO 的支持(布尔型true),并提供一个 文件。那些调用标准GPIO函数的驱动应该在Kconfig 入口中声明依赖GENERIC_GPIO。当驱动包含文件: #include GPIO函数是可用,无论是“真实代码”还是经优化过的语句。 如果你遵守这个公约,当你的代码完成后,对其他的开发者来说会更容易看懂和维护。 注意,这些操作包含所用平台的I/O 屏障代码,驱动无须显式地调用他们。 标识GPIO

linux内核是什么意思

千锋教育https://www.sodocs.net/doc/2c17929907.html, 精品课程 全程面授 千锋教育-中国IT 职业教育领先品牌 linux 培训学院哪家好 Linux 是常常用来形容整个基于Linux 内核,并且使用工程各种工具和数据库的操作系统。 很受欢迎,使用非常广泛。到了云时代,Linux 炙手可热,掌握。 知识和技能,能找到非常有前景的工作。 既然要学习,最重要的是找到一家好的培训机构。师资,费用,教学质量,这些都要考虑。 2017年5月26日上午,“千锋Linux 云计算运维及开发课程2017版”新品发布会在千锋互联科技有限公司总部北京隆重举行 届时,千锋教育总部的各位领导、千锋教育分校区的校长及网络咨询部、网络运营部代表等各界人士一起出席了“千锋Linux 云计算运维及开发课程2017版”新品发布会。 千锋Linux 云计算课程总监(中国第29位红帽认证架构师,以下简称:杨老师)向各位出席此次发布会的代表详细介绍了“千锋Linux 云计算运维及开发课程2017版”的课程设置体系内容及本年度首期开班招生计划要求。 职业教育领先品牌 千锋教育 linux 培训学院哪家好 ?千锋Linux 云计算培训课程,全方位培养运维工程师 Linux 与微软的“战争”持续已久,谁也不能抢占各自的用户。不过,全球200万名Linux 工程师终于等到了这一天,是时候对微软说“不”了,因为“云计算”时代即将来临,以及廉价的、超小型笔记本电脑正在快速普及。Linux 工程师等待已久了的“云计算”时代。 日前,百资信息科技公司创办人及执行人林政道和香港Linux 商会会长简锦源在广州信息产业周上指出,由于手机、超小型笔记本等移动互联网终端的出现,这种移动终端设备采用Linux 平台作为操作系统已经成为IT 业界的一种发展趋势。因为中国是全球的PC 制造基地和最大的消费市场,其已成为全球推动Linux 发展的最重要的力量之一。 在云计算的初级阶段,我们一定要把握先机,好好学习云计算的相关知识。为此,千锋推出Linux 云计算培训。千锋Linux 云计算培训课程实行免费试学两周,不花一分钱,满意后再报名的政策,全心全意为学员提供服务。讲师方面,千锋Linux 讲师均是拥有多年经验的老师,并特聘一线名企作为技术顾问;课程体系方面,千锋Linux 课程体系是最贴合企业需求的面授课程,并有名企技术顾问定期进行调整;学员福利方面,千锋Linux 为首期报名学员减免1000元学费,并赠送5个月阿里云ECS 云主机。2017年7月17日,千锋Linux 云计算培训等你来战

相关主题