Exynos4412裸机开发系列教程--TICK机制
2014-08-22 09:17
447 查看
Tick信号对于任何一款操作系统而言,就类似于人的心脏脉搏,关键性不言而寓,其本质上就是操作系统的激励源,各种调度算法,时间片等概念,包括具体的任务,可以理解为一个巨大的状态机,在激励源的激励下,按部就班执行,一切都是可预测的,只不过复杂度比较高而已。
同样,对于裸机而言,虽没有多任务执行的能力,但是实现了tick机制,可以编写出比较复杂的裸机软件,而且结构清新,可读性强,扩展简单。当然,如果我们真的需要在裸机下实现多种任务的执行,比如在后台下载http网页的时候,同时显示下载进度,并可以接收用户的任何点击操作,比如停止按钮等。我们可以通过协程就可以实现多任务了,协程的本质就是由程序员来控制各种任务的轮换,而不是由操作系统本身按照一定的算法进行调度。当然也可以用传统的MCU编程方法,前后台系统来实现。方法很多,但都异曲同工,条条大路通罗马。
Tick其实很简单,就是一周期性执行的一段代码,不管cpu当前在执行什么任务,时间到了,这段代码必须运行。在这个周期性的代码里,我们可以将一个全局变量加一,用于记录流逝的时间,在具体的应用软件里,我们可以依据此变量实现精确延时。
了解到这里,我想大家已经明白该怎么做了,就是申请一个周期性触发中断的定时器,然后在中断处理函数里,添加相应的代码而已。
Exynos4412裸机开发系列教程中使用了一个100HZ的定时器,也就最大精度为10ms,小于10ms的延时都是不太准确的,当然我们可以提高到1000HZ,这样精度就可以到1ms了。
好了,来看具体的实现。首先,我们需要初始化定时器,设置相应的寄存器,并注册中断处理函数:
void exynos4412_tick_initial(void) { u64_t pclk; if(!clk_get_rate("pclk", &pclk)) return; if(!request_irq("TIMER4", timer_interrupt, 0)) return; /* Using pwm timer 4, prescaler for timer 4 is 16 */ writel(EXYNOS4412_TCFG0, (readl(EXYNOS4412_TCFG0) & ~(0xff<<8)) | (0x0f<<8)); /* Select mux input for pwm timer4 is 1/2 */ writel(EXYNOS4412_TCFG1, (readl(EXYNOS4412_TCFG1) & ~(0xf<<16)) | (0x01<<16)); /* Load value for 10 ms timeout */ writel(EXYNOS4412_TCNTB4, (u32_t)(pclk / (2 * 16 * 100))); /* Auto load, manaual update of timer 4 and stop timer4 */ writel(EXYNOS4412_TCON, (readl(EXYNOS4412_TCON) & ~(0x7<<20)) | (0x06<<20)); /* Enable timer4 interrupt and clear interrupt status bit */ writel(EXYNOS4412_TINT_CSTAT, (readl(EXYNOS4412_TINT_CSTAT) & ~(0x1<<4)) | (0x01<<4) | (0x01<<9)); /* Start timer4 */ writel(EXYNOS4412_TCON, (readl(EXYNOS4412_TCON) & ~(0x7<<20)) | (0x05<<20)); /* initial system tick */ tick_hz = 100; jiffies = 0; }
中断处理函数里,只让一个全局变量jiffies简单的加一,并清中断标志:
static void timer_interrupt(void * data) { /* tick count */ jiffies++; /* Clear interrupt status bit */ writel(EXYNOS4412_TINT_CSTAT, (readl(EXYNOS4412_TINT_CSTAT) & ~(0x1f<<5)) | (0x01<<9)); }当然这里还有些辅助函数及变量,这里一遍贴出
volatile u32_t jiffies = 0; static u32_t tick_hz = 0; u32_t get_system_hz(void) { return tick_hz; } u64_t clock_gettime(void) { if(get_system_hz() > 0) return (u64_t)jiffies * 1000000 / get_system_hz(); return 0; }有了以上的tick机制,我们就可以实现一些比较使用的功能了,比如延时函数,具体实现如下。
static volatile u32_t loops_per_jiffy = 0; void __attribute__ ((noinline)) __delay(volatile u32_t loop) { for(; loop > 0; loop--); } void udelay(u32_t us) { u32_t hz = get_system_hz(); if(hz) __delay(us * loops_per_jiffy / (1000000 / hz)); else __delay(us); } void mdelay(u32_t ms) { u32_t hz = get_system_hz(); if(hz) __delay(ms * loops_per_jiffy / (1000 / hz)); else __delay(ms * 1000); } static void calibrate_delay(void) { u32_t ticks, loopbit; s32_t lps_precision = 8; u32_t hz = get_system_hz(); if(hz > 0) { loops_per_jiffy = (1<<12); while((loops_per_jiffy <<= 1) != 0) { /* wait for "start of" clock tick */ ticks = jiffies; while (ticks == jiffies); /* go ... */ ticks = jiffies; __delay(loops_per_jiffy); ticks = jiffies - ticks; if(ticks) break; } loops_per_jiffy >>= 1; loopbit = loops_per_jiffy; while(lps_precision-- && (loopbit >>= 1)) { loops_per_jiffy |= loopbit; ticks = jiffies; while(ticks == jiffies); ticks = jiffies; __delay(loops_per_jiffy); /* longer than 1 tick */ if(jiffies != ticks) loops_per_jiffy &= ~loopbit; } } else { loops_per_jiffy = 0; } } void exynos4412_tick_delay_initial(void) { calibrate_delay(); }这里有个关键的函数calibrate_delay,这个是用于计算loops_per_jiffy,计算方法为逐次逼近,这个是linux内核里计算bogomips的方法,即每秒种运行多少条指令,是一个相对量,同平台,同环境比较才有意义。
计算出此变量后,我们就可以实现精确延时了,比如mdelay及udelay函数,大家可以自行做实验,看是否准确。
恩,需要源码的朋友,可以直接在本博客寻找链接,或者直接加QQ8192542
相关文章推荐
- Exynos4412裸机开发系列教程--启动流程
- Exynos4412裸机开发系列教程--中断管理
- Exynos4412裸机开发系列教程--源码下载
- Exynos4412裸机开发系列教程--蜂鸣器
- Exynos4412裸机开发系列教程--LED流水灯
- Exynos4412裸机开发系列教程--时钟管理
- S5P4418裸机开发系列教程--源码下载
- cocos2d-x游戏开发系列教程-超级玛丽08-消息机制
- S5P4418裸机开发系列教程--源代码下载
- cocos2d-x游戏开发系列教程-超级玛丽08-消息机制
- 系列教程:DB2 9 应用开发(733)认证指南
- mos开发系列教程九:关于中文化
- ★★★【庖丁解牛:纵向切入Asp.net 3.5控件和组件开发技术系列—(5)事件和数据回发机制】★★★
- Struts1.x系列教程(1):用MyEclipse开发第一个Struts程序(一)
- ★★★【庖丁解牛:纵向切入Asp.net 3.5控件和组件开发技术系列—教程索引】★★★
- ★★★【庖丁解牛:纵向切入Asp.net 3.5控件和组件开发技术系列—教程索引】★★★
- 使用VTEditor软件快速开发网站系列教程一 原理篇
- [导入][Joe 原创]Web Control 开发系列(三) 解析IPostBackEventHandler和WebForm的事件机制
- [Joe 原创]Web Control 开发系列(三) 解析IPostBackEventHandler和WebForm的事件机制
- Struts1.x系列教程(1):用MyEclipse开发第一个Struts程序