1 /* 2 * FreeRTOS Kernel V10.6.2 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 29 /*This file has been prepared for Doxygen automatic documentation generation.*/ 30 /*! \file ********************************************************************* 31 * 32 * \brief FreeRTOS port source for AVR32 UC3. 33 * 34 * - Compiler: GNU GCC for AVR32 35 * - Supported devices: All AVR32 devices can be used. 36 * - AppNote: 37 * 38 * \author Atmel Corporation (Now Microchip): 39 * https://www.microchip.com \n 40 * Support and FAQ: https://www.microchip.com/support/ 41 * 42 *****************************************************************************/ 43 44 /* 45 * Copyright (c) 2007, Atmel Corporation All rights reserved. 46 * 47 * Redistribution and use in source and binary forms, with or without 48 * modification, are permitted provided that the following conditions are met: 49 * 50 * 1. Redistributions of source code must retain the above copyright notice, 51 * this list of conditions and the following disclaimer. 52 * 53 * 2. Redistributions in binary form must reproduce the above copyright notice, 54 * this list of conditions and the following disclaimer in the documentation 55 * and/or other materials provided with the distribution. 56 * 57 * 3. The name of ATMEL may not be used to endorse or promote products derived 58 * from this software without specific prior written permission. 59 * 60 * THIS SOFTWARE IS PROVIDED BY ATMEL ``AS IS'' AND ANY EXPRESS OR IMPLIED 61 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 62 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY AND 63 * SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, 64 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 65 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 66 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 67 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 68 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 69 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 70 */ 71 72 #ifndef PORTMACRO_H 73 #define PORTMACRO_H 74 75 /*----------------------------------------------------------- 76 * Port specific definitions. 77 * 78 * The settings in this file configure FreeRTOS correctly for the 79 * given hardware and compiler. 80 * 81 * These settings should not be altered. 82 *----------------------------------------------------------- 83 */ 84 #include <avr32/io.h> 85 #include "intc.h" 86 #include "compiler.h" 87 88 /* *INDENT-OFF* */ 89 #ifdef __cplusplus 90 extern "C" { 91 #endif 92 /* *INDENT-ON* */ 93 94 95 /* Type definitions. */ 96 #define portCHAR char 97 #define portFLOAT float 98 #define portDOUBLE double 99 #define portLONG long 100 #define portSHORT short 101 #define portSTACK_TYPE uint32_t 102 #define portBASE_TYPE long 103 104 typedef portSTACK_TYPE StackType_t; 105 typedef long BaseType_t; 106 typedef unsigned long UBaseType_t; 107 108 #define TASK_DELAY_MS(x) ( (x) /portTICK_PERIOD_MS ) 109 #define TASK_DELAY_S(x) ( (x)*1000 /portTICK_PERIOD_MS ) 110 #define TASK_DELAY_MIN(x) ( (x)*60*1000/portTICK_PERIOD_MS ) 111 112 #define configTICK_TC_IRQ ATPASTE2(AVR32_TC_IRQ, configTICK_TC_CHANNEL) 113 114 #if( configTICK_TYPE_WIDTH_IN_BITS == TICK_TYPE_WIDTH_16_BITS ) 115 typedef uint16_t TickType_t; 116 #define portMAX_DELAY ( TickType_t ) 0xffff 117 #elif ( configTICK_TYPE_WIDTH_IN_BITS == TICK_TYPE_WIDTH_32_BITS ) 118 typedef uint32_t TickType_t; 119 #define portMAX_DELAY ( TickType_t ) ( 0xFFFFFFFFUL ) 120 #else 121 #error configTICK_TYPE_WIDTH_IN_BITS set to unsupported tick type width. 122 #endif 123 /*-----------------------------------------------------------*/ 124 125 /* Architecture specifics. */ 126 #define portSTACK_GROWTH ( -1 ) 127 #define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ ) 128 #define portBYTE_ALIGNMENT 4 129 #define portNOP() {__asm__ __volatile__ ("nop");} 130 /*-----------------------------------------------------------*/ 131 132 133 /*-----------------------------------------------------------*/ 134 135 /* INTC-specific. */ 136 #define DISABLE_ALL_EXCEPTIONS() Disable_global_exception() 137 #define ENABLE_ALL_EXCEPTIONS() Enable_global_exception() 138 139 #define DISABLE_ALL_INTERRUPTS() Disable_global_interrupt() 140 #define ENABLE_ALL_INTERRUPTS() Enable_global_interrupt() 141 142 #define DISABLE_INT_LEVEL(int_lev) Disable_interrupt_level(int_lev) 143 #define ENABLE_INT_LEVEL(int_lev) Enable_interrupt_level(int_lev) 144 145 146 /* 147 * Debug trace. 148 * Activated if and only if configDBG is nonzero. 149 * Prints a formatted string to stdout. 150 * The current source file name and line number are output with a colon before 151 * the formatted string. 152 * A carriage return and a linefeed are appended to the output. 153 * stdout is redirected to the USART configured by configDBG_USART. 154 * The parameters are the same as for the standard printf function. 155 * There is no return value. 156 * SHALL NOT BE CALLED FROM WITHIN AN INTERRUPT as fputs and printf use malloc, 157 * which is interrupt-unsafe with the current __malloc_lock and __malloc_unlock. 158 */ 159 #if configDBG 160 #define portDBG_TRACE(...) \ 161 {\ 162 fputs(__FILE__ ":" ASTRINGZ(__LINE__) ": ", stdout);\ 163 printf(__VA_ARGS__);\ 164 fputs("\r\n", stdout);\ 165 } 166 #else 167 #define portDBG_TRACE(...) 168 #endif 169 170 171 /* Critical section management. */ 172 #define portDISABLE_INTERRUPTS() DISABLE_ALL_INTERRUPTS() 173 #define portENABLE_INTERRUPTS() ENABLE_ALL_INTERRUPTS() 174 175 176 extern void vPortEnterCritical( void ); 177 extern void vPortExitCritical( void ); 178 179 #define portENTER_CRITICAL() vPortEnterCritical(); 180 #define portEXIT_CRITICAL() vPortExitCritical(); 181 182 183 /* Added as there is no such function in FreeRTOS. */ 184 extern void *pvPortRealloc( void *pv, size_t xSize ); 185 /*-----------------------------------------------------------*/ 186 187 188 /*=============================================================================================*/ 189 190 /* 191 * Restore Context for cases other than INTi. 192 */ 193 #define portRESTORE_CONTEXT() \ 194 { \ 195 extern volatile uint32_t ulCriticalNesting; \ 196 extern volatile void *volatile pxCurrentTCB; \ 197 \ 198 __asm__ __volatile__ ( \ 199 /* Set SP to point to new stack */ \ 200 "mov r8, LO(%[pxCurrentTCB]) \n\t"\ 201 "orh r8, HI(%[pxCurrentTCB]) \n\t"\ 202 "ld.w r0, r8[0] \n\t"\ 203 "ld.w sp, r0[0] \n\t"\ 204 \ 205 /* Restore ulCriticalNesting variable */ \ 206 "ld.w r0, sp++ \n\t"\ 207 "mov r8, LO(%[ulCriticalNesting]) \n\t"\ 208 "orh r8, HI(%[ulCriticalNesting]) \n\t"\ 209 "st.w r8[0], r0 \n\t"\ 210 \ 211 /* Restore R0..R7 */ \ 212 "ldm sp++, r0-r7 \n\t"\ 213 /* R0-R7 should not be used below this line */ \ 214 /* Skip PC and SR (will do it at the end) */ \ 215 "sub sp, -2*4 \n\t"\ 216 /* Restore R8..R12 and LR */ \ 217 "ldm sp++, r8-r12, lr \n\t"\ 218 /* Restore SR */ \ 219 "ld.w r0, sp[-8*4]\n\t" /* R0 is modified, is restored later. */ \ 220 "mtsr %[SR], r0 \n\t"\ 221 /* Restore r0 */ \ 222 "ld.w r0, sp[-9*4] \n\t"\ 223 /* Restore PC */ \ 224 "ld.w pc, sp[-7*4]" /* Get PC from stack - PC is the 7th register saved */ \ 225 : \ 226 : [ulCriticalNesting] "i" (&ulCriticalNesting), \ 227 [pxCurrentTCB] "i" (&pxCurrentTCB), \ 228 [SR] "i" (AVR32_SR) \ 229 ); \ 230 } 231 232 233 /* 234 * portSAVE_CONTEXT_INT() and portRESTORE_CONTEXT_INT(): for INT0..3 exceptions. 235 * portSAVE_CONTEXT_SCALL() and portRESTORE_CONTEXT_SCALL(): for the scall exception. 236 * 237 * Had to make different versions because registers saved on the system stack 238 * are not the same between INT0..3 exceptions and the scall exception. 239 */ 240 241 // Task context stack layout: 242 // R8 (*) 243 // R9 (*) 244 // R10 (*) 245 // R11 (*) 246 // R12 (*) 247 // R14/LR (*) 248 // R15/PC (*) 249 // SR (*) 250 // R0 251 // R1 252 // R2 253 // R3 254 // R4 255 // R5 256 // R6 257 // R7 258 // ulCriticalNesting 259 // (*) automatically done for INT0..INT3, but not for SCALL 260 261 /* 262 * The ISR used for the scheduler tick depends on whether the cooperative or 263 * the preemptive scheduler is being used. 264 */ 265 #if configUSE_PREEMPTION == 0 266 267 /* 268 * portSAVE_CONTEXT_OS_INT() for OS Tick exception. 269 */ 270 #define portSAVE_CONTEXT_OS_INT() \ 271 { \ 272 /* Save R0..R7 */ \ 273 __asm__ __volatile__ ("stm --sp, r0-r7"); \ 274 \ 275 /* With the cooperative scheduler, as there is no context switch by interrupt, */ \ 276 /* there is also no context save. */ \ 277 } 278 279 /* 280 * portRESTORE_CONTEXT_OS_INT() for Tick exception. 281 */ 282 #define portRESTORE_CONTEXT_OS_INT() \ 283 { \ 284 __asm__ __volatile__ ( \ 285 /* Restore R0..R7 */ \ 286 "ldm sp++, r0-r7\n\t" \ 287 \ 288 /* With the cooperative scheduler, as there is no context switch by interrupt, */ \ 289 /* there is also no context restore. */ \ 290 "rete" \ 291 ); \ 292 } 293 294 #else 295 296 /* 297 * portSAVE_CONTEXT_OS_INT() for OS Tick exception. 298 */ 299 #define portSAVE_CONTEXT_OS_INT() \ 300 { \ 301 extern volatile uint32_t ulCriticalNesting; \ 302 extern volatile void *volatile pxCurrentTCB; \ 303 \ 304 /* When we come here */ \ 305 /* Registers R8..R12, LR, PC and SR had already been pushed to system stack */ \ 306 \ 307 __asm__ __volatile__ ( \ 308 /* Save R0..R7 */ \ 309 "stm --sp, r0-r7 \n\t"\ 310 \ 311 /* Save ulCriticalNesting variable - R0 is overwritten */ \ 312 "mov r8, LO(%[ulCriticalNesting])\n\t" \ 313 "orh r8, HI(%[ulCriticalNesting])\n\t" \ 314 "ld.w r0, r8[0] \n\t"\ 315 "st.w --sp, r0 \n\t"\ 316 \ 317 /* Check if INT0 or higher were being handled (case where the OS tick interrupted another */ \ 318 /* interrupt handler (which was of a higher priority level but decided to lower its priority */ \ 319 /* level and allow other lower interrupt level to occur). */ \ 320 /* In this case we don't want to do a task switch because we don't know what the stack */ \ 321 /* currently looks like (we don't know what the interrupted interrupt handler was doing). */ \ 322 /* Saving SP in pxCurrentTCB and then later restoring it (thinking restoring the task) */ \ 323 /* will just be restoring the interrupt handler, no way!!! */ \ 324 /* So, since we won't do a vTaskSwitchContext(), it's of no use to save SP. */ \ 325 "ld.w r0, sp[9*4]\n\t" /* Read SR in stack */ \ 326 "bfextu r0, r0, 22, 3\n\t" /* Extract the mode bits to R0. */ \ 327 "cp.w r0, 1\n\t" /* Compare the mode bits with supervisor mode(b'001) */ \ 328 "brhi LABEL_INT_SKIP_SAVE_CONTEXT_%[LINE] \n\t"\ 329 \ 330 /* Store SP in the first member of the structure pointed to by pxCurrentTCB */ \ 331 /* NOTE: we don't enter a critical section here because all interrupt handlers */ \ 332 /* MUST perform a SAVE_CONTEXT/RESTORE_CONTEXT in the same way as */ \ 333 /* portSAVE_CONTEXT_OS_INT/port_RESTORE_CONTEXT_OS_INT if they call OS functions. */ \ 334 /* => all interrupt handlers must use portENTER_SWITCHING_ISR/portEXIT_SWITCHING_ISR. */ \ 335 "mov r8, LO(%[pxCurrentTCB])\n\t" \ 336 "orh r8, HI(%[pxCurrentTCB])\n\t" \ 337 "ld.w r0, r8[0]\n\t" \ 338 "st.w r0[0], sp\n" \ 339 \ 340 "LABEL_INT_SKIP_SAVE_CONTEXT_%[LINE]:" \ 341 : \ 342 : [ulCriticalNesting] "i" (&ulCriticalNesting), \ 343 [pxCurrentTCB] "i" (&pxCurrentTCB), \ 344 [LINE] "i" (__LINE__) \ 345 ); \ 346 } 347 348 /* 349 * portRESTORE_CONTEXT_OS_INT() for Tick exception. 350 */ 351 #define portRESTORE_CONTEXT_OS_INT() \ 352 { \ 353 extern volatile uint32_t ulCriticalNesting; \ 354 extern volatile void *volatile pxCurrentTCB; \ 355 \ 356 /* Check if INT0 or higher were being handled (case where the OS tick interrupted another */ \ 357 /* interrupt handler (which was of a higher priority level but decided to lower its priority */ \ 358 /* level and allow other lower interrupt level to occur). */ \ 359 /* In this case we don't want to do a task switch because we don't know what the stack */ \ 360 /* currently looks like (we don't know what the interrupted interrupt handler was doing). */ \ 361 /* Saving SP in pxCurrentTCB and then later restoring it (thinking restoring the task) */ \ 362 /* will just be restoring the interrupt handler, no way!!! */ \ 363 __asm__ __volatile__ ( \ 364 "ld.w r0, sp[9*4]\n\t" /* Read SR in stack */ \ 365 "bfextu r0, r0, 22, 3\n\t" /* Extract the mode bits to R0. */ \ 366 "cp.w r0, 1\n\t" /* Compare the mode bits with supervisor mode(b'001) */ \ 367 "brhi LABEL_INT_SKIP_RESTORE_CONTEXT_%[LINE]" \ 368 : \ 369 : [LINE] "i" (__LINE__) \ 370 ); \ 371 \ 372 /* Else */ \ 373 /* because it is here safe, always call vTaskSwitchContext() since an OS tick occurred. */ \ 374 /* A critical section has to be used here because vTaskSwitchContext handles FreeRTOS linked lists. */\ 375 portENTER_CRITICAL(); \ 376 vTaskSwitchContext(); \ 377 portEXIT_CRITICAL(); \ 378 \ 379 /* Restore all registers */ \ 380 \ 381 __asm__ __volatile__ ( \ 382 /* Set SP to point to new stack */ \ 383 "mov r8, LO(%[pxCurrentTCB]) \n\t"\ 384 "orh r8, HI(%[pxCurrentTCB]) \n\t"\ 385 "ld.w r0, r8[0] \n\t"\ 386 "ld.w sp, r0[0] \n"\ 387 \ 388 "LABEL_INT_SKIP_RESTORE_CONTEXT_%[LINE]: \n\t"\ 389 \ 390 /* Restore ulCriticalNesting variable */ \ 391 "ld.w r0, sp++ \n\t" \ 392 "mov r8, LO(%[ulCriticalNesting]) \n\t"\ 393 "orh r8, HI(%[ulCriticalNesting]) \n\t"\ 394 "st.w r8[0], r0 \n\t"\ 395 \ 396 /* Restore R0..R7 */ \ 397 "ldm sp++, r0-r7 \n\t"\ 398 \ 399 /* Now, the stack should be R8..R12, LR, PC and SR */ \ 400 "rete" \ 401 : \ 402 : [ulCriticalNesting] "i" (&ulCriticalNesting), \ 403 [pxCurrentTCB] "i" (&pxCurrentTCB), \ 404 [LINE] "i" (__LINE__) \ 405 ); \ 406 } 407 408 #endif 409 410 411 /* 412 * portSAVE_CONTEXT_SCALL() for SupervisorCALL exception. 413 * 414 * NOTE: taskYIELD()(== SCALL) MUST NOT be called in a mode > supervisor mode. 415 * 416 */ 417 #define portSAVE_CONTEXT_SCALL() \ 418 { \ 419 extern volatile uint32_t ulCriticalNesting; \ 420 extern volatile void *volatile pxCurrentTCB; \ 421 \ 422 /* Warning: the stack layout after SCALL doesn't match the one after an interrupt. */ \ 423 /* If SR[M2:M0] == 001 */ \ 424 /* PC and SR are on the stack. */ \ 425 /* Else (other modes) */ \ 426 /* Nothing on the stack. */ \ 427 \ 428 /* WARNING NOTE: the else case cannot happen as it is strictly forbidden to call */ \ 429 /* vTaskDelay() and vTaskDelayUntil() OS functions (that result in a taskYield()) */ \ 430 /* in an interrupt|exception handler. */ \ 431 \ 432 __asm__ __volatile__ ( \ 433 /* in order to save R0-R7 */ \ 434 "sub sp, 6*4 \n\t"\ 435 /* Save R0..R7 */ \ 436 "stm --sp, r0-r7 \n\t"\ 437 \ 438 /* in order to save R8-R12 and LR */ \ 439 /* do not use SP if interrupts occurs, SP must be left at bottom of stack */ \ 440 "sub r7, sp,-16*4 \n\t"\ 441 /* Copy PC and SR in other places in the stack. */ \ 442 "ld.w r0, r7[-2*4] \n\t" /* Read SR */\ 443 "st.w r7[-8*4], r0 \n\t" /* Copy SR */\ 444 "ld.w r0, r7[-1*4] \n\t" /* Read PC */\ 445 "st.w r7[-7*4], r0 \n\t" /* Copy PC */\ 446 \ 447 /* Save R8..R12 and LR on the stack. */ \ 448 "stm --r7, r8-r12, lr \n\t"\ 449 \ 450 /* Arriving here we have the following stack organizations: */ \ 451 /* R8..R12, LR, PC, SR, R0..R7. */ \ 452 \ 453 /* Now we can finalize the save. */ \ 454 \ 455 /* Save ulCriticalNesting variable - R0 is overwritten */ \ 456 "mov r8, LO(%[ulCriticalNesting]) \n\t"\ 457 "orh r8, HI(%[ulCriticalNesting]) \n\t"\ 458 "ld.w r0, r8[0] \n\t"\ 459 "st.w --sp, r0" \ 460 : \ 461 : [ulCriticalNesting] "i" (&ulCriticalNesting) \ 462 ); \ 463 \ 464 /* Disable the its which may cause a context switch (i.e. cause a change of */ \ 465 /* pxCurrentTCB). */ \ 466 /* Basically, all accesses to the pxCurrentTCB structure should be put in a */ \ 467 /* critical section because it is a global structure. */ \ 468 portENTER_CRITICAL(); \ 469 \ 470 /* Store SP in the first member of the structure pointed to by pxCurrentTCB */ \ 471 __asm__ __volatile__ ( \ 472 "mov r8, LO(%[pxCurrentTCB]) \n\t"\ 473 "orh r8, HI(%[pxCurrentTCB]) \n\t"\ 474 "ld.w r0, r8[0] \n\t"\ 475 "st.w r0[0], sp" \ 476 : \ 477 : [pxCurrentTCB] "i" (&pxCurrentTCB) \ 478 ); \ 479 } 480 481 /* 482 * portRESTORE_CONTEXT() for SupervisorCALL exception. 483 */ 484 #define portRESTORE_CONTEXT_SCALL() \ 485 { \ 486 extern volatile uint32_t ulCriticalNesting; \ 487 extern volatile void *volatile pxCurrentTCB; \ 488 \ 489 /* Restore all registers */ \ 490 \ 491 /* Set SP to point to new stack */ \ 492 __asm__ __volatile__ ( \ 493 "mov r8, LO(%[pxCurrentTCB]) \n\t"\ 494 "orh r8, HI(%[pxCurrentTCB]) \n\t"\ 495 "ld.w r0, r8[0] \n\t"\ 496 "ld.w sp, r0[0]" \ 497 : \ 498 : [pxCurrentTCB] "i" (&pxCurrentTCB) \ 499 ); \ 500 \ 501 /* Leave pxCurrentTCB variable access critical section */ \ 502 portEXIT_CRITICAL(); \ 503 \ 504 __asm__ __volatile__ ( \ 505 /* Restore ulCriticalNesting variable */ \ 506 "ld.w r0, sp++ \n\t"\ 507 "mov r8, LO(%[ulCriticalNesting]) \n\t"\ 508 "orh r8, HI(%[ulCriticalNesting]) \n\t"\ 509 "st.w r8[0], r0 \n\t"\ 510 \ 511 /* skip PC and SR */ \ 512 /* do not use SP if interrupts occurs, SP must be left at bottom of stack */ \ 513 "sub r7, sp, -10*4 \n\t"\ 514 /* Restore r8-r12 and LR */ \ 515 "ldm r7++, r8-r12, lr \n\t"\ 516 \ 517 /* RETS will take care of the extra PC and SR restore. */ \ 518 /* So, we have to prepare the stack for this. */ \ 519 "ld.w r0, r7[-8*4] \n\t" /* Read SR */\ 520 "st.w r7[-2*4], r0 \n\t" /* Copy SR */\ 521 "ld.w r0, r7[-7*4] \n\t" /* Read PC */\ 522 "st.w r7[-1*4], r0 \n\t" /* Copy PC */\ 523 \ 524 /* Restore R0..R7 */ \ 525 "ldm sp++, r0-r7 \n\t"\ 526 \ 527 "sub sp, -6*4 \n\t"\ 528 \ 529 "rets" \ 530 : \ 531 : [ulCriticalNesting] "i" (&ulCriticalNesting) \ 532 ); \ 533 } 534 535 536 /* 537 * The ISR used depends on whether the cooperative or 538 * the preemptive scheduler is being used. 539 */ 540 #if configUSE_PREEMPTION == 0 541 542 /* 543 * ISR entry and exit macros. These are only required if a task switch 544 * is required from the ISR. 545 */ 546 #define portENTER_SWITCHING_ISR() \ 547 { \ 548 /* Save R0..R7 */ \ 549 __asm__ __volatile__ ("stm --sp, r0-r7"); \ 550 \ 551 /* With the cooperative scheduler, as there is no context switch by interrupt, */ \ 552 /* there is also no context save. */ \ 553 } 554 555 /* 556 * Input parameter: in R12, boolean. Perform a vTaskSwitchContext() if 1 557 */ 558 #define portEXIT_SWITCHING_ISR() \ 559 { \ 560 __asm__ __volatile__ ( \ 561 /* Restore R0..R7 */ \ 562 "ldm sp++, r0-r7 \n\t"\ 563 \ 564 /* With the cooperative scheduler, as there is no context switch by interrupt, */ \ 565 /* there is also no context restore. */ \ 566 "rete" \ 567 ); \ 568 } 569 570 #else 571 572 /* 573 * ISR entry and exit macros. These are only required if a task switch 574 * is required from the ISR. 575 */ 576 #define portENTER_SWITCHING_ISR() \ 577 { \ 578 extern volatile uint32_t ulCriticalNesting; \ 579 extern volatile void *volatile pxCurrentTCB; \ 580 \ 581 /* When we come here */ \ 582 /* Registers R8..R12, LR, PC and SR had already been pushed to system stack */ \ 583 \ 584 __asm__ __volatile__ ( \ 585 /* Save R0..R7 */ \ 586 "stm --sp, r0-r7 \n\t"\ 587 \ 588 /* Save ulCriticalNesting variable - R0 is overwritten */ \ 589 "mov r8, LO(%[ulCriticalNesting]) \n\t"\ 590 "orh r8, HI(%[ulCriticalNesting]) \n\t"\ 591 "ld.w r0, r8[0] \n\t"\ 592 "st.w --sp, r0 \n\t"\ 593 \ 594 /* Check if INT0 or higher were being handled (case where the OS tick interrupted another */ \ 595 /* interrupt handler (which was of a higher priority level but decided to lower its priority */ \ 596 /* level and allow other lower interrupt level to occur). */ \ 597 /* In this case we don't want to do a task switch because we don't know what the stack */ \ 598 /* currently looks like (we don't know what the interrupted interrupt handler was doing). */ \ 599 /* Saving SP in pxCurrentTCB and then later restoring it (thinking restoring the task) */ \ 600 /* will just be restoring the interrupt handler, no way!!! */ \ 601 /* So, since we won't do a vTaskSwitchContext(), it's of no use to save SP. */ \ 602 "ld.w r0, sp[9*4] \n\t" /* Read SR in stack */\ 603 "bfextu r0, r0, 22, 3 \n\t" /* Extract the mode bits to R0. */\ 604 "cp.w r0, 1 \n\t" /* Compare the mode bits with supervisor mode(b'001) */\ 605 "brhi LABEL_ISR_SKIP_SAVE_CONTEXT_%[LINE] \n\t"\ 606 \ 607 /* Store SP in the first member of the structure pointed to by pxCurrentTCB */ \ 608 "mov r8, LO(%[pxCurrentTCB]) \n\t"\ 609 "orh r8, HI(%[pxCurrentTCB]) \n\t"\ 610 "ld.w r0, r8[0] \n\t"\ 611 "st.w r0[0], sp \n"\ 612 \ 613 "LABEL_ISR_SKIP_SAVE_CONTEXT_%[LINE]:" \ 614 : \ 615 : [ulCriticalNesting] "i" (&ulCriticalNesting), \ 616 [pxCurrentTCB] "i" (&pxCurrentTCB), \ 617 [LINE] "i" (__LINE__) \ 618 ); \ 619 } 620 621 /* 622 * Input parameter: in R12, boolean. Perform a vTaskSwitchContext() if 1 623 */ 624 #define portEXIT_SWITCHING_ISR() \ 625 { \ 626 extern volatile uint32_t ulCriticalNesting; \ 627 extern volatile void *volatile pxCurrentTCB; \ 628 \ 629 __asm__ __volatile__ ( \ 630 /* Check if INT0 or higher were being handled (case where the OS tick interrupted another */ \ 631 /* interrupt handler (which was of a higher priority level but decided to lower its priority */ \ 632 /* level and allow other lower interrupt level to occur). */ \ 633 /* In this case it's of no use to switch context and restore a new SP because we purposedly */ \ 634 /* did not previously save SP in its TCB. */ \ 635 "ld.w r0, sp[9*4] \n\t" /* Read SR in stack */\ 636 "bfextu r0, r0, 22, 3 \n\t" /* Extract the mode bits to R0. */\ 637 "cp.w r0, 1 \n\t" /* Compare the mode bits with supervisor mode(b'001) */\ 638 "brhi LABEL_ISR_SKIP_RESTORE_CONTEXT_%[LINE] \n\t"\ 639 \ 640 /* If a switch is required then we just need to call */ \ 641 /* vTaskSwitchContext() as the context has already been */ \ 642 /* saved. */ \ 643 "cp.w r12, 1 \n\t" /* Check if Switch context is required. */\ 644 "brne LABEL_ISR_RESTORE_CONTEXT_%[LINE]" \ 645 : \ 646 : [LINE] "i" (__LINE__) \ 647 ); \ 648 \ 649 /* A critical section has to be used here because vTaskSwitchContext handles FreeRTOS linked lists. */ \ 650 portENTER_CRITICAL(); \ 651 vTaskSwitchContext(); \ 652 portEXIT_CRITICAL(); \ 653 \ 654 __asm__ __volatile__ ( \ 655 "LABEL_ISR_RESTORE_CONTEXT_%[LINE]: \n\t"\ 656 /* Restore the context of which ever task is now the highest */ \ 657 /* priority that is ready to run. */ \ 658 \ 659 /* Restore all registers */ \ 660 \ 661 /* Set SP to point to new stack */ \ 662 "mov r8, LO(%[pxCurrentTCB]) \n\t"\ 663 "orh r8, HI(%[pxCurrentTCB]) \n\t"\ 664 "ld.w r0, r8[0] \n\t"\ 665 "ld.w sp, r0[0] \n"\ 666 \ 667 "LABEL_ISR_SKIP_RESTORE_CONTEXT_%[LINE]: \n\t"\ 668 \ 669 /* Restore ulCriticalNesting variable */ \ 670 "ld.w r0, sp++ \n\t"\ 671 "mov r8, LO(%[ulCriticalNesting]) \n\t"\ 672 "orh r8, HI(%[ulCriticalNesting]) \n\t"\ 673 "st.w r8[0], r0 \n\t"\ 674 \ 675 /* Restore R0..R7 */ \ 676 "ldm sp++, r0-r7 \n\t"\ 677 \ 678 /* Now, the stack should be R8..R12, LR, PC and SR */ \ 679 "rete" \ 680 : \ 681 : [ulCriticalNesting] "i" (&ulCriticalNesting), \ 682 [pxCurrentTCB] "i" (&pxCurrentTCB), \ 683 [LINE] "i" (__LINE__) \ 684 ); \ 685 } 686 687 #endif 688 689 690 #define portYIELD() {__asm__ __volatile__ ("scall");} 691 692 /* Task function macros as described on the FreeRTOS.org WEB site. */ 693 #define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters ) 694 #define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters ) 695 696 /* *INDENT-OFF* */ 697 #ifdef __cplusplus 698 } 699 #endif 700 /* *INDENT-ON* */ 701 702 #endif /* PORTMACRO_H */ 703