/* * FreeRTOS Kernel V10.2.1 * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * http://www.FreeRTOS.org * http://aws.amazon.com/freertos * * 1 tab == 4 spaces! */ /* Changes from V3.0.0 Changes from V3.0.1 */ #ifndef PORTMACRO_H #define PORTMACRO_H #if !defined(_SERIES) || _SERIES != 18 #error "WizC supports FreeRTOS on the Microchip PIC18-series only" #endif #if !defined(QUICKCALL) || QUICKCALL != 1 #error "QuickCall must be enabled (see ProjectOptions/Optimisations)" #endif #include #include #define portCHAR char #define portFLOAT float #define portDOUBLE portFLOAT #define portLONG long #define portSHORT short #define portSTACK_TYPE uint8_t #define portBASE_TYPE char typedef portSTACK_TYPE StackType_t; typedef signed char BaseType_t; typedef unsigned char UBaseType_t; #if( configUSE_16_BIT_TICKS == 1 ) typedef uint16_t TickType_t; #define portMAX_DELAY ( TickType_t ) ( 0xFFFF ) #else typedef uint32_t TickType_t; #define portMAX_DELAY ( TickType_t ) ( 0xFFFFFFFF ) #endif #define portBYTE_ALIGNMENT 1 /*-----------------------------------------------------------*/ /* * Constant used for context switch macro when we require the interrupt * enable state to be forced when the interrupted task is switched back in. */ #define portINTERRUPTS_FORCED (0x01) /* * Constant used for context switch macro when we require the interrupt * enable state to be unchanged when the interrupted task is switched back in. */ #define portINTERRUPTS_UNCHANGED (0x00) /* Initial interrupt enable state for newly created tasks. This value is * used when a task switches in for the first time. */ #define portINTERRUPTS_INITIAL_STATE (portINTERRUPTS_FORCED) /* * Macros to modify the global interrupt enable bit in INTCON. */ #define portDISABLE_INTERRUPTS() \ do \ { \ bGIE=0; \ } while(bGIE) // MicroChip recommends this check! #define portENABLE_INTERRUPTS() \ do \ { \ bGIE=1; \ } while(0) /*-----------------------------------------------------------*/ /* * Critical section macros. */ extern uint8_t ucCriticalNesting; #define portNO_CRITICAL_SECTION_NESTING ( ( uint8_t ) 0 ) #define portENTER_CRITICAL() \ do \ { \ portDISABLE_INTERRUPTS(); \ \ /* \ * Now interrupts are disabled ucCriticalNesting \ * can be accessed directly. Increment \ * ucCriticalNesting to keep a count of how \ * many times portENTER_CRITICAL() has been called. \ */ \ ucCriticalNesting++; \ } while(0) #define portEXIT_CRITICAL() \ do \ { \ if(ucCriticalNesting > portNO_CRITICAL_SECTION_NESTING) \ { \ /* \ * Decrement the nesting count as we are leaving a \ * critical section. \ */ \ ucCriticalNesting--; \ } \ \ /* \ * If the nesting level has reached zero then \ * interrupts should be re-enabled. \ */ \ if( ucCriticalNesting == portNO_CRITICAL_SECTION_NESTING ) \ { \ portENABLE_INTERRUPTS(); \ } \ } while(0) /*-----------------------------------------------------------*/ /* * The minimal stacksize is calculated on the first reference of * portMINIMAL_STACK_SIZE. Some input to this calculation is * compiletime determined, other input is port-defined (see port.c) */ extern uint16_t usPortCALCULATE_MINIMAL_STACK_SIZE( void ); extern uint16_t usCalcMinStackSize; #define portMINIMAL_STACK_SIZE \ ((usCalcMinStackSize == 0) \ ? usPortCALCULATE_MINIMAL_STACK_SIZE() \ : usCalcMinStackSize ) /* * WizC uses a downgrowing stack */ #define portSTACK_GROWTH ( -1 ) /*-----------------------------------------------------------*/ /* * Macro's that pushes all the registers that make up the context of a task onto * the stack, then saves the new top of stack into the TCB. TOSU and TBLPTRU * are only saved/restored on devices with more than 64kB (32k Words) ROM. * * The stackpointer is helt by WizC in FSR2 and points to the first free byte. * WizC uses a "downgrowing" stack. There is no framepointer. * * We keep track of the interruptstatus using ucCriticalNesting. When this * value equals zero, interrupts have to be enabled upon exit from the * portRESTORE_CONTEXT macro. * * If this is called from an ISR then the interrupt enable bits must have been * set for the ISR to ever get called. Therefore we want to save * ucCriticalNesting with value zero. This means the interrupts will again be * re-enabled when the interrupted task is switched back in. * * If this is called from a manual context switch (i.e. from a call to yield), * then we want to keep the current value of ucCritialNesting so it is restored * with its current value. This allows a yield from within a critical section. * * The compiler uses some locations at the bottom of RAM for temporary * storage. The compiler may also have been instructed to optimize * function-parameters and local variables to global storage. The compiler * uses an area called LocOpt for this wizC feature. * The total overheadstorage has to be saved in it's entirety as part of * a task context. These macro's store/restore from data address 0x0000 to * (OVERHEADPAGE0-LOCOPTSIZE+MAXLOCOPTSIZE - 1). * OVERHEADPAGE0, LOCOPTSIZE and MAXLOCOPTSIZE are compiler-generated * assembler definitions. */ #define portSAVE_CONTEXT( ucInterruptForced ) \ do \ { \ portDISABLE_INTERRUPTS(); \ \ _Pragma("asm") \ ; \ ; Push the relevant SFR's onto the task's stack \ ; \ movff STATUS,POSTDEC2 \ movff WREG,POSTDEC2 \ movff BSR,POSTDEC2 \ movff PRODH,POSTDEC2 \ movff PRODL,POSTDEC2 \ movff FSR0H,POSTDEC2 \ movff FSR0L,POSTDEC2 \ movff FSR1H,POSTDEC2 \ movff FSR1L,POSTDEC2 \ movff TABLAT,POSTDEC2 \ if __ROMSIZE > 0x8000 \ movff TBLPTRU,POSTDEC2 \ endif \ movff TBLPTRH,POSTDEC2 \ movff TBLPTRL,POSTDEC2 \ if __ROMSIZE > 0x8000 \ movff PCLATU,POSTDEC2 \ endif \ movff PCLATH,POSTDEC2 \ ; \ ; Store the compiler-scratch-area as described above. \ ; \ movlw OVERHEADPAGE0-LOCOPTSIZE+MAXLOCOPTSIZE \ clrf FSR0L,ACCESS \ clrf FSR0H,ACCESS \ _rtos_S1: \ movff POSTINC0,POSTDEC2 \ decfsz WREG,W,ACCESS \ SMARTJUMP _rtos_S1 \ ; \ ; Save the pic call/return-stack belonging to the \ ; current task by copying it to the task's software- \ ; stack. We save the hardware stack pointer (which \ ; is the number of addresses on the stack) in the \ ; W-register first because we need it later and it \ ; is modified in the save-loop by executing pop's. \ ; After the loop the W-register is stored on the \ ; stack, too. \ ; \ movf STKPTR,W,ACCESS \ bz _rtos_s3 \ _rtos_S2: \ if __ROMSIZE > 0x8000 \ movff TOSU,POSTDEC2 \ endif \ movff TOSH,POSTDEC2 \ movff TOSL,POSTDEC2 \ pop \ tstfsz STKPTR,ACCESS \ SMARTJUMP _rtos_S2 \ _rtos_s3: \ movwf POSTDEC2,ACCESS \ ; \ ; Next the value for ucCriticalNesting used by the \ ; task is stored on the stack. When \ ; (ucInterruptForced == portINTERRUPTS_FORCED), we save \ ; it as 0 (portNO_CRITICAL_SECTION_NESTING). \ ; \ if ucInterruptForced == portINTERRUPTS_FORCED \ clrf POSTDEC2,ACCESS \ else \ movff ucCriticalNesting,POSTDEC2 \ endif \ ; \ ; Save the new top of the software stack in the TCB. \ ; \ movff pxCurrentTCB,FSR0L \ movff pxCurrentTCB+1,FSR0H \ movff FSR2L,POSTINC0 \ movff FSR2H,POSTINC0 \ _Pragma("asmend") \ } while(0) /************************************************************/ /* * This is the reverse of portSAVE_CONTEXT. */ #define portRESTORE_CONTEXT() \ do \ { \ _Pragma("asm") \ ; \ ; Set FSR0 to point to pxCurrentTCB->pxTopOfStack. \ ; \ movff pxCurrentTCB,FSR0L \ movff pxCurrentTCB+1,FSR0H \ ; \ ; De-reference FSR0 to set the address it holds into \ ; FSR2 (i.e. *( pxCurrentTCB->pxTopOfStack ) ). FSR2 \ ; is used by wizC as stackpointer. \ ; \ movff POSTINC0,FSR2L \ movff POSTINC0,FSR2H \ ; \ ; Next, the value for ucCriticalNesting used by the \ ; task is retrieved from the stack. \ ; \ movff PREINC2,ucCriticalNesting \ ; \ ; Rebuild the pic call/return-stack. The number of \ ; return addresses is the next item on the task stack. \ ; Save this number in PRODL. Then fetch the addresses \ ; and store them on the hardwarestack. \ ; The datasheets say we can't use movff here... \ ; \ movff PREINC2,PRODL // Use PRODL as tempregister \ clrf STKPTR,ACCESS \ _rtos_R1: \ push \ movf PREINC2,W,ACCESS \ movwf TOSL,ACCESS \ movf PREINC2,W,ACCESS \ movwf TOSH,ACCESS \ if __ROMSIZE > 0x8000 \ movf PREINC2,W,ACCESS \ movwf TOSU,ACCESS \ else \ clrf TOSU,ACCESS \ endif \ decfsz PRODL,F,ACCESS \ SMARTJUMP _rtos_R1 \ ; \ ; Restore the compiler's working storage area to page 0 \ ; \ movlw OVERHEADPAGE0-LOCOPTSIZE+MAXLOCOPTSIZE \ movwf FSR0L,ACCESS \ clrf FSR0H,ACCESS \ _rtos_R2: \ decf FSR0L,F,ACCESS \ movff PREINC2,INDF0 \ tstfsz FSR0L,ACCESS \ SMARTJUMP _rtos_R2 \ ; \ ; Restore the sfr's forming the tasks context. \ ; We cannot yet restore bsr, w and status because \ ; we need these registers for a final test. \ ; \ movff PREINC2,PCLATH \ if __ROMSIZE > 0x8000 \ movff PREINC2,PCLATU \ else \ clrf PCLATU,ACCESS \ endif \ movff PREINC2,TBLPTRL \ movff PREINC2,TBLPTRH \ if __ROMSIZE > 0x8000 \ movff PREINC2,TBLPTRU \ else \ clrf TBLPTRU,ACCESS \ endif \ movff PREINC2,TABLAT \ movff PREINC2,FSR1L \ movff PREINC2,FSR1H \ movff PREINC2,FSR0L \ movff PREINC2,FSR0H \ movff PREINC2,PRODL \ movff PREINC2,PRODH \ ; \ ; The return from portRESTORE_CONTEXT() depends on \ ; the value of ucCriticalNesting. When it is zero, \ ; interrupts need to be enabled. This is done via a \ ; retfie instruction because we need the \ ; interrupt-enabling and the return to the restored \ ; task to be uninterruptable. \ ; Because bsr, status and W are affected by the test \ ; they are restored after the test. \ ; \ movlb ucCriticalNesting>>8 \ tstfsz ucCriticalNesting,BANKED \ SMARTJUMP _rtos_R4 \ _rtos_R3: \ movff PREINC2,BSR \ movff PREINC2,WREG \ movff PREINC2,STATUS \ retfie 0 ; Return enabling interrupts \ _rtos_R4: \ movff PREINC2,BSR \ movff PREINC2,WREG \ movff PREINC2,STATUS \ return 0 ; Return without affecting interrupts \ _Pragma("asmend") \ } while(0) /*-----------------------------------------------------------*/ #define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ ) /*-----------------------------------------------------------*/ extern void vPortYield( void ); #define portYIELD() vPortYield() #define portNOP() _Pragma("asm") \ nop \ _Pragma("asmend") /*-----------------------------------------------------------*/ #define portTASK_FUNCTION( xFunction, pvParameters ) \ void pointed xFunction( void *pvParameters ) \ _Pragma(asmfunc xFunction) #define portTASK_FUNCTION_PROTO portTASK_FUNCTION /*-----------------------------------------------------------*/ #define volatile #define register #endif /* PORTMACRO_H */