port.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. /*
  2. * FreeRTOS Kernel <DEVELOPMENT BRANCH>
  3. * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
  4. *
  5. * SPDX-License-Identifier: MIT
  6. *
  7. * Permission is hereby granted, free of charge, to any person obtaining a copy of
  8. * this software and associated documentation files (the "Software"), to deal in
  9. * the Software without restriction, including without limitation the rights to
  10. * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  11. * the Software, and to permit persons to whom the Software is furnished to do so,
  12. * subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be included in all
  15. * copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  19. * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  20. * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  21. * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  22. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  23. *
  24. * https://www.FreeRTOS.org
  25. * https://github.com/FreeRTOS
  26. *
  27. */
  28. /*
  29. * Changes from V2.5.2
  30. *
  31. + usCriticalNesting now has a volatile qualifier.
  32. */
  33. /* Standard includes. */
  34. #include <stdlib.h>
  35. #include <signal.h>
  36. /* Scheduler includes. */
  37. #include "FreeRTOS.h"
  38. #include "task.h"
  39. /*-----------------------------------------------------------
  40. * Implementation of functions defined in portable.h for the MSP430 port.
  41. *----------------------------------------------------------*/
  42. /* Constants required for hardware setup. The tick ISR runs off the ACLK,
  43. * not the MCLK. */
  44. #define portACLK_FREQUENCY_HZ ( ( TickType_t ) 32768 )
  45. #define portINITIAL_CRITICAL_NESTING ( ( uint16_t ) 10 )
  46. #define portFLAGS_INT_ENABLED ( ( StackType_t ) 0x08 )
  47. /* We require the address of the pxCurrentTCB variable, but don't want to know
  48. * any details of its type. */
  49. typedef void TCB_t;
  50. extern volatile TCB_t * volatile pxCurrentTCB;
  51. /* Most ports implement critical sections by placing the interrupt flags on
  52. * the stack before disabling interrupts. Exiting the critical section is then
  53. * simply a case of popping the flags from the stack. As mspgcc does not use
  54. * a frame pointer this cannot be done as modifying the stack will clobber all
  55. * the stack variables. Instead each task maintains a count of the critical
  56. * section nesting depth. Each time a critical section is entered the count is
  57. * incremented. Each time a critical section is left the count is decremented -
  58. * with interrupts only being re-enabled if the count is zero.
  59. *
  60. * usCriticalNesting will get set to zero when the scheduler starts, but must
  61. * not be initialised to zero as this will cause problems during the startup
  62. * sequence. */
  63. volatile uint16_t usCriticalNesting = portINITIAL_CRITICAL_NESTING;
  64. /*-----------------------------------------------------------*/
  65. /*
  66. * Macro to save a task context to the task stack. This simply pushes all the
  67. * general purpose msp430 registers onto the stack, followed by the
  68. * usCriticalNesting value used by the task. Finally the resultant stack
  69. * pointer value is saved into the task control block so it can be retrieved
  70. * the next time the task executes.
  71. */
  72. #define portSAVE_CONTEXT() \
  73. asm volatile ( "push r4 \n\t" \
  74. "push r5 \n\t" \
  75. "push r6 \n\t" \
  76. "push r7 \n\t" \
  77. "push r8 \n\t" \
  78. "push r9 \n\t" \
  79. "push r10 \n\t" \
  80. "push r11 \n\t" \
  81. "push r12 \n\t" \
  82. "push r13 \n\t" \
  83. "push r14 \n\t" \
  84. "push r15 \n\t" \
  85. "mov.w usCriticalNesting, r14 \n\t" \
  86. "push r14 \n\t" \
  87. "mov.w pxCurrentTCB, r12 \n\t" \
  88. "mov.w r1, @r12 \n\t" \
  89. );
  90. /*
  91. * Macro to restore a task context from the task stack. This is effectively
  92. * the reverse of portSAVE_CONTEXT(). First the stack pointer value is
  93. * loaded from the task control block. Next the value for usCriticalNesting
  94. * used by the task is retrieved from the stack - followed by the value of all
  95. * the general purpose msp430 registers.
  96. *
  97. * The bic instruction ensures there are no low power bits set in the status
  98. * register that is about to be popped from the stack.
  99. */
  100. #define portRESTORE_CONTEXT() \
  101. asm volatile ( "mov.w pxCurrentTCB, r12 \n\t" \
  102. "mov.w @r12, r1 \n\t" \
  103. "pop r15 \n\t" \
  104. "mov.w r15, usCriticalNesting \n\t" \
  105. "pop r15 \n\t" \
  106. "pop r14 \n\t" \
  107. "pop r13 \n\t" \
  108. "pop r12 \n\t" \
  109. "pop r11 \n\t" \
  110. "pop r10 \n\t" \
  111. "pop r9 \n\t" \
  112. "pop r8 \n\t" \
  113. "pop r7 \n\t" \
  114. "pop r6 \n\t" \
  115. "pop r5 \n\t" \
  116. "pop r4 \n\t" \
  117. "bic #(0xf0),0(r1) \n\t" \
  118. "reti \n\t" \
  119. );
  120. /*-----------------------------------------------------------*/
  121. /*
  122. * Sets up the periodic ISR used for the RTOS tick. This uses timer 0, but
  123. * could have alternatively used the watchdog timer or timer 1.
  124. */
  125. static void prvSetupTimerInterrupt( void );
  126. /*-----------------------------------------------------------*/
  127. /*
  128. * Initialise the stack of a task to look exactly as if a call to
  129. * portSAVE_CONTEXT had been called.
  130. *
  131. * See the header file portable.h.
  132. */
  133. StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
  134. TaskFunction_t pxCode,
  135. void * pvParameters )
  136. {
  137. /*
  138. * Place a few bytes of known values on the bottom of the stack.
  139. * This is just useful for debugging and can be included if required.
  140. *
  141. * pxTopOfStack = ( StackType_t ) 0x1111;
  142. * pxTopOfStack--;
  143. * pxTopOfStack = ( StackType_t ) 0x2222;
  144. * pxTopOfStack--;
  145. * pxTopOfStack = ( StackType_t ) 0x3333;
  146. * pxTopOfStack--;
  147. */
  148. /* The msp430 automatically pushes the PC then SR onto the stack before
  149. * executing an ISR. We want the stack to look just as if this has happened
  150. * so place a pointer to the start of the task on the stack first - followed
  151. * by the flags we want the task to use when it starts up. */
  152. *pxTopOfStack = ( StackType_t ) pxCode;
  153. pxTopOfStack--;
  154. *pxTopOfStack = portFLAGS_INT_ENABLED;
  155. pxTopOfStack--;
  156. /* Next the general purpose registers. */
  157. *pxTopOfStack = ( StackType_t ) 0x4444;
  158. pxTopOfStack--;
  159. *pxTopOfStack = ( StackType_t ) 0x5555;
  160. pxTopOfStack--;
  161. *pxTopOfStack = ( StackType_t ) 0x6666;
  162. pxTopOfStack--;
  163. *pxTopOfStack = ( StackType_t ) 0x7777;
  164. pxTopOfStack--;
  165. *pxTopOfStack = ( StackType_t ) 0x8888;
  166. pxTopOfStack--;
  167. *pxTopOfStack = ( StackType_t ) 0x9999;
  168. pxTopOfStack--;
  169. *pxTopOfStack = ( StackType_t ) 0xaaaa;
  170. pxTopOfStack--;
  171. *pxTopOfStack = ( StackType_t ) 0xbbbb;
  172. pxTopOfStack--;
  173. #ifdef __MSPGCC__
  174. *pxTopOfStack = ( StackType_t ) 0xcccc;
  175. #else
  176. /* The MSP430 EABI expects the function parameter in R12. */
  177. *pxTopOfStack = ( StackType_t ) pvParameters;
  178. #endif
  179. pxTopOfStack--;
  180. *pxTopOfStack = ( StackType_t ) 0xdddd;
  181. pxTopOfStack--;
  182. *pxTopOfStack = ( StackType_t ) 0xeeee;
  183. pxTopOfStack--;
  184. #ifdef __MSPGCC__
  185. /* The mspgcc ABI expects the function parameter in R15. */
  186. *pxTopOfStack = ( StackType_t ) pvParameters;
  187. #else
  188. *pxTopOfStack = ( StackType_t ) 0xffff;
  189. #endif
  190. pxTopOfStack--;
  191. /* The code generated by the mspgcc compiler does not maintain separate
  192. * stack and frame pointers. The portENTER_CRITICAL macro cannot therefore
  193. * use the stack as per other ports. Instead a variable is used to keep
  194. * track of the critical section nesting. This variable has to be stored
  195. * as part of the task context and is initially set to zero. */
  196. *pxTopOfStack = ( StackType_t ) portNO_CRITICAL_SECTION_NESTING;
  197. /* Return a pointer to the top of the stack we have generated so this can
  198. * be stored in the task control block for the task. */
  199. return pxTopOfStack;
  200. }
  201. /*-----------------------------------------------------------*/
  202. BaseType_t xPortStartScheduler( void )
  203. {
  204. /* Setup the hardware to generate the tick. Interrupts are disabled when
  205. * this function is called. */
  206. prvSetupTimerInterrupt();
  207. /* Restore the context of the first task that is going to run. */
  208. portRESTORE_CONTEXT();
  209. /* Should not get here as the tasks are now running! */
  210. return pdTRUE;
  211. }
  212. /*-----------------------------------------------------------*/
  213. void vPortEndScheduler( void )
  214. {
  215. /* It is unlikely that the MSP430 port will get stopped. If required simply
  216. * disable the tick interrupt here. */
  217. }
  218. /*-----------------------------------------------------------*/
  219. /*
  220. * Manual context switch called by portYIELD or taskYIELD.
  221. *
  222. * The first thing we do is save the registers so we can use a naked attribute.
  223. */
  224. void vPortYield( void ) __attribute__( ( naked ) );
  225. void vPortYield( void )
  226. {
  227. /* We want the stack of the task being saved to look exactly as if the task
  228. * was saved during a pre-emptive RTOS tick ISR. Before calling an ISR the
  229. * msp430 places the status register onto the stack. As this is a function
  230. * call and not an ISR we have to do this manually. */
  231. asm volatile ( "push r2" );
  232. _DINT();
  233. /* Save the context of the current task. */
  234. portSAVE_CONTEXT();
  235. /* Switch to the highest priority task that is ready to run. */
  236. vTaskSwitchContext();
  237. /* Restore the context of the new task. */
  238. portRESTORE_CONTEXT();
  239. }
  240. /*-----------------------------------------------------------*/
  241. /*
  242. * Hardware initialisation to generate the RTOS tick. This uses timer 0
  243. * but could alternatively use the watchdog timer or timer 1.
  244. */
  245. static void prvSetupTimerInterrupt( void )
  246. {
  247. /* Ensure the timer is stopped. */
  248. TACTL = 0;
  249. /* Run the timer of the ACLK. */
  250. TACTL = TASSEL_1;
  251. /* Clear everything to start with. */
  252. TACTL |= TACLR;
  253. /* Set the compare match value according to the tick rate we want. */
  254. TACCR0 = portACLK_FREQUENCY_HZ / configTICK_RATE_HZ;
  255. /* Enable the interrupts. */
  256. TACCTL0 = CCIE;
  257. /* Start up clean. */
  258. TACTL |= TACLR;
  259. /* Up mode. */
  260. TACTL |= MC_1;
  261. }
  262. /*-----------------------------------------------------------*/
  263. /*
  264. * The interrupt service routine used depends on whether the pre-emptive
  265. * scheduler is being used or not.
  266. */
  267. #if configUSE_PREEMPTION == 1
  268. /*
  269. * Tick ISR for preemptive scheduler. We can use a naked attribute as
  270. * the context is saved at the start of vPortYieldFromTick(). The tick
  271. * count is incremented after the context is saved.
  272. */
  273. interrupt( TIMERA0_VECTOR ) void prvTickISR( void ) __attribute__( ( naked ) );
  274. interrupt( TIMERA0_VECTOR ) void prvTickISR( void )
  275. {
  276. /* Save the context of the interrupted task. */
  277. portSAVE_CONTEXT();
  278. /* Increment the tick count then switch to the highest priority task
  279. * that is ready to run. */
  280. if( xTaskIncrementTick() != pdFALSE )
  281. {
  282. vTaskSwitchContext();
  283. }
  284. /* Restore the context of the new task. */
  285. portRESTORE_CONTEXT();
  286. }
  287. #else /* if configUSE_PREEMPTION == 1 */
  288. /*
  289. * Tick ISR for the cooperative scheduler. All this does is increment the
  290. * tick count. We don't need to switch context, this can only be done by
  291. * manual calls to taskYIELD();
  292. */
  293. interrupt( TIMERA0_VECTOR ) void prvTickISR( void );
  294. interrupt( TIMERA0_VECTOR ) void prvTickISR( void )
  295. {
  296. xTaskIncrementTick();
  297. }
  298. #endif /* if configUSE_PREEMPTION == 1 */