2 FreeRTOS V7.5.0 - Copyright (C) 2013 Real Time Engineers Ltd.
\r
4 VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
\r
6 ***************************************************************************
\r
8 * FreeRTOS provides completely free yet professionally developed, *
\r
9 * robust, strictly quality controlled, supported, and cross *
\r
10 * platform software that has become a de facto standard. *
\r
12 * Help yourself get started quickly and support the FreeRTOS *
\r
13 * project by purchasing a FreeRTOS tutorial book, reference *
\r
14 * manual, or both from: http://www.FreeRTOS.org/Documentation *
\r
18 ***************************************************************************
\r
20 This file is part of the FreeRTOS distribution.
\r
22 FreeRTOS is free software; you can redistribute it and/or modify it under
\r
23 the terms of the GNU General Public License (version 2) as published by the
\r
24 Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
\r
26 >>! NOTE: The modification to the GPL is included to allow you to distribute
\r
27 >>! a combined work that includes FreeRTOS without being obliged to provide
\r
28 >>! the source code for proprietary components outside of the FreeRTOS
\r
31 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
\r
32 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
\r
33 FOR A PARTICULAR PURPOSE. Full license text is available from the following
\r
34 link: http://www.freertos.org/a00114.html
\r
38 ***************************************************************************
\r
40 * Having a problem? Start by reading the FAQ "My application does *
\r
41 * not run, what could be wrong?" *
\r
43 * http://www.FreeRTOS.org/FAQHelp.html *
\r
45 ***************************************************************************
\r
47 http://www.FreeRTOS.org - Documentation, books, training, latest versions,
\r
48 license and Real Time Engineers Ltd. contact details.
\r
50 http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
\r
51 including FreeRTOS+Trace - an indispensable productivity tool, a DOS
\r
52 compatible FAT file system, and our tiny thread aware UDP/IP stack.
\r
54 http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
\r
55 Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS
\r
56 licenses offer ticketed support, indemnification and middleware.
\r
58 http://www.SafeRTOS.com - High Integrity Systems also provide a safety
\r
59 engineered and independently SIL3 certified version for use in safety and
\r
60 mission critical applications that require provable dependability.
\r
65 /*-----------------------------------------------------------
\r
66 * Implementation of functions defined in portable.h for the SH2A port.
\r
67 *----------------------------------------------------------*/
\r
69 /* Standard C includes. */
\r
72 /* Scheduler includes. */
\r
73 #include "FreeRTOS.h"
\r
76 /* Library includes. */
\r
79 /* Hardware specifics. */
\r
80 #include "iorx111.h"
\r
82 /*-----------------------------------------------------------*/
\r
84 /* Tasks should start with interrupts enabled and in Supervisor mode, therefore
\r
85 PSW is set with U and I set, and PM and IPL clear. */
\r
86 #define portINITIAL_PSW ( ( portSTACK_TYPE ) 0x00030000 )
\r
88 /* The peripheral clock is divided by this value before being supplying the
\r
90 #if ( configUSE_TICKLESS_IDLE == 0 )
\r
91 /* If tickless idle is not used then the divisor can be fixed. */
\r
92 #define portCLOCK_DIVISOR 8UL
\r
93 #elif ( configPERIPHERAL_CLOCK_HZ >= 12000000 )
\r
94 #define portCLOCK_DIVISOR 512UL
\r
95 #elif ( configPERIPHERAL_CLOCK_HZ >= 6000000 )
\r
96 #define portCLOCK_DIVISOR 128UL
\r
97 #elif ( configPERIPHERAL_CLOCK_HZ >= 1000000 )
\r
98 #define portCLOCK_DIVISOR 32UL
\r
100 #define portCLOCK_DIVISOR 8UL
\r
104 /* Keys required to lock and unlock access to certain system registers
\r
106 #define portUNLOCK_KEY 0xA50B
\r
107 #define portLOCK_KEY 0xA500
\r
109 /*-----------------------------------------------------------*/
\r
112 * Function to start the first task executing - written in asm code as direct
\r
113 * access to registers is required.
\r
115 extern void prvStartFirstTask( void );
\r
118 * The tick ISR handler. The peripheral used is configured by the application
\r
119 * via a hook/callback function.
\r
121 __interrupt static void prvTickISR( void );
\r
124 * Sets up the periodic ISR used for the RTOS tick using the CMT.
\r
125 * The application writer can define configSETUP_TICK_INTERRUPT() (in
\r
126 * FreeRTOSConfig.h) such that their own tick interrupt configuration is used
\r
127 * in place of prvSetupTimerInterrupt().
\r
129 static void prvSetupTimerInterrupt( void );
\r
130 #ifndef configSETUP_TICK_INTERRUPT
\r
131 /* The user has not provided their own tick interrupt configuration so use
\r
132 the definition in this file (which uses the interval timer). */
\r
133 #define configSETUP_TICK_INTERRUPT() prvSetupTimerInterrupt()
\r
134 #endif /* configSETUP_TICK_INTERRUPT */
\r
137 * Called after the sleep mode registers have been configured, prvSleep()
\r
138 * executes the pre and post sleep macros, and actually calls the wait
\r
141 #if configUSE_TICKLESS_IDLE == 1
\r
142 static void prvSleep( portTickType xExpectedIdleTime );
\r
143 #endif /* configUSE_TICKLESS_IDLE */
\r
145 /*-----------------------------------------------------------*/
\r
147 extern void *pxCurrentTCB;
\r
149 /*-----------------------------------------------------------*/
\r
151 /* Calculate how many clock increments make up a single tick period. */
\r
152 static const unsigned long ulMatchValueForOneTick = ( ( configPERIPHERAL_CLOCK_HZ / portCLOCK_DIVISOR ) / configTICK_RATE_HZ );
\r
154 #if configUSE_TICKLESS_IDLE == 1
\r
156 /* Holds the maximum number of ticks that can be suppressed - which is
\r
157 basically how far into the future an interrupt can be generated. Set
\r
158 during initialisation. This is the maximum possible value that the
\r
159 compare match register can hold divided by ulMatchValueForOneTick. */
\r
160 static const portTickType xMaximumPossibleSuppressedTicks = USHRT_MAX / ( ( configPERIPHERAL_CLOCK_HZ / portCLOCK_DIVISOR ) / configTICK_RATE_HZ );
\r
162 /* Flag set from the tick interrupt to allow the sleep processing to know if
\r
163 sleep mode was exited because of a tick interrupt, or an interrupt
\r
164 generated by something else. */
\r
165 static volatile uint32_t ulTickFlag = pdFALSE;
\r
167 /* The CMT counter is stopped temporarily each time it is re-programmed.
\r
168 The following constant offsets the CMT counter match value by the number of
\r
169 CMT counts that would typically be missed while the counter was stopped to
\r
170 compensate for the lost time. The large difference between the divided CMT
\r
171 clock and the CPU clock means it is likely ulStoppedTimerCompensation will
\r
172 equal zero - and be optimised away. */
\r
173 static const unsigned long ulStoppedTimerCompensation = 100UL / ( configCPU_CLOCK_HZ / ( configPERIPHERAL_CLOCK_HZ / portCLOCK_DIVISOR ) );
\r
177 /*-----------------------------------------------------------*/
\r
180 * See header file for description.
\r
182 portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters )
\r
184 /* Offset to end up on 8 byte boundary. */
\r
187 /* R0 is not included as it is the stack pointer. */
\r
188 *pxTopOfStack = 0x00;
\r
190 *pxTopOfStack = 0x00;
\r
192 *pxTopOfStack = portINITIAL_PSW;
\r
194 *pxTopOfStack = ( portSTACK_TYPE ) pxCode;
\r
196 /* When debugging it can be useful if every register is set to a known
\r
197 value. Otherwise code space can be saved by just setting the registers
\r
198 that need to be set. */
\r
199 #ifdef USE_FULL_REGISTER_INITIALISATION
\r
202 *pxTopOfStack = 0x12345678; /* r15. */
\r
204 *pxTopOfStack = 0xaaaabbbb;
\r
206 *pxTopOfStack = 0xdddddddd;
\r
208 *pxTopOfStack = 0xcccccccc;
\r
210 *pxTopOfStack = 0xbbbbbbbb;
\r
212 *pxTopOfStack = 0xaaaaaaaa;
\r
214 *pxTopOfStack = 0x99999999;
\r
216 *pxTopOfStack = 0x88888888;
\r
218 *pxTopOfStack = 0x77777777;
\r
220 *pxTopOfStack = 0x66666666;
\r
222 *pxTopOfStack = 0x55555555;
\r
224 *pxTopOfStack = 0x44444444;
\r
226 *pxTopOfStack = 0x33333333;
\r
228 *pxTopOfStack = 0x22222222;
\r
233 /* Leave space for the registers that will get popped from the stack
\r
234 when the task first starts executing. */
\r
235 pxTopOfStack -= 15;
\r
239 *pxTopOfStack = ( portSTACK_TYPE ) pvParameters; /* R1 */
\r
241 *pxTopOfStack = 0x12345678; /* Accumulator. */
\r
243 *pxTopOfStack = 0x87654321; /* Accumulator. */
\r
245 return pxTopOfStack;
\r
247 /*-----------------------------------------------------------*/
\r
249 portBASE_TYPE xPortStartScheduler( void )
\r
251 /* Use pxCurrentTCB just so it does not get optimised away. */
\r
252 if( pxCurrentTCB != NULL )
\r
254 /* Call an application function to set up the timer that will generate
\r
255 the tick interrupt. This way the application can decide which
\r
256 peripheral to use. If tickless mode is used then the default
\r
257 implementation defined in this file (which uses CMT0) should not be
\r
259 configSETUP_TICK_INTERRUPT();
\r
261 /* Enable the software interrupt. */
\r
262 _IEN( _ICU_SWINT ) = 1;
\r
264 /* Ensure the software interrupt is clear. */
\r
265 _IR( _ICU_SWINT ) = 0;
\r
267 /* Ensure the software interrupt is set to the kernel priority. */
\r
268 _IPR( _ICU_SWINT ) = configKERNEL_INTERRUPT_PRIORITY;
\r
270 /* Start the first task. */
\r
271 prvStartFirstTask();
\r
274 /* Execution should not reach here as the tasks are now running!
\r
275 prvSetupTimerInterrupt() is called here to prevent the compiler outputting
\r
276 a warning about a statically declared function not being referenced in the
\r
277 case that the application writer has provided their own tick interrupt
\r
278 configuration routine (and defined configSETUP_TICK_INTERRUPT() such that
\r
279 their own routine will be called in place of prvSetupTimerInterrupt()). */
\r
280 prvSetupTimerInterrupt();
\r
282 /* Should not get here. */
\r
285 /*-----------------------------------------------------------*/
\r
287 #pragma vector = configTICK_VECTOR
\r
288 __interrupt static void prvTickISR( void )
\r
290 /* Re-enable interrupts. */
\r
291 __enable_interrupt();
\r
293 /* Increment the tick, and perform any processing the new tick value
\r
295 __set_interrupt_level( configMAX_SYSCALL_INTERRUPT_PRIORITY );
\r
297 if( xTaskIncrementTick() != pdFALSE )
\r
302 __set_interrupt_level( configKERNEL_INTERRUPT_PRIORITY );
\r
304 #if configUSE_TICKLESS_IDLE == 1
\r
306 /* The CPU woke because of a tick. */
\r
307 ulTickFlag = pdTRUE;
\r
309 /* If this is the first tick since exiting tickless mode then the CMT
\r
310 compare match value needs resetting. */
\r
311 CMT0.CMCOR = ( unsigned short ) ulMatchValueForOneTick;
\r
315 /*-----------------------------------------------------------*/
\r
317 void vPortEndScheduler( void )
\r
319 /* Not implemented as there is nothing to return to. */
\r
321 /*-----------------------------------------------------------*/
\r
323 static void prvSetupTimerInterrupt( void )
\r
326 SYSTEM.PRCR.WORD = portUNLOCK_KEY;
\r
332 SYSTEM.PRCR.WORD = portLOCK_KEY;
\r
334 /* Interrupt on compare match. */
\r
335 CMT0.CMCR.BIT.CMIE = 1;
\r
337 /* Set the compare match value. */
\r
338 CMT0.CMCOR = ( unsigned short ) ulMatchValueForOneTick;
\r
340 /* Divide the PCLK. */
\r
341 #if portCLOCK_DIVISOR == 512
\r
343 CMT0.CMCR.BIT.CKS = 3;
\r
345 #elif portCLOCK_DIVISOR == 128
\r
347 CMT0.CMCR.BIT.CKS = 2;
\r
349 #elif portCLOCK_DIVISOR == 32
\r
351 CMT0.CMCR.BIT.CKS = 1;
\r
353 #elif portCLOCK_DIVISOR == 8
\r
355 CMT0.CMCR.BIT.CKS = 0;
\r
359 #error Invalid portCLOCK_DIVISOR setting
\r
364 /* Enable the interrupt... */
\r
365 _IEN( _CMT0_CMI0 ) = 1;
\r
367 /* ...and set its priority to the application defined kernel priority. */
\r
368 _IPR( _CMT0_CMI0 ) = configKERNEL_INTERRUPT_PRIORITY;
\r
370 /* Start the timer. */
\r
371 CMT.CMSTR0.BIT.STR0 = 1;
\r
373 /*-----------------------------------------------------------*/
\r
375 #if configUSE_TICKLESS_IDLE == 1
\r
377 static void prvSleep( portTickType xExpectedIdleTime )
\r
379 /* Allow the application to define some pre-sleep processing. */
\r
380 configPRE_SLEEP_PROCESSING( xExpectedIdleTime );
\r
382 /* xExpectedIdleTime being set to 0 by configPRE_SLEEP_PROCESSING()
\r
383 means the application defined code has already executed the WAIT
\r
385 if( xExpectedIdleTime > 0 )
\r
387 __wait_for_interrupt();
\r
390 /* Allow the application to define some post sleep processing. */
\r
391 configPOST_SLEEP_PROCESSING( xExpectedIdleTime );
\r
394 #endif /* configUSE_TICKLESS_IDLE */
\r
395 /*-----------------------------------------------------------*/
\r
397 #if configUSE_TICKLESS_IDLE == 1
\r
399 void vPortSuppressTicksAndSleep( portTickType xExpectedIdleTime )
\r
401 unsigned long ulMatchValue, ulCompleteTickPeriods, ulCurrentCount;
\r
402 eSleepModeStatus eSleepAction;
\r
404 /* THIS FUNCTION IS CALLED WITH THE SCHEDULER SUSPENDED. */
\r
406 /* Make sure the CMT reload value does not overflow the counter. */
\r
407 if( xExpectedIdleTime > xMaximumPossibleSuppressedTicks )
\r
409 xExpectedIdleTime = xMaximumPossibleSuppressedTicks;
\r
412 /* Calculate the reload value required to wait xExpectedIdleTime tick
\r
414 ulMatchValue = ulMatchValueForOneTick * xExpectedIdleTime;
\r
415 if( ulMatchValue > ulStoppedTimerCompensation )
\r
417 /* Compensate for the fact that the CMT is going to be stopped
\r
419 ulMatchValue -= ulStoppedTimerCompensation;
\r
422 /* Stop the CMT momentarily. The time the CMT is stopped for is
\r
423 accounted for as best it can be, but using the tickless mode will
\r
424 inevitably result in some tiny drift of the time maintained by the
\r
425 kernel with respect to calendar time. */
\r
426 CMT.CMSTR0.BIT.STR0 = 0;
\r
427 while( CMT.CMSTR0.BIT.STR0 == 1 )
\r
429 /* Nothing to do here. */
\r
432 /* Critical section using the global interrupt bit as the i bit is
\r
433 automatically reset by the WAIT instruction. */
\r
434 __disable_interrupt();
\r
436 /* The tick flag is set to false before sleeping. If it is true when
\r
437 sleep mode is exited then sleep mode was probably exited because the
\r
438 tick was suppressed for the entire xExpectedIdleTime period. */
\r
439 ulTickFlag = pdFALSE;
\r
441 /* If a context switch is pending then abandon the low power entry as
\r
442 the context switch might have been pended by an external interrupt that
\r
443 requires processing. */
\r
444 eSleepAction = eTaskConfirmSleepModeStatus();
\r
445 if( eSleepAction == eAbortSleep )
\r
447 /* Restart tick. */
\r
448 CMT.CMSTR0.BIT.STR0 = 1;
\r
449 __enable_interrupt();
\r
451 else if( eSleepAction == eNoTasksWaitingTimeout )
\r
453 /* Protection off. */
\r
454 SYSTEM.PRCR.WORD = portUNLOCK_KEY;
\r
456 /* Ready for software standby with all clocks stopped. */
\r
457 SYSTEM.SBYCR.BIT.SSBY = 1;
\r
459 /* Protection on. */
\r
460 SYSTEM.PRCR.WORD = portLOCK_KEY;
\r
462 /* Sleep until something happens. Calling prvSleep() will
\r
463 automatically reset the i bit in the PSW. */
\r
464 prvSleep( xExpectedIdleTime );
\r
466 /* Restart the CMT. */
\r
467 CMT.CMSTR0.BIT.STR0 = 1;
\r
471 /* Protection off. */
\r
472 SYSTEM.PRCR.WORD = portUNLOCK_KEY;
\r
474 /* Ready for deep sleep mode. */
\r
475 SYSTEM.MSTPCRC.BIT.DSLPE = 1;
\r
476 SYSTEM.MSTPCRA.BIT.MSTPA28 = 1;
\r
477 SYSTEM.SBYCR.BIT.SSBY = 0;
\r
479 /* Protection on. */
\r
480 SYSTEM.PRCR.WORD = portLOCK_KEY;
\r
482 /* Adjust the match value to take into account that the current
\r
483 time slice is already partially complete. */
\r
484 ulMatchValue -= ( unsigned long ) CMT0.CMCNT;
\r
485 CMT0.CMCOR = ( unsigned short ) ulMatchValue;
\r
487 /* Restart the CMT to count up to the new match value. */
\r
489 CMT.CMSTR0.BIT.STR0 = 1;
\r
491 /* Sleep until something happens. Calling prvSleep() will
\r
492 automatically reset the i bit in the PSW. */
\r
493 prvSleep( xExpectedIdleTime );
\r
495 /* Stop CMT. Again, the time the SysTick is stopped for is
\r
496 accounted for as best it can be, but using the tickless mode will
\r
497 inevitably result in some tiny drift of the time maintained by the
\r
498 kernel with respect to calendar time. */
\r
499 CMT.CMSTR0.BIT.STR0 = 0;
\r
500 while( CMT.CMSTR0.BIT.STR0 == 1 )
\r
502 /* Nothing to do here. */
\r
505 ulCurrentCount = ( unsigned long ) CMT0.CMCNT;
\r
507 if( ulTickFlag != pdFALSE )
\r
509 /* The tick interrupt has already executed, although because
\r
510 this function is called with the scheduler suspended the actual
\r
511 tick processing will not occur until after this function has
\r
512 exited. Reset the match value with whatever remains of this
\r
514 ulMatchValue = ulMatchValueForOneTick - ulCurrentCount;
\r
515 CMT0.CMCOR = ( unsigned short ) ulMatchValue;
\r
517 /* The tick interrupt handler will already have pended the tick
\r
518 processing in the kernel. As the pending tick will be
\r
519 processed as soon as this function exits, the tick value
\r
520 maintained by the tick is stepped forward by one less than the
\r
521 time spent sleeping. The actual stepping of the tick appears
\r
522 later in this function. */
\r
523 ulCompleteTickPeriods = xExpectedIdleTime - 1UL;
\r
527 /* Something other than the tick interrupt ended the sleep.
\r
528 How many complete tick periods passed while the processor was
\r
530 ulCompleteTickPeriods = ulCurrentCount / ulMatchValueForOneTick;
\r
532 /* The match value is set to whatever fraction of a single tick
\r
534 ulMatchValue = ulCurrentCount - ( ulCompleteTickPeriods * ulMatchValueForOneTick );
\r
535 CMT0.CMCOR = ( unsigned short ) ulMatchValue;
\r
538 /* Restart the CMT so it runs up to the match value. The match value
\r
539 will get set to the value required to generate exactly one tick period
\r
540 the next time the CMT interrupt executes. */
\r
542 CMT.CMSTR0.BIT.STR0 = 1;
\r
544 /* Wind the tick forward by the number of tick periods that the CPU
\r
545 remained in a low power state. */
\r
546 vTaskStepTick( ulCompleteTickPeriods );
\r
550 #endif /* configUSE_TICKLESS_IDLE */
\r