【一】、中断底半部

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中断的更多相关文章

  1. linux中断与异常

    看了<深入理解linux内核>的中断与异常,简单总结了下,如果有错误,望指正! 一 什么是中断和异常 异常又叫同步中断,是当指令执行时由cpu控制单元产生的,之所以称之为异常,是因为只有在 ...

  2. 13.linux中断处理程序

    linux中断处理程序 一.中断处理流程 在linux内核代码中进入entry-armv.S目录: linux统一的入口:__irq svc. 进入了统一的入口之后,程序跳到irq_handler标号 ...

  3. Linux中断(interrupt)子系统

    Linux中断(interrupt)子系统之一:中断系统基本原理 Linux中断(interrupt)子系统之二:arch相关的硬件封装层 Linux中断(interrupt)子系统之三:中断流控处理 ...

  4. 驱动: 中断【1】linux中断流程

    通常情况下,当一个给定的中断处理程序正在执行时,所有其他的中断都是打开的,所以这些不同中断线上的其他中断都能被处理,但当前中断总是被禁止的. 将中断处理切为两个部分或两半.中断处理程序上半部(top ...

  5. Linux中断子系统:级联中断控制器驱动

    Linux中断子系统 Linux中断子系统是个很大的话题,如下面的思维导图所示,包含硬件.驱动.中断上半部.中断下半部等等.本文着眼于中断控制器(PIC),特别是级联中断控制器驱动部分,对驱动的设计和 ...

  6. Linux中断管理

    CPU和外设之间的交互,或CPU通过轮询机制查询,或外设通过中断机制主动上报. 对大部分外设中断比轮询效率高,但比如网卡驱动采取轮询比中断效率高. 这里重点关注ARM+Linux组合下中断管理,从底层 ...

  7. Linux中断管理 (1)Linux中断管理机制

    目录: <Linux中断管理> <Linux中断管理 (1)Linux中断管理机制> <Linux中断管理 (2)软中断和tasklet> <Linux中断管 ...

  8. Linux中断管理 (2)软中断和tasklet

    目录: <Linux中断管理> <Linux中断管理 (1)Linux中断管理机制> <Linux中断管理 (2)软中断和tasklet> <Linux中断管 ...

  9. Linux中断管理 (3)workqueue工作队列

    目录: <Linux中断管理> <Linux中断管理 (1)Linux中断管理机制> <Linux中断管理 (2)软中断和tasklet> <Linux中断管 ...

  10. 全志A33 lichee 开发板 Linux中断编程原理说明

    开发平台 * 芯灵思SinlinxA33开发板 淘宝店铺: https://sinlinx.taobao.com/ 嵌入式linux 开发板交流 QQ:641395230 本节实验目标实现按键触发中断 ...

随机推荐

  1. Spring重复扫描导致事务失败的解决方案及深入分析

    问题及日志使用Spring和mybatis,然后配置事务,出现SqlSession was not registered for synchronization because synchroniza ...

  2. 模板 图的遍历 bfs+dfs 图的最短路径 Floyed+Dijkstra

    广搜 bfs //bfs #include<iostream> #include<cstdio> using namespace std; ],top=,end=; ][]; ...

  3. 【优先队列+贪心】BZOJ1826-[JSOI2010]缓存交换

    ……啊开始颓了. [题目大意] 已知当前集合最大容量为m,n个询问.每次询问一个元素,如果集合中没有则需要加入该元素,如果集合已经满了则需要先删去集合中的某些元素再加入.问至少要加入几次元素? [思路 ...

  4. hdu 5792 World is Exploding 树状数组

    World is Exploding 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5792 Description Given a sequence ...

  5. 51Nod 1092 回文字符串(LCS + dp)

    51Nod 1092 数据结构暑假作业上出现的一题,学习了一下相关算法之后,找到了oj测试能AC. 1.回文串是一种中心对称的结构,这道题可以转变为求最长回文子序列长度的题目.(子序列:可以不连续) ...

  6. mongodb用mongoose查库的对象,不能增加属性

    node + koa2 + mongodb 写了一个给前端的接口 如果不是写这个接口,这辈子都发现不了mongodb里这个大坑 mongoose 是个ODM(Object Document Mappe ...

  7. 关于java中的锁(转)

    对于锁一直处于比较模糊的状态,最近一天晚上偶然想看看,就翻了几本书,然后弄明白了一些概念,有一些仍然没明白,例如AQS,先把搞明白的记录一下吧. 什么是线程安全? 当多个线程访问一个对象时,如果不用考 ...

  8. eclipse使用内置tomcat和使用外部tomcat的设置

    近期由于项目中jsp发请求要訪问项目以外的文件.直接訪问写成"c:\xxx\xxx.mp4"来訪问是没有权限的.不能完毕现有要求.经查询后发现能够在tomcat中配置虚拟文件夹将本 ...

  9. php开发之命名规则

    类命名 1.使用大写的字母作为词的切割,其它字母均使用小写字母 2.名字的首字母使用大写字母 3.不要使用下划线"_" 类属性的命名 1.属性的命名应该以'm'为前缀 2.前缀'm ...

  10. godaddy 亚太机房 更换 美国机房 全过程(图)

    其它我就不说了,直接干货... 如果要换机房的话,要先支付134元人民币.在哪里支付,怎么支付我就不说了,自己在后台找... 关键的地方来了:当你支付完134元,你回到步骤3会发现没有美国机房选择,呵 ...