当前位置: 首页 > news >正文

投资建设网站电商发展新方向

投资建设网站,电商发展新方向,微信做爰视频网站,做网站运营要了解哪些嵌入式Linux应用开发-基础知识-第十九章驱动程序基石③ 第十九章 驱动程序基石③19.5 定时器19.5.1 内核函数19.5.2 定时器时间单位19.5.3 使用定时器处理按键抖动19.5.4 现场编程、上机19.5.5 深入研究#xff1a;定时器的内部机制19.5.6 深入研究#xff1a;找到系统滴答 1… 嵌入式Linux应用开发-基础知识-第十九章驱动程序基石③ 第十九章 驱动程序基石③19.5 定时器19.5.1 内核函数19.5.2 定时器时间单位19.5.3 使用定时器处理按键抖动19.5.4 现场编程、上机19.5.5 深入研究定时器的内部机制19.5.6 深入研究找到系统滴答 19.6 中断下半部tasklet19.6.1 内核函数19.6.1.1 定义 tasklet19.6.1.2 使能/禁止 tasklet19.6.1.3 调度 tasklet19.6.1.4 19.6.219.6.3 第十九章 驱动程序基石③ 19.5 定时器 使用 GIT命令载后本节源码位于这个目录下 01_all_series_quickstart\ 05_嵌入式 Linux驱动开发基础知识\source\ 06_gpio_irq\ 07_read_key_irq_poll_fasync_block_timer 19.5.1 内核函数 所谓定时器就是闹钟时间到后你就要做某些事。有 2个要素时间、做事换成程序员的话就是超时时间、函数。 在内核中使用定时器很简单涉及这些函数(参考内核源码 include\linux\timer.h) ① setup_timer(timer, fn, data) 设置定时器主要是初始化 timer_list结构体设置其中的函数、参数。 ② void add_timer(struct timer_list *timer) 向内核添加定时器。timer-expires表示超时时间。 当超时时间到达内核就会调用这个函数timer-function(timer-data)。 ③ int mod_timer(struct timer_list *timer, unsigned long expires): 修改定时器的超时时间 它等同于del_timer(timer); timer-expires expires; add_timer(timer); 但是更加高效。 ④ int del_timer(struct timer_list *timer) 删除定时器。 19.5.2 定时器时间单位 编译内核时可以在内核源码根目录下用“ls -a”看到一个隐藏文件它就是内核配置文件。打开后可以看到如下这项 CONFIG_HZ100 这表示内核每秒中会发生 100次系统滴答中断(tick)这就像人类的心跳一样这是 Linux系统的心跳。每发生一次 tick中断全局变量 jiffies就会累加 1。 CONFIG_HZ100表示每个滴答是 10ms。 定时器的时间就是基于 jiffies的我们修改超时时间时一般使用这 2种方法 ① 在 add_timer之前直接修改 timer.expires jiffies xxx; // xxx表示多少个滴答后超时也就是 xxx*10ms timer.expires jiffies 2*HZ; // HZ等于 CONFIG_HZ2*HZ就相当于 2秒 ② 在 add_timer之后使用 mod_timer修改 mod_timer(timer, jiffies xxx); // xxx表示多少个滴答后超时也就是 xxx*10ms mod_timer(timer, jiffies 2*HZ); // HZ等于 CONFIG_HZ2*HZ就相当于 2秒 19.5.3 使用定时器处理按键抖动 在实际的按键操作中可能会有机械抖动 按下或松开一个按键它的 GPIO电平会反复变化最后才稳定。一般是几十毫秒才会稳定。 如果不处理抖动的话用户只操作一次按键中断程序可能会上报多个数据。 怎么处理 ① 在按键中断程序中可以循环判断几十亳秒发现电平稳定之后再上报 ② 使用定时器 显然第 1种方法太耗时违背“中断要尽快处理”的原则你的系统会很卡。 怎么使用定时器看下图 核心在于在 GPIO中断中并不立刻记录按键值而是修改定时器超时时间10ms后再处理。 如果 10ms内又发生了 GPIO中断那就认为是抖动这时再次修改超时时间为 10ms。 只有 10ms之内再无 GPIO中断发生那么定时器的函数才会被调用。 在定时器函数中记录按键值。 19.5.4 现场编程、上机 19.5.5 深入研究定时器的内部机制 初学者会用定时器就行本节不用看。 怎么实现定时器逻辑上很简单每发生一次硬件中断时硬件中断处理完后就会看看有没有软件中断要处理。 定时器就是通过软件中断来实现的它属于 TIMER_SOFTIRQ软中断。 对于 TIMER_SOFTIRQ软中断初始化代码如下 void __init init_timers(void) { init_timer_cpus(); init_timer_stats(); open_softirq(TIMER_SOFTIRQ, run_timer_softirq); } 当发生硬件中断时硬件中断处理完后内核会调用软件中断的处理函数。对于 TIMER_SOFTIRQ会调用 run_timer_softirq它的函数如下 run_timer_softirq __run_timers(base); while (time_after_eq(jiffies, base-clk)) { …… expire_timers(base, heads levels); fn timer-function; data timer-data; call_timer_fn(timer, fn, data); fn(data); 简单地说add_timer函数会把 timer放入内核里某个链表 在 TIMER_SOFTIRQ的处理函数中会从链表中把这些超时的 timer取出来执行其中的函数。 怎么判断是否超时jiffies大于或等于 timer-expires时timer就超时。 内核中有很多 timer如果高效地找到超时的 timer这是比较复杂的 我们以后如果要深入讲解 timer的话会用视频来讲解。 19.5.6 深入研究找到系统滴答 这只是一些笔记初学者不用看。 在开发板执行以下命令可以看到 CPU0下有一个数值变化特别快它就是滴答中断 # cat /proc/interrupts CPU0 16: 2532 GPC 55 Level i.MX Timer Tick 19: 22 GPC 33 Level 2010000.ecspi 20: 384 GPC 26 Level 2020000.serial 21: 0 GPC 98 Level sai 以 xxxxxx_IMX6ULL为做滴答中断名字就是“i.MX Timer Tick”。 在 Linux内核源码目录下执行以下命令 $ grep i.MX Timer Tick * -nr drivers/clocksource/timer-imx-gpt.c:319: act-name i.MX Timer Tick; 打开 timer-imx-gpt.c 319行左右可得如下源码 act-name i.MX Timer Tick; act-flags IRQF_TIMER | IRQF_IRQPOLL; act-handler mxc_timer_interrupt; act-dev_id ced; return setup_irq(imxtm-irq, act); mxc_timer_interrupt应该就是滴答中断的处理函数代码如下 static irqreturn_t mxc_timer_interrupt(int irq, void *dev_id) { struct clock_event_device *ced dev_id; struct imx_timer *imxtm to_imx_timer(ced); uint32_t tstat; tstat readl_relaxed(imxtm-base imxtm-gpt-reg_tstat); imxtm-gpt-gpt_irq_acknowledge(imxtm); ced-event_handler(ced); return IRQ_HANDLED; }在上述代码中没看到对 jiffies的累加操作啊应该是在 ced-event_handler(ced)中进行。 ced-event_handler(ced)是哪一个函数不太好找我使用QEMU来调试内核在mxc_timer_interrupt中打断点跟踪代码(以后的课程会讲怎么用 QEMU调试内核)发现它对应 tick_handle_periodic。 tick_handle_periodic位于 kernel\time\tick-common.c中它里面的调用关系如下 tick_handle_periodic tick_periodic(cpu); do_timer(1); jiffies_64 ticks; // jiffies就是 jiffies_64 你为何说 jiffies就是 jiffies_64在 arch\arm\kernel\vmlinux.lds.S有如下代码 #ifndef __ARMEB__ jiffies jiffies_64; #else jiffies jiffies_64 4; #endif 上述代码说明了对于大字节序的 CPUjiffies指向 jiffies_64的高 4字节对于小字节序的 CPUjiffies指向 jiffies_64的低 4字节。 对 jiffies_64的累加操作就是对 jiffies的累加操作。 19.6 中断下半部tasklet 使用 GIT命令载后本节源码位于这个目录下 01_all_series_quickstart\ 05_嵌入式 Linux驱动开发基础知识\source\ 06_gpio_irq\ 08_read_key_irq_poll_fasync_block_timer_tasklet 在前面我们介绍过中断上半部、下半部。中断的处理有几个原则 ① 不能嵌套 ② 越快越好。 在处理当前中断时即使发生了其他中断其他中断也不会得到处理所以中断的处理要越快越好。但是某些中断要做的事情稍微耗时这时可以把中断拆分为上半部、下半部。 在上半部处理紧急的事情在上半部的处理过程中中断是被禁止的 在下半部处理耗时的事情在下半部的处理过程中中断是使能的。 中断上半部、下半部的关系机制请回顾第 18.2.5节。 19.6.1 内核函数 19.6.1.1 定义 tasklet 中断下半部使用结构体 tasklet_struct来表示它在内核源码 include\linux\interrupt.h中定义 struct tasklet_struct { struct tasklet_struct *next; unsigned long state; atomic_t count; void (*func)(unsigned long); unsigned long data; }; 其中的 state有 2位 ① bit0表示 TASKLET_STATE_SCHED 等于 1时表示已经执行了 tasklet_schedule把该 tasklet放入队列了tasklet_schedule会判断该位如果已经等于 1那么它就不会再次把 tasklet放入队列。 ② bit1表示 TASKLET_STATE_RUN 等于 1时表示正在运行 tasklet中的 func函数函数执行完后内核会把该位清 0。 其中的 count表示该 tasklet是否使能等于 0表示使能了非 0表示被禁止了。对于 count非 0的tasklet里面的 func函数不会被执行。 使用中断下半部之前要先实现一个 tasklet_struct结构体这可以用这 2个宏来定义结构体 #define DECLARE_TASKLET(name, func, data) \ struct tasklet_struct name { NULL, 0, ATOMIC_INIT(0), func, data } #define DECLARE_TASKLET_DISABLED(name, func, data) \ struct tasklet_struct name { NULL, 0, ATOMIC_INIT(1), func, data } 使用 DECLARE_TASKLET定义的 tasklet结构体它是使能的 使用 DECLARE_TASKLET_DISABLED定义的 tasklet结构体它是禁止的使用之前要先调用tasklet_enable使能它。 也可以使用函数来初始化 tasklet结构体 extern void tasklet_init(struct tasklet_struct *t, void (*func)(unsigned long), unsigned long data); 19.6.1.2 使能/禁止 tasklet static inline void tasklet_enable(struct tasklet_struct *t); static inline void tasklet_disable(struct tasklet_struct *t); tasklet_enable把 count增加 1tasklet_disable把 count减 1。 19.6.1.3 调度 tasklet static inline void tasklet_schedule(struct tasklet_struct *t); 把 tasklet放入链表并且设置它的 TASKLET_STATE_SCHED状态为 1。 19.6.1.4 kill tasklet extern void tasklet_kill(struct tasklet_struct *t); 如果一个 tasklet未被调度tasklet_kill会把它的 TASKLET_STATE_SCHED状态清 0 如果一个 tasklet已被调度tasklet_kill会等待它执行完华再把它的 TASKLET_STATE_SCHED状态清 0。 通常在卸载驱动程序时调用 tasklet_kill。 19.6.2 tasklet使用方法 先定义 tasklet需要使用时调用 tasklet_schedule驱动卸载前调用 tasklet_kill。 tasklet_schedule只是把 tasklet放入内核队列它的 func函数会在软件中断的执行过程中被调用。 19.6.3 tasklet内部机制 作为初学者可以不看本节。 tasklet属于 TASKLET_SOFTIRQ软件中断入口函数为 tasklet_action这在内核 kernel\softirq.c中设置 当驱动程序调用 tasklet_schedule时会设置 tasklet的 state为 TASKLET_STATE_SCHED并把它放入某个链表 当发生硬件中断时内核处理完硬件中断后会处理软件中断。对于 TASKLET_SOFTIRQ软件中断会调用 tasklet_action函数。 执行过程还是挺简单的从队列中找到 tasklet进行状态判断后执行 func函数从队列中删除 tasklet。 从这里可以看出 ① tasklet_schedule调度 tasklet时其中的函数并不会立刻执行而只是把 tasklet放入队列 ② 调用一次 tasklet_schedule只会导致 tasklnet的函数被执行一次 ③ 如果 tasklet的函数尚未执行多次调用 tasklet_schedule也是无效的只会放入队列一次。 tasklet_action函数解析如下
http://www.zqtcl.cn/news/762258/

