RTOS的精确延时功能扩展
大家都知道,OS有一个系统时基,这个时基大多取值为100,200,500,1000,一般都不会大于1000。取1000的时候,意味着每1毫秒就产生一次时基中断,OS时基函数也就被执行一次,如果这个时基中断产生的太频繁,对系统性能是有很大影响的。假设我们的系统时基选择100,那就是延时精度为10毫秒。这种精度很让人烦恼不是吗?
那么怎样提供一个精确的RTOS延时而又不增加系统负担呢?
在延时段死循环执行指定数量的指令?不是!因为这是最浪费CPU资源的做法!
把RTOS时基增加?也不是!因为每个时基都会耗费CPU资源,增加时基就意味着增加CPU资源耗费!
这里,我在LPC17xx上使用RIT模块实现了一个精确延时模块,目前精度为10微秒,系统是ucos-ii,供大家参考。
原理很简单,就是维护一个链表结构。有几个线程正在延时,就有几个链表节点,链表节点不占用堆内存,用的是线程局部堆栈。
延时计数硬件不用每10微秒产生中断,中断次数就等于链表的节点数而已!如果不用RIT硬件模块,其他硬件定时器一样可以实现的。
hp_timer.h内容:
1: #ifndef __HP_TIMER_H__
2: #define __HP_TIMER_H__
3: ////////////////////////////////////////////////////////////////////////////////
4: #include "target.h"
5: #include "fport.h"
6: #include "frame.h"
7:
8: typedef struct {
9: u32_t ticks;
10: OS_EVENT *ev;
11: void *next;
12: } hp_tmr_t;
13:
14: void hp_timer_init(void);
15: void hp_delay(u32_t ticks);
16: void hp_delay_ex(hp_tmr_t *tmr);
17:
18: ////////////////////////////////////////////////////////////////////////////////
19: #endif /* __HP_TIMER_H__ */
20:
hp_timer.c内容:
1: #include "hp_timer.h"
2:
3: static u32_t hpTickBase;
4: static hp_tmr_t *hpList = NULL;
5: ////////////////////////////////////////////////////////////////////////////////
6: //| |
7: //| 函数名称 |: hp_timer_init
8: //| 功能描述 |:
9: //| |:
10: //| 参数列表 |:
11: //| |:
12: //| 返 回 |:
13: //| |:
14: //| 备注信息 |: 10uS延时单位。
15: //| |:
16: ////////////////////////////////////////////////////////////////////////////////
17: void hp_timer_init(void)
18: {
19: u32_t utmp;
20:
21: target_enable_power(PCONP_RIT);
22: utmp = target_get_apbclk(PCLK_RIT);
23: utmp /= 100000u; /* 每10uS的APB时钟计数。*/
24: hpTickBase = utmp;
25:
26: NVIC_DisableIRQ(RIT_IRQn);
27: LPC_RIT->RIMASK = 0u;
28: // 清除中断标志并停止计数器。
29: LPC_RIT->RICTRL = ((1<<2)|(1<<0));
30: NVIC_EnableIRQ(RIT_IRQn);
31: }
32:
33: ////////////////////////////////////////////////////////////////////////////////
34: //| |
35: //| 函数名称 |: RIT_IRQHandler
36: //| 功能描述 |:
37: //| |:
38: //| 参数列表 |:
39: //| |:
40: //| 返 回 |:
41: //| |:
42: //| 备注信息 |:
43: //| |:
44: ////////////////////////////////////////////////////////////////////////////////
45: void RIT_IRQHandler(void)
46: {
47: DECL_CPU_SR;
48: u32_t tmval;
49: hp_tmr_t *p;
50:
51: // 清除中断标志并停止计数器。
52: LPC_RIT->RICTRL = ((1<<2)|(1<<0));
53: OS_ENTER_CRITICAL();
54: OSIntNesting++;
55: p = hpList;
56: while(p && (p->ticks == 0)){
57: if(p->ev){
58: OSSemPost(p->ev);
59: }
60: p = (hp_tmr_t *)p->next;
61: }
62: hpList = p;
63: if(p){
64: tmval = p->ticks*hpTickBase;
65: tmval += LPC_RIT->RICOUNTER;
66: LPC_RIT->RICOMPVAL = tmval;
67: p->ticks = 0;
68: LPC_RIT->RICTRL = ((1<<2)|(1<<3));
69: }
70: OS_EXIT_CRITICAL();
71:
72: OSIntExit();
73: }
74:
75: ////////////////////////////////////////////////////////////////////////////////
76: //| |
77: //| 函数名称 |: __internal_delay
78: //| 功能描述 |:
79: //| |:
80: //| 参数列表 |:
81: //| |:
82: //| 返 回 |:
83: //| |:
84: //| 备注信息 |: 10uS延时单位。
85: //| |:
86: ////////////////////////////////////////////////////////////////////////////////
87: static void __internal_delay(hp_tmr_t *tmr)
88: {
89: hp_tmr_t *p;
90: DECL_CPU_SR;
91: INT8U err;
92: u32_t cnt;
93:
94: tmr->next = 0;
95: OS_ENTER_CRITICAL();
96: // 清除中断标志并停止计数器。
97: LPC_RIT->RICTRL = ((1<<2)|(1<<0));
98: p = hpList;
99: if(p){
100: cnt = LPC_RIT->RICOMPVAL;
101: cnt -= LPC_RIT->RICOUNTER;
102: cnt /= hpTickBase;
103: LPC_RIT->RICOMPVAL -= cnt*hpTickBase;
104: p->ticks += cnt;
105: if(p->ticks > tmr->ticks){
106: p->ticks -= tmr->ticks;
107: tmr->next = p;
108: hpList = tmr;
109: }else{
110: while(1){
111: tmr->ticks -= p->ticks;
112: if(p->next == NULL){
113: p->next = tmr;
114: break;
115: }
116: if(((hp_tmr_t *)p->next)->ticks >= tmr->ticks){
117: ((hp_tmr_t *)p->next)->ticks -= tmr->ticks;
118: tmr->next = p->next;
119: p->next = tmr;
120: break;
121: }
122: p = p->next;
123: }
124: }
125: cnt = hpList->ticks;
126: LPC_RIT->RICOMPVAL += cnt*hpTickBase;
127: hpList->ticks = 0;
128: }else{
129: // 列表为空。
130: hpList = tmr;
131: cnt = tmr->ticks*hpTickBase;
132: cnt += LPC_RIT->RICOUNTER;
133: LPC_RIT->RICOMPVAL = cnt;
134: tmr->ticks = 0;
135: }
136: // 启动计数器。
137: LPC_RIT->RICTRL = ((1<<2)|(1<<3));
138: OS_EXIT_CRITICAL();
139:
140: OSSemPend(tmr->ev, 0, &err);
141: }
142:
143: ////////////////////////////////////////////////////////////////////////////////
144: //| |
145: //| 函数名称 |: hp_delay
146: //| 功能描述 |:
147: //| |:
148: //| 参数列表 |: ticks 延时时间,单位是10uS。
149: //| |:
150: //| 返 回 |:
151: //| |:
152: //| 备注信息 |: 注意:100MHZ主频时,调用该函数会有10uS以上的代码执行开销,因此:
153: //| |: 当ticks参数为1时,当函数返回时就已经过去20uS时间了。
154: ////////////////////////////////////////////////////////////////////////////////
155: void hp_delay(u32_t ticks)
156: {
157: OS_EVENT *ev;
158: INT8U err;
159:
160: if(ticks){
161: ev = OSSemCreate(0);
162: if(ev){
163: hp_tmr_t tmr;
164: tmr.ticks = ticks;
165: tmr.ev = ev;
166: __internal_delay(&tmr);
167: OSSemDel(ev, OS_DEL_ALWAYS, &err);
168: }
169: }
170: }
171:
172: ////////////////////////////////////////////////////////////////////////////////
173: //| |
174: //| 函数名称 |: hp_delay_ex
175: //| 功能描述 |:
176: //| |:
177: //| 参数列表 |:
178: //| |:
179: //| 返 回 |:
180: //| |:
181: //| 备注信息 |: 10uS延时单位。
182: //| |:
183: ////////////////////////////////////////////////////////////////////////////////
184: void hp_delay_ex(hp_tmr_t *tmr)
185: {
186: if(tmr && tmr->ev && tmr->ticks){
187: __internal_delay(tmr);
188: }
189: }
190: