linux中断
【一】、中断底半部
1. 软中断 --->>> 执行在中断上下文 --->>> 会被中断打断,不会被软中断或进程打断 --->>> 可以完成耗时操作
2. tasklet --->>> 执行在中断上下文 --->>> 会被中断打断,不会被软中断或进程打断 --->>> 可以完成耗时操作
3. 工作队列 --->>> 执行在进程上下文 --->>> 会被中断、中断底半部、进程打断 --->>> 可以完成耗时操作,同时
也可以有进程调度相关的函数
中断底半部实现:
[1]. 软中断
init/main.c
--->>> start_kernel
--->>> softirq_init();
/***********************************************************************
*功能:开启(初始化)软中断
*参数:
* @nr 软中断枚举值
* @action 中断底半部处理函数
**********************************************************************/
void open_softirq(int nr, void (*action)(struct softirq_action *))
/************************************************
*功能:调度中断底半部
*参数:
* @nr 软中断枚举值
***********************************************/
void raise_softirq(unsigned int nr)
[2]. tasklet
1. struct tasklet_struct 数据类型
2. 定义、初始化
/*******************************************************************************
*功能:定义并初始化tasklet
*参数:
* @name tasklet结构体变量名
* @func tasklet底半部处理函数指针
* @data 私有数据
******************************************************************************/
#define DECLARE_TASKLET(name, func, data) \
struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(0), func, data }
/**********************************************************************************************
*功能:初始化tasklet
*参数:
* @t tasklet结构体指针
* @func tasklet底半部处理函数指针
* @data 私有数据
*********************************************************************************************/
void tasklet_init(struct tasklet_struct *t,void (*func)(unsigned long), unsigned long data);
3. 调度tasklet底半部
/********************************************************************
*功能:调度tasklet底半部
*参数:
* @t tasklet结构体指针
*返回值:void
*******************************************************************/
void tasklet_schedule(struct tasklet_struct *t)
[3]. 工作队列
<linux/workqueue.h>
1. 工作队列结构体
struct work_struct
2. 定义、初始化
typedef void (*work_func_t)(struct work_struct *work);
/**********************************************************
*功能:定义并初始化workqueue
*参数:
* @n 工作队列变量名
* @f 工作队列底半部处理函数指针
*********************************************************/
#define DECLARE_WORK(n, f) \
struct work_struct n = __WORK_INITIALIZER(n, f)
/**********************************************************
*功能:初始化工作队列
*参数:
* @_work 工作队列结构体指针
* @_func 工作队列底半部处理函数指针
*********************************************************/
INIT_WORK(struct work_struct * _work, _func)
3. 调度工作队列
/****************************************************
*功能:调度工作队列底半部
*参数:
* @work 工作队列结构体指针
***************************************************/
bool schedule_work(struct work_struct *work)
【二】、定时器
<linux/timer.h>
jiffies :计数值
HZ
expires = jiffies + HZ; //定时1s
expires - jiffies + n*HZ; //定时ns
struct timer_list {
unsigned long expires; //定时器的定时时间 --->>> 计数值
void (*function)(unsigned long); //定时器中断处理函数指针
unsigned long data; //私有数据
};
/***************************************************************************
*功能:定义并初始化定时器
*参数:
* @_name 定时器变量名
* @_function 定时器中断处理函数指针
* @_expires 定时时间计数值
* @_data 私有数据
**************************************************************************/
#define DEFINE_TIMER(_name, _function, _expires, _data) \
struct timer_list _name = \
TIMER_INITIALIZER(_function, _expires, _data)
/**********************************
*功能:初始化定时器
*参数:
* @timer 定时器指针
*********************************/
init_timer(struct timer_list * timer)
/* 开启定时器 */
void add_timer(struct timer_list *timer)
/* 关闭定时器 */
int del_timer(struct timer_list *timer)
/************************************************************************
*功能:修改定时器定时时间
*参数:
* @timer struct timer_list *
* @expires 定时时间值
***********************************************************************/
int mod_timer(struct timer_list *timer, unsigned long expires)
【三】、按键消抖
采用定时器延时消抖
延迟机制:
1. 定时器
2. 中断底半部
软中断
tasklet
工作队列
3. 内核延时函数
void ndelay(unsigned long x)
mdelay(n)
4. 内核睡眠函数
void msleep(unsigned int msecs);
unsigned long msleep_interruptible(unsigned int msecs);
void ssleep(unsigned int seconds)
【四】、IIC总线
platform IIC SPI
dev platform_device i2c_client spi_device
drv platform_driver i2c_driver spi_driver
bus bus_type
电气特性:
SDA:数据线
SCK:时钟线
同步 半双工 串行
时序(时序图):
起始信号:时钟线高电平期间,数据线产生负跳变
结束信号:时钟线高电平期间,数据线产生正跳变
协议:
a). signal read:
| start signal | Device address[6:0],W[7] | slave ACK | register address[7:0] | slave ACK | --->>>
SR | Device address[6:0],R[7] | slave ACK | Data[7:0] | MACK | SP |
b). signal write:
| start signal | Device address[6:0],W[7] | slave ACK | register address[7:0] | slave ACK | --->>>
Data[7:0] | slave ACK | SP |
W: write = 0
R: read = 1
SR:repeated start condition
SP:stop condition
IIC驱动:
设备驱动层:
需要驱动工程师完成的,向应用层提供操作的接口(fops),向下层操作硬件
核心层: i2c-core.c
内核提供好的,提供设备驱动和总线驱动注册和注销的方法,还提供设备驱动和总线驱动的匹配方式
总线驱动层:i2c-s3c2410.c
内核提供好的,按照用户传递的数据和操作时序操作硬件
IIC设备驱动:<linux/i2c.h>
struct i2c_driver {
int (*probe)(struct i2c_client *, const struct i2c_device_id *);
int (*remove)(struct i2c_client *);
struct device_driver driver;
const struct i2c_device_id *id_table; //i2c idtable表
};
struct i2c_device_id {
char name[I2C_NAME_SIZE]; //IIC设备名
kernel_ulong_t driver_data; //私有数据
};
/********************************************************
*功能:注册i2c驱动
*参数:
* @driver struct i2c_driver *
*******************************************************/
#define i2c_add_driver(driver) \
i2c_register_driver(THIS_MODULE, driver)
void i2c_del_driver(struct i2c_driver *driver);
i2c设备驱动注册过程:
i2c_register_driver
--->>> driver_register(&driver->driver);
--->>> bus_add_driver(drv);
--->>> driver_attach(drv);
--->>> bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
--->>> __driver_attach
--->>> driver_match_device(drv, dev)
--->>> drv->bus->match ? drv->bus->match(dev, drv) : 1
static int i2c_device_match(struct device *dev, struct device_driver *drv)
{
struct i2c_client *client = i2c_verify_client(dev);
struct i2c_driver *driver;
if (!client)
return 0;
/* 设备数匹配 */
if (of_driver_match_device(dev, drv))
return 1;
/* Then ACPI style match */
if (acpi_driver_match_device(dev, drv))
return 1;
driver = to_i2c_driver(drv);
/* idtable表匹配 */
if (driver->id_table)
return i2c_match_id(driver->id_table, client) != NULL;
return 0;
}
设备数匹配 > idtable表匹配
struct i2c_msg {
__u16 addr; /* slave address */
__u16 flags; /* I2C_M_RD 读数据 0 写数据 */
__u16 len; /* msg length */
__u8 *buf; /* pointer to msg data */
};
/***********************************************************************************
*功能:i2c总线数据传输
*参数:
* @adap struct i2c_adapter *
* @msgs 消息结构体
* @num 消息结构体个数
**********************************************************************************/
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs,int num);
数据收发函数的封装:
[1]. 发送数据
int write_reg(struct i2c_client *client,u8 reg,u8 val)
{
int ret = 0;
u8 buf[] = {reg,val};
struct i2c_msg msgs[] = {
[0] = {
.addr = client->addr,
.flags= 0,
.len = 2,
.buf = buf,
},
};
ret = i2c_transfer(client->adapter,msgs,ARRAY_SIZE(msgs));
if(ret < 0){
return ret;
}
return 0;
}
[2]. 接受数据
int read_reg(struct i2c_client *client,u8 reg)
{
int ret = 0;
u8 val = 0;
u8 buf[] = {reg};
struct i2c_msg msgs[] = {
[0] = {
.addr = client->addr,
.flags= 0,
.len = 1,
.buf = buf,
},
[1] = {
.addr = client->addr,
.flags= I2C_M_RD,
.len = 1,
.buf = &val,
},
};
ret = i2c_transfer(client->adapter,msgs,ARRAY_SIZE(msgs));
if(ret < 0){
return ret;
}
return (unsigned int)val;
}
linux中断的更多相关文章
- linux中断与异常
看了<深入理解linux内核>的中断与异常,简单总结了下,如果有错误,望指正! 一 什么是中断和异常 异常又叫同步中断,是当指令执行时由cpu控制单元产生的,之所以称之为异常,是因为只有在 ...
- 13.linux中断处理程序
linux中断处理程序 一.中断处理流程 在linux内核代码中进入entry-armv.S目录: linux统一的入口:__irq svc. 进入了统一的入口之后,程序跳到irq_handler标号 ...
- Linux中断(interrupt)子系统
Linux中断(interrupt)子系统之一:中断系统基本原理 Linux中断(interrupt)子系统之二:arch相关的硬件封装层 Linux中断(interrupt)子系统之三:中断流控处理 ...
- 驱动: 中断【1】linux中断流程
通常情况下,当一个给定的中断处理程序正在执行时,所有其他的中断都是打开的,所以这些不同中断线上的其他中断都能被处理,但当前中断总是被禁止的. 将中断处理切为两个部分或两半.中断处理程序上半部(top ...
- Linux中断子系统:级联中断控制器驱动
Linux中断子系统 Linux中断子系统是个很大的话题,如下面的思维导图所示,包含硬件.驱动.中断上半部.中断下半部等等.本文着眼于中断控制器(PIC),特别是级联中断控制器驱动部分,对驱动的设计和 ...
- Linux中断管理
CPU和外设之间的交互,或CPU通过轮询机制查询,或外设通过中断机制主动上报. 对大部分外设中断比轮询效率高,但比如网卡驱动采取轮询比中断效率高. 这里重点关注ARM+Linux组合下中断管理,从底层 ...
- Linux中断管理 (1)Linux中断管理机制
目录: <Linux中断管理> <Linux中断管理 (1)Linux中断管理机制> <Linux中断管理 (2)软中断和tasklet> <Linux中断管 ...
- Linux中断管理 (2)软中断和tasklet
目录: <Linux中断管理> <Linux中断管理 (1)Linux中断管理机制> <Linux中断管理 (2)软中断和tasklet> <Linux中断管 ...
- Linux中断管理 (3)workqueue工作队列
目录: <Linux中断管理> <Linux中断管理 (1)Linux中断管理机制> <Linux中断管理 (2)软中断和tasklet> <Linux中断管 ...
- 全志A33 lichee 开发板 Linux中断编程原理说明
开发平台 * 芯灵思SinlinxA33开发板 淘宝店铺: https://sinlinx.taobao.com/ 嵌入式linux 开发板交流 QQ:641395230 本节实验目标实现按键触发中断 ...
随机推荐
- IP基础知识与分配实现
一.IP寻址 1.划分网络ID和主机ID的最初方案是使用地址分类. 2.A类:0.0.0.0-127.255.255.255 B类:128.0.0.0-191.255.255.255 C类:192.0 ...
- 卡在 构建 gradle 项目信息
之所以卡死是因为Android Studio在初次构建的时候,会联网进行gradle目录的更新操作.断网之后就不会去主动更新了. 断网. 打开项目. 把 gradle 改成 使用当地. ======= ...
- 8.5 正睿暑期集训营 Day2
目录 2018.8.5 正睿暑期集训营 Day2 总结 A.占领地区(前缀和) B.配对(组合) C 导数卷积(NTT) 考试代码 T1 T2 T3 2018.8.5 正睿暑期集训营 Day2 时间: ...
- [CEOI2018]Global warming
[CEOI2018]Global warming 题目大意: 给定\(n(n\le2\times10^5)\),你可以将任意\(a_{l\sim r}(1\le l\le r\le n)\)每一个元素 ...
- 如何处理C++构造函数中的错误——兼谈不同语言的错误处理
用C++写代码的时候总是避免不了处理错误,一般来说有两种方式,通过函数的返回值或者抛出异常.C语言的错误处理一律是通过函数的返回值来判断的,一般是返回0.NULL或者-1表示错误,或者直接返回错误代码 ...
- 使用 IntraWeb (27) - 基本控件之 TIWAudio、TIWMPEG、TIWFlash、TIWSilverlight、TIWSilverlightVideo、TIWApplet、TIWQuickTime、TIWActiveX
TIWAudio 所在单元及继承链: IWCompAudio.TIWAudio 主要成员: property AudioFile: TIWFileReference // property Focus ...
- Ubuntu Java7 SDK环境变量配置(转)
1.去甲骨文官网下载java7 sdk http://www.oracle.com/technetwork/java/javase/downloads/index.html 这里笔者下载了最新的jav ...
- Android中pm命令用法(转)
usage: pm [list|path|install|uninstall] pm list packages [-f] pm list permission-groups pm list perm ...
- 打印函数 lodop
Lodop属性和方法详解 例子:LODOP.PRINT_INIT("打印任务名");LODOP.SET_PRINT_COPIES(2);bdhtml=window.document ...
- [Node.js]操作redis
摘要 在实际开发中,免不了要操作mysql,mongodb,redis等数据存储服务器.这里先简单介绍如何操作redis. 一个例子 关于redis服务端的安装这里不再介绍,重点不在这里.感兴趣的可以 ...