相关文章:

  • 360建站系统徐州建设银行网上银行个人网站
  • 网站域名在哪里备案石家庄站规模
  • 重庆南川网站制作公司电话工会网站群建设
  • 深圳高端建设网站忘了网站链接怎么做
  • 郑州做网站报价wordpress中文4.8
  • 网站维护费用一年多少跨境电商平台网站建设广州
  • 辽宁网站制作公司网店装修流程
  • html5可以做交互网站吗打开网站说建设中是什么问题?
  • 彩票网站开发制作需要什么wordpress 在线预览
  • 外贸平台app衡水seo排名
  • 怎样做网站表白墙东莞商城网站推广建设
  • 郑州郑州网站建设河南做网站公司哪家好爱站长尾词挖掘工具
  • dede网站地图文章变量网站qq 微信分享怎么做
  • 越南做网站网站建设以及运营方面
  • 广西建网站哪家好网站关闭与域名备案
  • 网站开发版本号婚庆网站建设策划案费用预算
  • 厦门建设网站制作中山市哪家公司做网站
  • 网站路径wordpress制作电商网站
  • 江西网站开发哪家专业装饰设计公司网站
  • 企业网站策划实训Wordpress 主题简化
  • 做网站点击挣钱不兰州工程建设信息网站
  • 网站说服力 营销...免费看片网站
  • 深圳招聘网站大全制作网站软件下载
  • 网站建设说明哈尔滨网站建设渠道
  • 一 网站建设管理基本情况设计类的网站
  • wordpress产品编辑如何优化wordpress
  • 网站后台更新缓存失败网站平台规划方案
  • 网站开发需求分析主要内容saas建站系统是怎么实现的
  • 做qq头像的网站有哪些wordpress怎么部署到虚拟linux服务器
  • 征求网站建设企业网站建设word