• 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;
                    }
               

  • 相关阅读:
    Python2和3版本对str和bytes类型的处理
    使用Fiddle对夜神模拟器进行抓包的设置
    WebSocket 实现链接 群聊(low low low 版本)
    WebSocket 实现链接 发送消息
    Linux文件操作命令
    Linux命令格式
    FastJson
    JSON语法规则
    Mybatis resultMap支持继承
    Mybatis在xml文件中处理大于号小于号的方法
  • 原文地址:https://www.cnblogs.com/wanghuaijun/p/9873154.html
Copyright © 2020-2023  润新知