port.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  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 AND BSD-3-Clause
  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. /*This file has been prepared for Doxygen automatic documentation generation.*/
  29. /*! \file *********************************************************************
  30. *
  31. * \brief FreeRTOS port source for AVR32 UC3.
  32. *
  33. * - Compiler: GNU GCC for AVR32
  34. * - Supported devices: All AVR32 devices can be used.
  35. * - AppNote:
  36. *
  37. * \author Atmel Corporation (Now Microchip):
  38. * https://www.microchip.com \n
  39. * Support and FAQ: https://www.microchip.com/support/
  40. *
  41. *****************************************************************************/
  42. /*
  43. * Copyright (c) 2007, Atmel Corporation All rights reserved.
  44. *
  45. * Redistribution and use in source and binary forms, with or without
  46. * modification, are permitted provided that the following conditions are met:
  47. *
  48. * 1. Redistributions of source code must retain the above copyright notice,
  49. * this list of conditions and the following disclaimer.
  50. *
  51. * 2. Redistributions in binary form must reproduce the above copyright notice,
  52. * this list of conditions and the following disclaimer in the documentation
  53. * and/or other materials provided with the distribution.
  54. *
  55. * 3. The name of ATMEL may not be used to endorse or promote products derived
  56. * from this software without specific prior written permission.
  57. *
  58. * THIS SOFTWARE IS PROVIDED BY ATMEL ``AS IS'' AND ANY EXPRESS OR IMPLIED
  59. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  60. * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY AND
  61. * SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT,
  62. * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  63. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  64. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  65. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  66. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  67. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  68. */
  69. /* Standard includes. */
  70. #include <sys/cpu.h>
  71. #include <sys/usart.h>
  72. #include <malloc.h>
  73. /* Scheduler includes. */
  74. #include "FreeRTOS.h"
  75. #include "task.h"
  76. /* AVR32 UC3 includes. */
  77. #include <avr32/io.h>
  78. #include "gpio.h"
  79. #if ( configTICK_USE_TC == 1 )
  80. #include "tc.h"
  81. #endif
  82. /* Constants required to setup the task context. */
  83. #define portINITIAL_SR ( ( StackType_t ) 0x00400000 ) /* AVR32 : [M2:M0]=001 I1M=0 I0M=0, GM=0 */
  84. #define portINSTRUCTION_SIZE ( ( StackType_t ) 0 )
  85. /* Each task maintains its own critical nesting variable. */
  86. #define portNO_CRITICAL_NESTING ( ( uint32_t ) 0 )
  87. volatile uint32_t ulCriticalNesting = 9999UL;
  88. #if ( configTICK_USE_TC == 0 )
  89. static void prvScheduleNextTick( void );
  90. #else
  91. static void prvClearTcInt( void );
  92. #endif
  93. /* Setup the timer to generate the tick interrupts. */
  94. static void prvSetupTimerInterrupt( void );
  95. /*-----------------------------------------------------------*/
  96. /*
  97. * Low-level initialization routine called during startup, before the main
  98. * function.
  99. * This version comes in replacement to the default one provided by Newlib.
  100. * Newlib's _init_startup only calls init_exceptions, but Newlib's exception
  101. * vectors are not compatible with the SCALL management in the current FreeRTOS
  102. * port. More low-level initializations are besides added here.
  103. */
  104. void _init_startup( void )
  105. {
  106. /* Import the Exception Vector Base Address. */
  107. extern void _evba;
  108. #if configHEAP_INIT
  109. extern void __heap_start__;
  110. extern void __heap_end__;
  111. BaseType_t * pxMem;
  112. #endif
  113. /* Load the Exception Vector Base Address in the corresponding system register. */
  114. Set_system_register( AVR32_EVBA, ( int ) &_evba );
  115. /* Enable exceptions. */
  116. ENABLE_ALL_EXCEPTIONS();
  117. /* Initialize interrupt handling. */
  118. INTC_init_interrupts();
  119. #if configHEAP_INIT
  120. /* Initialize the heap used by malloc. */
  121. for( pxMem = &__heap_start__; pxMem < ( BaseType_t * ) &__heap_end__; )
  122. {
  123. *pxMem++ = 0xA5A5A5A5;
  124. }
  125. #endif
  126. /* Give the used CPU clock frequency to Newlib, so it can work properly. */
  127. set_cpu_hz( configCPU_CLOCK_HZ );
  128. /* Code section present if and only if the debug trace is activated. */
  129. #if configDBG
  130. {
  131. static const gpio_map_t DBG_USART_GPIO_MAP =
  132. {
  133. { configDBG_USART_RX_PIN, configDBG_USART_RX_FUNCTION },
  134. { configDBG_USART_TX_PIN, configDBG_USART_TX_FUNCTION }
  135. };
  136. /* Initialize the USART used for the debug trace with the configured parameters. */
  137. set_usart_base( ( void * ) configDBG_USART );
  138. gpio_enable_module( DBG_USART_GPIO_MAP,
  139. sizeof( DBG_USART_GPIO_MAP ) / sizeof( DBG_USART_GPIO_MAP[ 0 ] ) );
  140. usart_init( configDBG_USART_BAUDRATE );
  141. }
  142. #endif /* if configDBG */
  143. }
  144. /*-----------------------------------------------------------*/
  145. /*
  146. * malloc, realloc and free are meant to be called through respectively
  147. * pvPortMalloc, pvPortRealloc and vPortFree.
  148. * The latter functions call the former ones from within sections where tasks
  149. * are suspended, so the latter functions are task-safe. __malloc_lock and
  150. * __malloc_unlock use the same mechanism to also keep the former functions
  151. * task-safe as they may be called directly from Newlib's functions.
  152. * However, all these functions are interrupt-unsafe and SHALL THEREFORE NOT BE
  153. * CALLED FROM WITHIN AN INTERRUPT, because __malloc_lock and __malloc_unlock do
  154. * not call portENTER_CRITICAL and portEXIT_CRITICAL in order not to disable
  155. * interrupts during memory allocation management as this may be a very time-
  156. * consuming process.
  157. */
  158. /*
  159. * Lock routine called by Newlib on malloc / realloc / free entry to guarantee a
  160. * safe section as memory allocation management uses global data.
  161. * See the aforementioned details.
  162. */
  163. void __malloc_lock( struct _reent * ptr )
  164. {
  165. vTaskSuspendAll();
  166. }
  167. /*
  168. * Unlock routine called by Newlib on malloc / realloc / free exit to guarantee
  169. * a safe section as memory allocation management uses global data.
  170. * See the aforementioned details.
  171. */
  172. void __malloc_unlock( struct _reent * ptr )
  173. {
  174. xTaskResumeAll();
  175. }
  176. /*-----------------------------------------------------------*/
  177. /* Added as there is no such function in FreeRTOS. */
  178. void * pvPortRealloc( void * pv,
  179. size_t xWantedSize )
  180. {
  181. void * pvReturn;
  182. vTaskSuspendAll();
  183. {
  184. pvReturn = realloc( pv, xWantedSize );
  185. }
  186. xTaskResumeAll();
  187. return pvReturn;
  188. }
  189. /*-----------------------------------------------------------*/
  190. /* The cooperative scheduler requires a normal IRQ service routine to
  191. * simply increment the system tick. */
  192. /* The preemptive scheduler is defined as "naked" as the full context is saved
  193. * on entry as part of the context switch. */
  194. __attribute__( ( __naked__ ) ) static void vTick( void )
  195. {
  196. /* Save the context of the interrupted task. */
  197. portSAVE_CONTEXT_OS_INT();
  198. #if ( configTICK_USE_TC == 1 )
  199. /* Clear the interrupt flag. */
  200. prvClearTcInt();
  201. #else
  202. /* Schedule the COUNT&COMPARE match interrupt in (configCPU_CLOCK_HZ/configTICK_RATE_HZ)
  203. * clock cycles from now. */
  204. prvScheduleNextTick();
  205. #endif
  206. /* Because FreeRTOS is not supposed to run with nested interrupts, put all OS
  207. * calls in a critical section . */
  208. portENTER_CRITICAL();
  209. xTaskIncrementTick();
  210. portEXIT_CRITICAL();
  211. /* Restore the context of the "elected task". */
  212. portRESTORE_CONTEXT_OS_INT();
  213. }
  214. /*-----------------------------------------------------------*/
  215. __attribute__( ( __naked__ ) ) void SCALLYield( void )
  216. {
  217. /* Save the context of the interrupted task. */
  218. portSAVE_CONTEXT_SCALL();
  219. vTaskSwitchContext();
  220. portRESTORE_CONTEXT_SCALL();
  221. }
  222. /*-----------------------------------------------------------*/
  223. /* The code generated by the GCC compiler uses the stack in different ways at
  224. * different optimisation levels. The interrupt flags can therefore not always
  225. * be saved to the stack. Instead the critical section nesting level is stored
  226. * in a variable, which is then saved as part of the stack context. */
  227. __attribute__( ( __noinline__ ) ) void vPortEnterCritical( void )
  228. {
  229. /* Disable interrupts */
  230. portDISABLE_INTERRUPTS();
  231. /* Now that interrupts are disabled, ulCriticalNesting can be accessed
  232. * directly. Increment ulCriticalNesting to keep a count of how many times
  233. * portENTER_CRITICAL() has been called. */
  234. ulCriticalNesting++;
  235. }
  236. /*-----------------------------------------------------------*/
  237. __attribute__( ( __noinline__ ) ) void vPortExitCritical( void )
  238. {
  239. if( ulCriticalNesting > portNO_CRITICAL_NESTING )
  240. {
  241. ulCriticalNesting--;
  242. if( ulCriticalNesting == portNO_CRITICAL_NESTING )
  243. {
  244. /* Enable all interrupt/exception. */
  245. portENABLE_INTERRUPTS();
  246. }
  247. }
  248. }
  249. /*-----------------------------------------------------------*/
  250. /*
  251. * Initialise the stack of a task to look exactly as if a call to
  252. * portSAVE_CONTEXT had been called.
  253. *
  254. * See header file for description.
  255. */
  256. StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
  257. TaskFunction_t pxCode,
  258. void * pvParameters )
  259. {
  260. /* Setup the initial stack of the task. The stack is set exactly as
  261. * expected by the portRESTORE_CONTEXT() macro. */
  262. /* When the task starts, it will expect to find the function parameter in R12. */
  263. pxTopOfStack--;
  264. *pxTopOfStack-- = ( StackType_t ) 0x08080808; /* R8 */
  265. *pxTopOfStack-- = ( StackType_t ) 0x09090909; /* R9 */
  266. *pxTopOfStack-- = ( StackType_t ) 0x0A0A0A0A; /* R10 */
  267. *pxTopOfStack-- = ( StackType_t ) 0x0B0B0B0B; /* R11 */
  268. *pxTopOfStack-- = ( StackType_t ) pvParameters; /* R12 */
  269. *pxTopOfStack-- = ( StackType_t ) 0xDEADBEEF; /* R14/LR */
  270. *pxTopOfStack-- = ( StackType_t ) pxCode + portINSTRUCTION_SIZE; /* R15/PC */
  271. *pxTopOfStack-- = ( StackType_t ) portINITIAL_SR; /* SR */
  272. *pxTopOfStack-- = ( StackType_t ) 0xFF0000FF; /* R0 */
  273. *pxTopOfStack-- = ( StackType_t ) 0x01010101; /* R1 */
  274. *pxTopOfStack-- = ( StackType_t ) 0x02020202; /* R2 */
  275. *pxTopOfStack-- = ( StackType_t ) 0x03030303; /* R3 */
  276. *pxTopOfStack-- = ( StackType_t ) 0x04040404; /* R4 */
  277. *pxTopOfStack-- = ( StackType_t ) 0x05050505; /* R5 */
  278. *pxTopOfStack-- = ( StackType_t ) 0x06060606; /* R6 */
  279. *pxTopOfStack-- = ( StackType_t ) 0x07070707; /* R7 */
  280. *pxTopOfStack = ( StackType_t ) portNO_CRITICAL_NESTING; /* ulCriticalNesting */
  281. return pxTopOfStack;
  282. }
  283. /*-----------------------------------------------------------*/
  284. BaseType_t xPortStartScheduler( void )
  285. {
  286. /* Start the timer that generates the tick ISR. Interrupts are disabled
  287. * here already. */
  288. prvSetupTimerInterrupt();
  289. /* Start the first task. */
  290. portRESTORE_CONTEXT();
  291. /* Should not get here! */
  292. return 0;
  293. }
  294. /*-----------------------------------------------------------*/
  295. void vPortEndScheduler( void )
  296. {
  297. /* It is unlikely that the AVR32 port will require this function as there
  298. * is nothing to return to. */
  299. }
  300. /*-----------------------------------------------------------*/
  301. /* Schedule the COUNT&COMPARE match interrupt in (configCPU_CLOCK_HZ/configTICK_RATE_HZ)
  302. * clock cycles from now. */
  303. #if ( configTICK_USE_TC == 0 )
  304. static void prvScheduleFirstTick( void )
  305. {
  306. uint32_t lCycles;
  307. lCycles = Get_system_register( AVR32_COUNT );
  308. lCycles += ( configCPU_CLOCK_HZ / configTICK_RATE_HZ );
  309. /* If lCycles ends up to be 0, make it 1 so that the COMPARE and exception */
  310. /* generation feature does not get disabled. */
  311. if( 0 == lCycles )
  312. {
  313. lCycles++;
  314. }
  315. Set_system_register( AVR32_COMPARE, lCycles );
  316. }
  317. __attribute__( ( __noinline__ ) ) static void prvScheduleNextTick( void )
  318. {
  319. uint32_t lCycles, lCount;
  320. lCycles = Get_system_register( AVR32_COMPARE );
  321. lCycles += ( configCPU_CLOCK_HZ / configTICK_RATE_HZ );
  322. /* If lCycles ends up to be 0, make it 1 so that the COMPARE and exception */
  323. /* generation feature does not get disabled. */
  324. if( 0 == lCycles )
  325. {
  326. lCycles++;
  327. }
  328. lCount = Get_system_register( AVR32_COUNT );
  329. if( lCycles < lCount )
  330. { /* We missed a tick, recover for the next. */
  331. lCycles += ( configCPU_CLOCK_HZ / configTICK_RATE_HZ );
  332. }
  333. Set_system_register( AVR32_COMPARE, lCycles );
  334. }
  335. #else /* if ( configTICK_USE_TC == 0 ) */
  336. __attribute__( ( __noinline__ ) ) static void prvClearTcInt( void )
  337. {
  338. AVR32_TC.channel[ configTICK_TC_CHANNEL ].sr;
  339. }
  340. #endif /* if ( configTICK_USE_TC == 0 ) */
  341. /*-----------------------------------------------------------*/
  342. /* Setup the timer to generate the tick interrupts. */
  343. static void prvSetupTimerInterrupt( void )
  344. {
  345. #if ( configTICK_USE_TC == 1 )
  346. volatile avr32_tc_t * tc = &AVR32_TC;
  347. /* Options for waveform generation. */
  348. tc_waveform_opt_t waveform_opt =
  349. {
  350. .channel = configTICK_TC_CHANNEL, /* Channel selection. */
  351. .bswtrg = TC_EVT_EFFECT_NOOP, /* Software trigger effect on TIOB. */
  352. .beevt = TC_EVT_EFFECT_NOOP, /* External event effect on TIOB. */
  353. .bcpc = TC_EVT_EFFECT_NOOP, /* RC compare effect on TIOB. */
  354. .bcpb = TC_EVT_EFFECT_NOOP, /* RB compare effect on TIOB. */
  355. .aswtrg = TC_EVT_EFFECT_NOOP, /* Software trigger effect on TIOA. */
  356. .aeevt = TC_EVT_EFFECT_NOOP, /* External event effect on TIOA. */
  357. .acpc = TC_EVT_EFFECT_NOOP, /* RC compare effect on TIOA: toggle. */
  358. .acpa = TC_EVT_EFFECT_NOOP, /* RA compare effect on TIOA: toggle (other possibilities are none, set and clear). */
  359. .wavsel = TC_WAVEFORM_SEL_UP_MODE_RC_TRIGGER, /* Waveform selection: Up mode without automatic trigger on RC compare. */
  360. .enetrg = FALSE, /* External event trigger enable. */
  361. .eevt = 0, /* External event selection. */
  362. .eevtedg = TC_SEL_NO_EDGE, /* External event edge selection. */
  363. .cpcdis = FALSE, /* Counter disable when RC compare. */
  364. .cpcstop = FALSE, /* Counter clock stopped with RC compare. */
  365. .burst = FALSE, /* Burst signal selection. */
  366. .clki = FALSE, /* Clock inversion. */
  367. .tcclks = TC_CLOCK_SOURCE_TC2 /* Internal source clock 2. */
  368. };
  369. tc_interrupt_t tc_interrupt =
  370. {
  371. .etrgs = 0,
  372. .ldrbs = 0,
  373. .ldras = 0,
  374. .cpcs = 1,
  375. .cpbs = 0,
  376. .cpas = 0,
  377. .lovrs = 0,
  378. .covfs = 0,
  379. };
  380. #endif /* if ( configTICK_USE_TC == 1 ) */
  381. /* Disable all interrupt/exception. */
  382. portDISABLE_INTERRUPTS();
  383. /* Register the compare interrupt handler to the interrupt controller and
  384. * enable the compare interrupt. */
  385. #if ( configTICK_USE_TC == 1 )
  386. {
  387. INTC_register_interrupt( &vTick, configTICK_TC_IRQ, INT0 );
  388. /* Initialize the timer/counter. */
  389. tc_init_waveform( tc, &waveform_opt );
  390. /* Set the compare triggers.
  391. * Remember TC counter is 16-bits, so counting second is not possible!
  392. * That's why we configure it to count ms. */
  393. tc_write_rc( tc, configTICK_TC_CHANNEL, ( configPBA_CLOCK_HZ / 4 ) / configTICK_RATE_HZ );
  394. tc_configure_interrupts( tc, configTICK_TC_CHANNEL, &tc_interrupt );
  395. /* Start the timer/counter. */
  396. tc_start( tc, configTICK_TC_CHANNEL );
  397. }
  398. #else /* if ( configTICK_USE_TC == 1 ) */
  399. {
  400. INTC_register_interrupt( &vTick, AVR32_CORE_COMPARE_IRQ, INT0 );
  401. prvScheduleFirstTick();
  402. }
  403. #endif /* if ( configTICK_USE_TC == 1 ) */
  404. }