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 本节实验目标实现按键触发中断 ...
随机推荐
- Android `AsyncTask`简要分析
AsyncTask简要分析 经典异步任务:AsyncTask,使用场景有:批量下载,批量拷贝等.官方文档就直接给出了一个批量下载的示例. private class DownloadFilesTask ...
- 学习ABP遇到的问题汇总
1,在abp官网下载的模板(asp.net+ef)写Application层的时候需要使用AutoMapper.结果ObjectMapper一直为null 解决:需要在当前项目的Module依赖Abp ...
- Android Intent Service
Android Intent Service 学习自 Android 官方文档 https://blog.csdn.net/iromkoear/article/details/63252665 Ove ...
- InvokeRepeating重复定时器
JS // Starting in 2 seconds.// a projectile will be launched every 0.3 secondsvar projectile : Rigid ...
- Codeforces.566F.Clique in the Divisibility Graph(DP)
题目链接 \(Description\) 给定集合\(S=\{a_1,a_2,\ldots,a_n\}\),集合中两点之间有边当且仅当\(a_i|a_j\)或\(a_j|a_i\). 求\(S\)最大 ...
- Codeforces Round #371 (Div. 2) B. Filya and Homework 水题
B. Filya and Homework 题目连接: http://codeforces.com/contest/714/problem/B Description Today, hedgehog ...
- Codeforces Round #281 (Div. 2) A. Vasya and Football 模拟
A. Vasya and Football 题目连接: http://codeforces.com/contest/493/problem/A Description Vasya has starte ...
- Gym 100646 You’ll be Working on the Railroad dfs
You'll be Working on the Railroad 题目连接: http://codeforces.com/gym/100646/attachments Description Con ...
- 深入理解webpack
什么是Webpack WebPack可以看做是模块打包机:它做的事情是,分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并 ...
- FireDAC 下的 Sqlite [1] - 前言
很长时间没静下心来写博客了, 现在回来, 是 Delphi 不断地进步让我感动.振奋. Delphi XE5 并入了 FireDAC, 第一印象非常好, 恐怕 dbExpress 等等都要靠边站了. ...