linux中断

Posted 专注it

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 x86_64内核中断初始化

linux内核中断体系结构

linux中断处理函数

linux中断处理函数

linux中断管理