| LPCOpen Platform v1.03 LPCOpen Platform for NXP LPC Microcontrollers

- Main Page
- Modules
- Data Structures
- Files
- Related Pages

- File List
- Globals

All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
os_time.c
Go to the documentation of this file.
1 /*
2 ************************************************************************************************************************
3 * uC/OS-III
4 * The Real-Time Kernel
5 *
6 * (c) Copyright 2009-2012; Micrium, Inc.; Weston, FL
7 * All rights reserved. Protected by international copyright laws.
8 *
9 * TIME MANAGEMENT
10 *
11 * File : OS_TIME.C
12 * By : JJL
13 * Version : V3.03.00
14 *
15 * LICENSING TERMS:
16 * ---------------
17 * uC/OS-III is provided in source form for FREE short-term evaluation, for educational use or
18 * for peaceful research. If you plan or intend to use uC/OS-III in a commercial application/
19 * product then, you need to contact Micrium to properly license uC/OS-III for its use in your
20 * application/product. We provide ALL the source code for your convenience and to help you
21 * experience uC/OS-III. The fact that the source is provided does NOT mean that you can use
22 * it commercially without paying a licensing fee.
23 *
24 * Knowledge of the source code may NOT be used to develop a similar product.
25 *
26 * Please help us continue to provide the embedded community with the finest software available.
27 * Your honesty is greatly appreciated.
28 *
29 * You can contact us at www.micrium.com, or by phone at +1 (954) 217-2036.
30 ************************************************************************************************************************
31 */
32
33 #define MICRIUM_SOURCE
34 #include <os.h>
35
36 #ifdef VSC_INCLUDE_SOURCE_FILE_NAMES
37 const CPU_CHAR *os_time__c = "$Id: $";
38 #endif
39
40 /*
41 ************************************************************************************************************************
42 * DELAY TASK 'n' TICKS
43 *
44 * Description: This function is called to delay execution of the currently running task until the specified number of
45 * system ticks expires. This, of course, directly equates to delaying the current task for some time to
46 * expire. No delay will result if the specified delay is 0. If the specified delay is greater than 0
47 * then, a context switch will result.
48 *
49 * Arguments : dly is a value in 'clock ticks' that the task will either delay for or, the target match value
50 * of the tick counter (OSTickCtr). Note that specifying 0 means the task is not to delay.
51 *
52 * depending on the option argument, the task will wake up when OSTickCtr reaches:
53 *
54 * OS_OPT_TIME_DLY : OSTickCtr + dly
55 * OS_OPT_TIME_TIMEOUT : OSTickCtr + dly
56 * OS_OPT_TIME_MATCH : dly
57 * OS_OPT_TIME_PERIODIC : OSTCBCurPtr->TickCtrPrev + dly
58 *
59 * opt specifies whether 'dly' represents absolute or relative time; default option marked with *** :
60 *
61 * *** OS_OPT_TIME_DLY specifies a relative time from the current value of OSTickCtr.
62 * OS_OPT_TIME_TIMEOUT same as OS_OPT_TIME_DLY.
63 * OS_OPT_TIME_MATCH indicates that 'dly' specifies the absolute value that OSTickCtr
64 * must reach before the task will be resumed.
65 * OS_OPT_TIME_PERIODIC indicates that 'dly' specifies the periodic value that OSTickCtr
66 * must reach before the task will be resumed.
67 *
68 * p_err is a pointer to a variable that will contain an error code from this call.
69 *
70 * OS_ERR_NONE the call was successful and the delay occurred.
71 * OS_ERR_OPT_INVALID if you specified an invalid option for this function.
72 * OS_ERR_SCHED_LOCKED can't delay when the scheduler is locked.
73 * OS_ERR_TIME_DLY_ISR if you called this function from an ISR.
74 * OS_ERR_TIME_ZERO_DLY if you specified a delay of zero.
75 *
76 * Returns : none
77 ************************************************************************************************************************
78 */
79
80 void OSTimeDly (OS_TICK dly,
81 OS_OPT opt,
82 OS_ERR *p_err)
83 {
84 CPU_SR_ALLOC();
85
86
87
88 #ifdef OS_SAFETY_CRITICAL
89 if (p_err == (OS_ERR *)0) {
90 OS_SAFETY_CRITICAL_EXCEPTION();
91 return;
92 }
93 #endif
94
95 #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
96 if (OSIntNestingCtr > (OS_NESTING_CTR)0u) { /* Not allowed to call from an ISR */
97 *p_err = OS_ERR_TIME_DLY_ISR;
98 return;
99 }
100 #endif
101
102 if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0u) { /* Can't delay when the scheduler is locked */
103 *p_err = OS_ERR_SCHED_LOCKED;
104 return;
105 }
106
107 switch (opt) {
108 case OS_OPT_TIME_DLY:
109 case OS_OPT_TIME_TIMEOUT:
110 case OS_OPT_TIME_PERIODIC:
111 if (dly == (OS_TICK)0u) { /* 0 means no delay! */
112 *p_err = OS_ERR_TIME_ZERO_DLY;
113 return;
114 }
115 break;
116
117 case OS_OPT_TIME_MATCH:
118 break;
119
120 default:
121 *p_err = OS_ERR_OPT_INVALID;
122 return;
123 }
124
125 OS_CRITICAL_ENTER();
126 OSTCBCurPtr->TaskState = OS_TASK_STATE_DLY;
127 OS_TickListInsert(OSTCBCurPtr,
128 dly,
129 opt,
130 p_err);
131 if (*p_err != OS_ERR_NONE) {
132 OS_CRITICAL_EXIT_NO_SCHED();
133 return;
134 }
135 OS_RdyListRemove(OSTCBCurPtr); /* Remove current task from ready list */
136 OS_CRITICAL_EXIT_NO_SCHED();
137 OSSched(); /* Find next task to run! */
138 *p_err = OS_ERR_NONE;
139 }
140
141 /*$PAGE*/
142 /*
143 ************************************************************************************************************************
144 * DELAY TASK FOR SPECIFIED TIME
145 *
146 * Description: This function is called to delay execution of the currently running task until some time expires. This
147 * call allows you to specify the delay time in HOURS, MINUTES, SECONDS and MILLISECONDS instead of ticks.
148 *
149 * Arguments : hours specifies the number of hours that the task will be delayed (max. is 999 if the tick rate is
150 * 1000 Hz or less otherwise, a higher value would overflow a 32-bit unsigned counter).
151 *
152 * minutes specifies the number of minutes (max. 59 if 'opt' is OS_OPT_TIME_HMSM_STRICT)
153 *
154 * seconds specifies the number of seconds (max. 59 if 'opt' is OS_OPT_TIME_HMSM_STRICT)
155 *
156 * milli specifies the number of milliseconds (max. 999 if 'opt' is OS_OPT_TIME_HMSM_STRICT)
157 *
158 * opt specifies time delay bit-field options logically OR'd; default options marked with *** :
159 *
160 * *** OS_OPT_TIME_DLY specifies a relative time from the current value of OSTickCtr.
161 * OS_OPT_TIME_TIMEOUT same as OS_OPT_TIME_DLY.
162 * OS_OPT_TIME_MATCH indicates that the delay specifies the absolute value that OSTickCtr
163 * must reach before the task will be resumed.
164 * OS_OPT_TIME_PERIODIC indicates that the delay specifies the periodic value that OSTickCtr
165 * must reach before the task will be resumed.
166 *
167 * *** OS_OPT_TIME_HMSM_STRICT strictly allow only hours (0...99)
168 * minutes (0...59)
169 * seconds (0...59)
170 * milliseconds (0...999)
171 * OS_OPT_TIME_HMSM_NON_STRICT allow any value of hours (0...999)
172 * minutes (0...9999)
173 * seconds (0...65535)
174 * milliseconds (0...4294967295)
175 *
176 * p_err is a pointer to a variable that will receive an error code from this call.
177 *
178 * OS_ERR_NONE If the function returns from the desired delay
179 * OS_ERR_OPT_INVALID If you specified an invalid option for 'opt'
180 * OS_ERR_SCHED_LOCKED Can't delay when the scheduler is locked
181 * OS_ERR_TIME_DLY_ISR If called from an ISR
182 * OS_ERR_TIME_INVALID_HOURS If you didn't specify a valid value for 'hours'
183 * OS_ERR_TIME_INVALID_MINUTES If you didn't specify a valid value for 'minutes'
184 * OS_ERR_TIME_INVALID_SECONDS If you didn't specify a valid value for 'seconds'
185 * OS_ERR_TIME_INVALID_MILLISECONDS If you didn't specify a valid value for 'milli'
186 * OS_ERR_TIME_ZERO_DLY If hours, minutes, seconds and milli are all 0
187 *
188 * Returns : none
189 *
190 * Note(s) : 1) The resolution on the milliseconds depends on the tick rate. For example, you can't do a 10 mS delay
191 * if the ticker interrupts every 100 mS. In this case, the delay would be set to 0. The actual delay
192 * is rounded to the nearest tick.
193 *
194 * 2) Although this function allows you to delay a task for many, many hours, it's not recommended to put
195 * a task to sleep for that long.
196 ************************************************************************************************************************
197 */
198
199 #if OS_CFG_TIME_DLY_HMSM_EN > 0u
200 void OSTimeDlyHMSM (CPU_INT16U hours,
201 CPU_INT16U minutes,
202 CPU_INT16U seconds,
203 CPU_INT32U milli,
204 OS_OPT opt,
205 OS_ERR *p_err)
206 {
207 #if OS_CFG_ARG_CHK_EN > 0u
208 CPU_BOOLEAN opt_invalid;
209 CPU_BOOLEAN opt_non_strict;
210 #endif
211 OS_OPT opt_time;
212 OS_RATE_HZ tick_rate;
213 OS_TICK ticks;
214 CPU_SR_ALLOC();
215
216
217
218 #ifdef OS_SAFETY_CRITICAL
219 if (p_err == (OS_ERR *)0) {
220 OS_SAFETY_CRITICAL_EXCEPTION();
221 return;
222 }
223 #endif
224
225 #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
226 if (OSIntNestingCtr > (OS_NESTING_CTR)0u) { /* Not allowed to call from an ISR */
227 *p_err = OS_ERR_TIME_DLY_ISR;
228 return;
229 }
230 #endif
231
232 if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0u) { /* Can't delay when the scheduler is locked */
233 *p_err = OS_ERR_SCHED_LOCKED;
234 return;
235 }
236
237 opt_time = opt & OS_OPT_TIME_MASK; /* Retrieve time options only. */
238 switch (opt_time) {
239 case OS_OPT_TIME_DLY:
240 case OS_OPT_TIME_TIMEOUT:
241 case OS_OPT_TIME_PERIODIC:
242 if (milli == (CPU_INT32U)0u) { /* Make sure we didn't specify a 0 delay */
243 if (seconds == (CPU_INT16U)0u) {
244 if (minutes == (CPU_INT16U)0u) {
245 if (hours == (CPU_INT16U)0u) {
246 *p_err = OS_ERR_TIME_ZERO_DLY;
247 return;
248 }
249 }
250 }
251 }
252 break;
253
254 case OS_OPT_TIME_MATCH:
255 break;
256
257 default:
258 *p_err = OS_ERR_OPT_INVALID;
259 return;
260 }
261
262 #if OS_CFG_ARG_CHK_EN > 0u /* Validate arguments to be within range */
263 opt_invalid = DEF_BIT_IS_SET_ANY(opt, ~OS_OPT_TIME_OPTS_MASK);
264 if (opt_invalid == DEF_YES) {
265 *p_err = OS_ERR_OPT_INVALID;
266 return;
267 }
268
269 opt_non_strict = DEF_BIT_IS_SET(opt, OS_OPT_TIME_HMSM_NON_STRICT);
270 if (opt_non_strict != DEF_YES) {
271 if (milli > (CPU_INT32U)999u) {
272 *p_err = OS_ERR_TIME_INVALID_MILLISECONDS;
273 return;
274 }
275 if (seconds > (CPU_INT16U)59u) {
276 *p_err = OS_ERR_TIME_INVALID_SECONDS;
277 return;
278 }
279 if (minutes > (CPU_INT16U)59u) {
280 *p_err = OS_ERR_TIME_INVALID_MINUTES;
281 return;
282 }
283 if (hours > (CPU_INT16U)99u) {
284 *p_err = OS_ERR_TIME_INVALID_HOURS;
285 return;
286 }
287 } else {
288 if (minutes > (CPU_INT16U)9999u) {
289 *p_err = OS_ERR_TIME_INVALID_MINUTES;
290 return;
291 }
292 if (hours > (CPU_INT16U)999u) {
293 *p_err = OS_ERR_TIME_INVALID_HOURS;
294 return;
295 }
296 }
297 #endif
298
299 /* Compute the total number of clock ticks required.. */
300 /* .. (rounded to the nearest tick) */
301 tick_rate = OSCfg_TickRate_Hz;
302 ticks = ((OS_TICK)hours * (OS_TICK)3600u + (OS_TICK)minutes * (OS_TICK)60u + (OS_TICK)seconds) * tick_rate
303 + (tick_rate * ((OS_TICK)milli + (OS_TICK)500u / tick_rate)) / (OS_TICK)1000u;
304
305 if (ticks > (OS_TICK)0u) {
306 OS_CRITICAL_ENTER();
307 OSTCBCurPtr->TaskState = OS_TASK_STATE_DLY;
308 OS_TickListInsert(OSTCBCurPtr,
309 ticks,
310 opt_time,
311 p_err);
312 if (*p_err != OS_ERR_NONE) {
313 OS_CRITICAL_EXIT_NO_SCHED();
314 return;
315 }
316 OS_RdyListRemove(OSTCBCurPtr); /* Remove current task from ready list */
317 OS_CRITICAL_EXIT_NO_SCHED();
318 OSSched(); /* Find next task to run! */
319 *p_err = OS_ERR_NONE;
320 } else {
321 *p_err = OS_ERR_TIME_ZERO_DLY;
322 }
323 }
324 #endif
325 /*$PAGE*/
326 /*
327 ************************************************************************************************************************
328 * RESUME A DELAYED TASK
329 *
330 * Description: This function is used resume a task that has been delayed through a call to either OSTimeDly() or
331 * OSTimeDlyHMSM(). Note that cannot call this function to resume a task that is waiting for an event
332 * with timeout.
333 *
334 * Arguments : p_tcb is a pointer to the TCB of the task to resume.
335 *
336 * p_err is a pointer to a variable that will receive an error code
337 *
338 * OS_ERR_NONE Task has been resumed
339 * OS_ERR_STATE_INVALID Task is in an invalid state
340 * OS_ERR_TIME_DLY_RESUME_ISR If called from an ISR
341 * OS_ERR_TIME_NOT_DLY Task is not waiting for time to expire
342 * OS_ERR_TASK_SUSPENDED Task cannot be resumed, it was suspended by OSTaskSuspend()
343 *
344 * Note(s) : none
345 ************************************************************************************************************************
346 */
347
348 #if OS_CFG_TIME_DLY_RESUME_EN > 0u
349 void OSTimeDlyResume (OS_TCB *p_tcb,
350 OS_ERR *p_err)
351 {
352 CPU_SR_ALLOC();
353
354
355
356 #ifdef OS_SAFETY_CRITICAL
357 if (p_err == (OS_ERR *)0) {
358 OS_SAFETY_CRITICAL_EXCEPTION();
359 return;
360 }
361 #endif
362
363 #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
364 if (OSIntNestingCtr > (OS_NESTING_CTR)0u) { /* Not allowed to call from an ISR */
365 *p_err = OS_ERR_TIME_DLY_RESUME_ISR;
366 return;
367 }
368 #endif
369
370 #if OS_CFG_ARG_CHK_EN > 0u
371 if (p_tcb == (OS_TCB *)0) { /* Not possible for the running task to be delayed! */
372 *p_err = OS_ERR_TASK_NOT_DLY;
373 return;
374 }
375 #endif
376
377 CPU_CRITICAL_ENTER();
378 if (p_tcb == OSTCBCurPtr) { /* Not possible for the running task to be delayed! */
379 *p_err = OS_ERR_TASK_NOT_DLY;
380 CPU_CRITICAL_EXIT();
381 return;
382 }
383
384 switch (p_tcb->TaskState) {
385 case OS_TASK_STATE_RDY: /* Cannot Abort delay if task is ready */
386 CPU_CRITICAL_EXIT();
387 *p_err = OS_ERR_TASK_NOT_DLY;
388 break;
389
390 case OS_TASK_STATE_DLY:
391 OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT();
392 p_tcb->TaskState = OS_TASK_STATE_RDY;
393 OS_TickListRemove(p_tcb); /* Remove task from tick list */
394 OS_RdyListInsert(p_tcb); /* Add to ready list */
395 OS_CRITICAL_EXIT_NO_SCHED();
396 *p_err = OS_ERR_NONE;
397 break;
398
399 case OS_TASK_STATE_PEND:
400 CPU_CRITICAL_EXIT();
401 *p_err = OS_ERR_TASK_NOT_DLY;
402 break;
403
404 case OS_TASK_STATE_PEND_TIMEOUT:
405 CPU_CRITICAL_EXIT();
406 *p_err = OS_ERR_TASK_NOT_DLY;
407 break;
408
409 case OS_TASK_STATE_SUSPENDED:
410 CPU_CRITICAL_EXIT();
411 *p_err = OS_ERR_TASK_NOT_DLY;
412 break;
413
414 case OS_TASK_STATE_DLY_SUSPENDED:
415 OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT();
416 p_tcb->TaskState = OS_TASK_STATE_SUSPENDED;
417 OS_TickListRemove(p_tcb); /* Remove task from tick list */
418 OS_CRITICAL_EXIT_NO_SCHED();
419 *p_err = OS_ERR_TASK_SUSPENDED;
420 break;
421
422 case OS_TASK_STATE_PEND_SUSPENDED:
423 CPU_CRITICAL_EXIT();
424 *p_err = OS_ERR_TASK_NOT_DLY;
425 break;
426
427 case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED:
428 CPU_CRITICAL_EXIT();
429 *p_err = OS_ERR_TASK_NOT_DLY;
430 break;
431
432 default:
433 CPU_CRITICAL_EXIT();
434 *p_err = OS_ERR_STATE_INVALID;
435 break;
436 }
437
438 OSSched();
439 }
440 #endif
441 /*$PAGE*/
442 /*
443 ************************************************************************************************************************
444 * GET CURRENT SYSTEM TIME
445 *
446 * Description: This function is used by your application to obtain the current value of the counter which keeps track of
447 * the number of clock ticks.
448 *
449 * Arguments : p_err is a pointer to a variable that will receive an error code
450 *
451 * OS_ERR_NONE If the call was successful
452 *
453 * Returns : The current value of OSTickCtr
454 ************************************************************************************************************************
455 */
456
457 OS_TICK OSTimeGet (OS_ERR *p_err)
458 {
459 OS_TICK ticks;
460 CPU_SR_ALLOC();
461
462
463
464 #ifdef OS_SAFETY_CRITICAL
465 if (p_err == (OS_ERR *)0) {
466 OS_SAFETY_CRITICAL_EXCEPTION();
467 return ((OS_TICK)0);
468 }
469 #endif
470
471 CPU_CRITICAL_ENTER();
472 ticks = OSTickCtr;
473 CPU_CRITICAL_EXIT();
474 *p_err = OS_ERR_NONE;
475 return (ticks);
476 }
477
478 /*
479 ************************************************************************************************************************
480 * SET SYSTEM CLOCK
481 *
482 * Description: This function sets the counter which keeps track of the number of clock ticks.
483 *
484 * Arguments : ticks is the desired tick value
485 *
486 * p_err is a pointer to a variable that will receive an error code
487 *
488 * OS_ERR_NONE If the call was successful
489 *
490 * Returns : none
491 ************************************************************************************************************************
492 */
493
494 void OSTimeSet (OS_TICK ticks,
495 OS_ERR *p_err)
496 {
497 CPU_SR_ALLOC();
498
499
500
501 #ifdef OS_SAFETY_CRITICAL
502 if (p_err == (OS_ERR *)0) {
503 OS_SAFETY_CRITICAL_EXCEPTION();
504 return;
505 }
506 #endif
507
508 CPU_CRITICAL_ENTER();
509 OSTickCtr = ticks;
510 CPU_CRITICAL_EXIT();
511 *p_err = OS_ERR_NONE;
512 }
513
514 /*$PAGE*/
515 /*
516 ************************************************************************************************************************
517 * PROCESS SYSTEM TICK
518 *
519 * Description: This function is used to signal to uC/OS-III the occurrence of a 'system tick' (also known as a
520 * 'clock tick'). This function should be called by the tick ISR.
521 *
522 * Arguments : none
523 *
524 * Returns : none
525 ************************************************************************************************************************
526 */
527
528 void OSTimeTick (void)
529 {
530 OS_ERR err;
531 #if OS_CFG_ISR_POST_DEFERRED_EN > 0u
532 CPU_TS ts;
533 #endif
534
535
536 OSTimeTickHook(); /* Call user definable hook */
537
538 #if OS_CFG_ISR_POST_DEFERRED_EN > 0u
539
540 ts = OS_TS_GET(); /* Get timestamp */
541 OS_IntQPost((OS_OBJ_TYPE) OS_OBJ_TYPE_TICK, /* Post to ISR queue */
542 (void *)&OSRdyList[OSPrioCur],
543 (void *) 0,
544 (OS_MSG_SIZE) 0u,
545 (OS_FLAGS ) 0u,
546 (OS_OPT ) 0u,
547 (CPU_TS ) ts,
548 (OS_ERR *)&err);
549
550 #else
551
552 (void)OSTaskSemPost((OS_TCB *)&OSTickTaskTCB, /* Signal tick task */
553 (OS_OPT ) OS_OPT_POST_NONE,
554 (OS_ERR *)&err);
555
556
557 #if OS_CFG_SCHED_ROUND_ROBIN_EN > 0u
558 OS_SchedRoundRobin(&OSRdyList[OSPrioCur]);
559 #endif
560
561 #if OS_CFG_TMR_EN > 0u
562 OSTmrUpdateCtr--;
563 if (OSTmrUpdateCtr == (OS_CTR)0u) {
564 OSTmrUpdateCtr = OSTmrUpdateCnt;
565 OSTaskSemPost((OS_TCB *)&OSTmrTaskTCB, /* Signal timer task */
566 (OS_OPT ) OS_OPT_POST_NONE,
567 (OS_ERR *)&err);
568 }
569 #endif
570
571 #endif
572 }