OSAL事件触发机制----定时器触发
OSAL系统进入主循环后,轮询任务事件标志tasksEvents[],发现存在任务及其事件则进入tasksArr[]调用相对应的回调函数进行任务事件的处理,轮询任务前,向
1、由定时器超时溢出,设置任务及事件;
2、由外部信号(如按键)触发消息传递机制,设置任务及事件;
3、可调用osal_set_event()函数进行设定。
1 /********************************************************************* 2 3 * @fn osal_set_event 4 5 * @brief 6 7 * This function is called to set the event flags for a task. The 8 9 * event passed in is OR'd into the task's event variable. 10 11 * @param uint8 task_id - receiving tasks ID 12 13 * @param uint8 event_flag - what event to set 14 15 * @return SUCCESS, INVALID_TASK 16 17 */ 18 19 uint8 osal_set_event( uint8 task_id, uint16 event_flag ) 20 21 { 22 23 if ( task_id < tasksCnt ) 24 25 { 26 27 halIntState_t intState; 28 29 HAL_ENTER_CRITICAL_SECTION(intState); // Hold off interrupts 30 31 tasksEvents[task_id] |= event_flag; // Stuff the event bit(s) 32 33 HAL_EXIT_CRITICAL_SECTION(intState); // Release interrupts 34 35 return ( SUCCESS ); 36 37 } 38 39 else 40 41 { 42 43 return ( INVALID_TASK ); 44 45 } 46 47 }
OSAL中,由osal_set_event()向主循环注入事件等待处理,
tasksEvents[task_id] |= event_flag;
task_id为任务ID,event_flag为该任务待处理事件。
不论是定时器还是消息传递,最终注入事件都是调用osal_set_event()完成。
1、 定时器触发事件流程
调用osal_start_timerEx()函数创建定时任务,该函数中调用osalAddTimer()接口,添加定时器函数中,遍历定时器链表,若存在该任务ID同事件的定时器,更新定时器超时时间,若不存在,则创建一个新定时器,将新创建的定时器添加到定时器链表中并返回定时器指针,创建失败返回NULL。
OSAL调用osalTimeUpdate()函数进行定时器遍历,
1 /********************************************************************* 2 3 * @fn osalTimeUpdate 4 5 * 6 7 * @brief Uses the free running rollover count of the MAC backoff timer; 8 9 * this timer runs freely with a constant 320 usec interval. The 10 11 * count of 320-usec ticks is converted to msecs and used to update 12 13 * the OSAL clock and Timers by invoking osalClockUpdate() and 14 15 * osalTimerUpdate(). This function is intended to be invoked 16 17 * from the background, not interrupt level. 18 19 * 20 21 * @param None. 22 23 * 24 25 * @return None. 26 27 */ 28 29 void osalTimeUpdate( void ) 30 31 { 32 33 uint16 tmp; 34 35 uint16 ticks625us; 36 37 uint16 elapsedMSec = 0; 38 39 40 41 // Get the free-running count of 625us timer ticks 42 43 tmp = ll_McuPrecisionCount(); 44 45 46 47 if ( tmp != previousLLTimerTick ) 48 49 { 50 51 // Calculate the elapsed ticks of the free-running timer. 52 53 ticks625us = tmp - previousLLTimerTick; 54 55 56 57 // Store the LL Timer tick count for the next time through this function. 58 59 previousLLTimerTick = tmp; 60 61 62 63 /* It is necessary to loop to convert the usecs to msecs in increments so as 64 65 * not to overflow the 16-bit variables. 66 67 */ 68 69 while ( ticks625us > MAXCALCTICKS ) 70 71 { 72 73 ticks625us -= MAXCALCTICKS; 74 75 elapsedMSec += MAXCALCTICKS * 5 / 8; 76 77 remUsTicks += MAXCALCTICKS * 5 % 8; 78 79 } 80 81 82 83 // update converted number with remaining ticks from loop and the 84 85 // accumulated remainder from loop 86 87 tmp = (ticks625us * 5) + remUsTicks; 88 89 90 91 // Convert the 625 us ticks into milliseconds and a remainder 92 93 elapsedMSec += tmp / 8; 94 95 remUsTicks = tmp % 8; 96 97 98 99 // Update OSAL Clock and Timers 100 101 if ( elapsedMSec ) 102 103 { 104 105 osalClockUpdate( elapsedMSec ); 106 107 osalTimerUpdate( elapsedMSec ); 108 109 } 110 111 } 112 113 }
该函数在主循环中调用,使用一个链路层的定时器,根据TI网站上工作人员的回答,使用timer2计时,时间间隔为625us,而不是注释中的320us,该函数中获取到ticks之后,转换为毫秒时间并调用osalClockUpdate()更新系统时间,单位 S;调用osalTimerUpdate()遍历定时器链表。
1 /********************************************************************* 2 3 * @fn osalTimerUpdate 4 5 * 6 7 * @brief Update the timer structures for a timer tick. 8 9 * 10 11 * @param none 12 13 * 14 15 * @return none 16 17 *********************************************************************/ 18 19 void osalTimerUpdate( uint32 updateTime ) 20 21 { 22 23 halIntState_t intState; 24 25 osalTimerRec_t *srchTimer; 26 27 osalTimerRec_t *prevTimer; 28 29 30 31 osalTime_t timeUnion; 32 33 timeUnion.time32 = updateTime; 34 35 36 37 HAL_ENTER_CRITICAL_SECTION( intState ); // Hold off interrupts. 38 39 // Update the system time 40 41 osal_systemClock += updateTime; 42 43 HAL_EXIT_CRITICAL_SECTION( intState ); // Re-enable interrupts. 44 45 46 47 // Look for open timer slot 48 49 if ( timerHead != NULL ) 50 51 { 52 53 // Add it to the end of the timer list 54 55 srchTimer = timerHead; 56 57 prevTimer = (void *)NULL; 58 59 60 61 // Look for open timer slot 62 63 while ( srchTimer ) 64 65 { 66 67 osalTimerRec_t *freeTimer = NULL; 68 69 70 71 HAL_ENTER_CRITICAL_SECTION( intState ); // Hold off interrupts. 72 73 74 75 // To minimize time in this critical section, avoid 32-bit math 76 77 if ((timeUnion.time16[1] == 0) && (timeUnion.time8[1] == 0)) 78 79 { 80 81 // If upper 24 bits are zero, check lower 8 bits for roll over 82 83 if (srchTimer->timeout.time8[0] >= timeUnion.time8[0]) 84 85 { 86 87 // 8-bit math 88 89 srchTimer->timeout.time8[0] -= timeUnion.time8[0]; 90 91 } 92 93 else 94 95 { 96 97 // 32-bit math 98 99 if (srchTimer->timeout.time32 > timeUnion.time32) 100 101 { 102 103 srchTimer->timeout.time32 -= timeUnion.time32; 104 105 } 106 107 else 108 109 { 110 111 srchTimer->timeout.time32 = 0; 112 113 } 114 115 } 116 117 } 118 119 else 120 121 { 122 123 // 32-bit math 124 125 if (srchTimer->timeout.time32 > timeUnion.time32) 126 127 { 128 129 srchTimer->timeout.time32 -= timeUnion.time32; 130 131 } 132 133 else 134 135 { 136 137 srchTimer->timeout.time32 = 0; 138 139 } 140 141 } 142 143 144 145 // Check for reloading 146 147 if ( (srchTimer->timeout.time16[0] == 0) && (srchTimer->timeout.time16[1] == 0) && 148 149 (srchTimer->reloadTimeout) && (srchTimer->event_flag) ) 150 151 { 152 153 // Notify the task of a timeout 154 155 osal_set_event( srchTimer->task_id, srchTimer->event_flag ); 156 157 158 159 // Reload the timer timeout value 160 161 srchTimer->timeout.time32 = srchTimer->reloadTimeout; 162 163 } 164 165 166 167 // When timeout or delete (event_flag == 0) 168 169 if ( ((srchTimer->timeout.time16[0] == 0) && (srchTimer->timeout.time16[1] == 0)) || 170 171 (srchTimer->event_flag == 0) ) 172 173 { 174 175 // Take out of list 176 177 if ( prevTimer == NULL ) 178 179 { 180 181 timerHead = srchTimer->next; 182 183 } 184 185 else 186 187 { 188 189 prevTimer->next = srchTimer->next; 190 191 } 192 193 194 195 // Setup to free memory 196 197 freeTimer = srchTimer; 198 199 200 201 // Next 202 203 srchTimer = srchTimer->next; 204 205 } 206 207 else 208 209 { 210 211 // Get next 212 213 prevTimer = srchTimer; 214 215 srchTimer = srchTimer->next; 216 217 } 218 219 220 221 HAL_EXIT_CRITICAL_SECTION( intState ); // Re-enable interrupts. 222 223 224 225 if ( freeTimer ) 226 227 { 228 229 if ( (freeTimer->timeout.time16[0] == 0) && (freeTimer->timeout.time16[1] == 0) ) 230 231 { 232 233 osal_set_event( freeTimer->task_id, freeTimer->event_flag ); 234 235 } 236 237 osal_mem_free( freeTimer ); 238 239 } 240 241 } 242 243 } 244 245 }
该函数中获取到系统流逝时间后,存储在一个长度为32位的联合体中timeUnion,并更新系统时钟,单位ms,遍历定时器链表。
a、为了减少时间消耗,没有直接使用32位进行比较,其实本质上还是定时器超时时间减去系统流逝时间,若超时时间小于系统流逝时间,则直接置0;
b、判断是否为循环定时器超时时间为0,是,则调用osal_set_event()向主循环注入任务事件,并reloadTimeout;
c、判断是否是普通定时器超时,是,则调用osal_set_event()向主循环注入任务事件,并删除定时器释放内存。