diff --git a/portable/ARMv8M/non_secure/port.c b/portable/ARMv8M/non_secure/port.c index b0bb8d9b1..3f39bc3b1 100644 --- a/portable/ARMv8M/non_secure/port.c +++ b/portable/ARMv8M/non_secure/port.c @@ -567,7 +567,7 @@ __attribute__( ( weak ) ) void vPortSetupTimerInterrupt( void ) /* PRIVILEGED_FU portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; /* Configure SysTick to interrupt at the requested rate. */ - portNVIC_SYSTICK_LOAD_REG = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; + portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT; } /*-----------------------------------------------------------*/ diff --git a/portable/Common/mpu_wrappers.c b/portable/Common/mpu_wrappers.c index ca59b8d41..c29bd2837 100644 --- a/portable/Common/mpu_wrappers.c +++ b/portable/Common/mpu_wrappers.c @@ -68,7 +68,7 @@ BaseType_t xPortRaisePrivilege( void ) /* FREERTOS_SYSTEM_CALL */ xRunningPrivileged = portIS_PRIVILEGED(); /* If the processor is not already privileged, raise privilege. */ - if( xRunningPrivileged != pdTRUE ) + if( xRunningPrivileged == pdFALSE ) { portRAISE_PRIVILEGE(); } @@ -79,7 +79,7 @@ BaseType_t xPortRaisePrivilege( void ) /* FREERTOS_SYSTEM_CALL */ void vPortResetPrivilege( BaseType_t xRunningPrivileged ) { - if( xRunningPrivileged != pdTRUE ) + if( xRunningPrivileged == pdFALSE ) { portRESET_PRIVILEGE(); } diff --git a/portable/GCC/ARM_CM23/non_secure/port.c b/portable/GCC/ARM_CM23/non_secure/port.c index b0bb8d9b1..3f39bc3b1 100644 --- a/portable/GCC/ARM_CM23/non_secure/port.c +++ b/portable/GCC/ARM_CM23/non_secure/port.c @@ -567,7 +567,7 @@ __attribute__( ( weak ) ) void vPortSetupTimerInterrupt( void ) /* PRIVILEGED_FU portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; /* Configure SysTick to interrupt at the requested rate. */ - portNVIC_SYSTICK_LOAD_REG = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; + portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT; } /*-----------------------------------------------------------*/ diff --git a/portable/GCC/ARM_CM23_NTZ/non_secure/port.c b/portable/GCC/ARM_CM23_NTZ/non_secure/port.c index b0bb8d9b1..3f39bc3b1 100644 --- a/portable/GCC/ARM_CM23_NTZ/non_secure/port.c +++ b/portable/GCC/ARM_CM23_NTZ/non_secure/port.c @@ -567,7 +567,7 @@ __attribute__( ( weak ) ) void vPortSetupTimerInterrupt( void ) /* PRIVILEGED_FU portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; /* Configure SysTick to interrupt at the requested rate. */ - portNVIC_SYSTICK_LOAD_REG = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; + portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT; } /*-----------------------------------------------------------*/ diff --git a/portable/GCC/ARM_CM33/non_secure/port.c b/portable/GCC/ARM_CM33/non_secure/port.c index b0bb8d9b1..3f39bc3b1 100644 --- a/portable/GCC/ARM_CM33/non_secure/port.c +++ b/portable/GCC/ARM_CM33/non_secure/port.c @@ -567,7 +567,7 @@ __attribute__( ( weak ) ) void vPortSetupTimerInterrupt( void ) /* PRIVILEGED_FU portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; /* Configure SysTick to interrupt at the requested rate. */ - portNVIC_SYSTICK_LOAD_REG = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; + portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT; } /*-----------------------------------------------------------*/ diff --git a/portable/GCC/ARM_CM33_NTZ/non_secure/port.c b/portable/GCC/ARM_CM33_NTZ/non_secure/port.c index b0bb8d9b1..3f39bc3b1 100644 --- a/portable/GCC/ARM_CM33_NTZ/non_secure/port.c +++ b/portable/GCC/ARM_CM33_NTZ/non_secure/port.c @@ -567,7 +567,7 @@ __attribute__( ( weak ) ) void vPortSetupTimerInterrupt( void ) /* PRIVILEGED_FU portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; /* Configure SysTick to interrupt at the requested rate. */ - portNVIC_SYSTICK_LOAD_REG = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; + portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT; } /*-----------------------------------------------------------*/ diff --git a/portable/GCC/ARM_CM4_MPU/port.c b/portable/GCC/ARM_CM4_MPU/port.c index 46d65fa27..af9b53e1f 100644 --- a/portable/GCC/ARM_CM4_MPU/port.c +++ b/portable/GCC/ARM_CM4_MPU/port.c @@ -703,7 +703,7 @@ static void prvSetupMPU( void ) ( portUNPRIVILEGED_FLASH_REGION ); portMPU_REGION_ATTRIBUTE_REG = ( portMPU_REGION_READ_ONLY ) | - ( portMPU_REGION_CACHEABLE_BUFFERABLE ) | + ( ( configTEX_S_C_B_FLASH & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) | ( prvGetMPURegionSizeSetting( ( uint32_t ) __FLASH_segment_end__ - ( uint32_t ) __FLASH_segment_start__ ) ) | ( portMPU_REGION_ENABLE ); @@ -714,7 +714,7 @@ static void prvSetupMPU( void ) ( portPRIVILEGED_FLASH_REGION ); portMPU_REGION_ATTRIBUTE_REG = ( portMPU_REGION_PRIVILEGED_READ_ONLY ) | - ( portMPU_REGION_CACHEABLE_BUFFERABLE ) | + ( ( configTEX_S_C_B_FLASH & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) | ( prvGetMPURegionSizeSetting( ( uint32_t ) __privileged_functions_end__ - ( uint32_t ) __privileged_functions_start__ ) ) | ( portMPU_REGION_ENABLE ); @@ -725,7 +725,7 @@ static void prvSetupMPU( void ) ( portPRIVILEGED_RAM_REGION ); portMPU_REGION_ATTRIBUTE_REG = ( portMPU_REGION_PRIVILEGED_READ_WRITE ) | - ( portMPU_REGION_CACHEABLE_BUFFERABLE ) | + ( ( configTEX_S_C_B_SRAM & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) | prvGetMPURegionSizeSetting( ( uint32_t ) __privileged_data_end__ - ( uint32_t ) __privileged_data_start__ ) | ( portMPU_REGION_ENABLE ); @@ -836,7 +836,7 @@ void vPortStoreTaskMPUSettings( xMPU_SETTINGS * xMPUSettings, xMPUSettings->xRegion[ 0 ].ulRegionAttribute = ( portMPU_REGION_READ_WRITE ) | - ( portMPU_REGION_CACHEABLE_BUFFERABLE ) | + ( ( configTEX_S_C_B_SRAM & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) | ( prvGetMPURegionSizeSetting( ( uint32_t ) __SRAM_segment_end__ - ( uint32_t ) __SRAM_segment_start__ ) ) | ( portMPU_REGION_ENABLE ); @@ -849,7 +849,7 @@ void vPortStoreTaskMPUSettings( xMPU_SETTINGS * xMPUSettings, xMPUSettings->xRegion[ 1 ].ulRegionAttribute = ( portMPU_REGION_PRIVILEGED_READ_WRITE ) | - ( portMPU_REGION_CACHEABLE_BUFFERABLE ) | + ( ( configTEX_S_C_B_SRAM & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) | prvGetMPURegionSizeSetting( ( uint32_t ) __privileged_data_end__ - ( uint32_t ) __privileged_data_start__ ) | ( portMPU_REGION_ENABLE ); @@ -877,7 +877,7 @@ void vPortStoreTaskMPUSettings( xMPU_SETTINGS * xMPUSettings, xMPUSettings->xRegion[ 0 ].ulRegionAttribute = ( portMPU_REGION_READ_WRITE ) | /* Read and write. */ ( prvGetMPURegionSizeSetting( ulStackDepth * ( uint32_t ) sizeof( StackType_t ) ) ) | - ( portMPU_REGION_CACHEABLE_BUFFERABLE ) | + ( ( configTEX_S_C_B_SRAM & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) | ( portMPU_REGION_ENABLE ); } diff --git a/portable/GCC/ARM_CM4_MPU/portmacro.h b/portable/GCC/ARM_CM4_MPU/portmacro.h index a774559dd..4588dd2c0 100644 --- a/portable/GCC/ARM_CM4_MPU/portmacro.h +++ b/portable/GCC/ARM_CM4_MPU/portmacro.h @@ -80,6 +80,10 @@ #define portMPU_REGION_PRIVILEGED_READ_WRITE_UNPRIV_READ_ONLY ( 0x02UL << 24UL ) #define portMPU_REGION_CACHEABLE_BUFFERABLE ( 0x07UL << 16UL ) #define portMPU_REGION_EXECUTE_NEVER ( 0x01UL << 28UL ) + /* Location of the TEX,S,C,B bits in the MPU Region Attribute and Size + * Register (RASR). */ + #define portMPU_RASR_TEX_S_C_B_LOCATION ( 16UL ) + #define portMPU_RASR_TEX_S_C_B_MASK ( 0x3FUL ) /* MPU settings that can be overriden in FreeRTOSConfig.h. */ #ifndef configTOTAL_MPU_REGIONS @@ -87,6 +91,82 @@ #define configTOTAL_MPU_REGIONS ( 8UL ) #endif + /* + * The TEX, Shareable (S), Cacheable (C) and Bufferable (B) bits define the + * memory type, and where necessary the cacheable and shareable properties + * of the memory region. + * + * The TEX, C, and B bits together indicate the memory type of the region, + * and: + * - For Normal memory, the cacheable properties of the region. + * - For Device memory, whether the region is shareable. + * + * For Normal memory regions, the S bit indicates whether the region is + * shareable. For Strongly-ordered and Device memory, the S bit is ignored. + * + * See the following two tables for setting TEX, S, C and B bits for + * unprivileged flash, privileged flash and privileged RAM regions. + * + +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+ + | TEX | C | B | Memory type | Description or Normal region cacheability | Shareable? | + +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+ + | 000 | 0 | 0 | Strongly-ordered | Strongly ordered | Shareable | + +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+ + | 000 | 0 | 1 | Device | Shared device | Shareable | + +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+ + | 000 | 1 | 0 | Normal | Outer and inner write-through; no write allocate | S bit | + +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+ + | 000 | 1 | 1 | Normal | Outer and inner write-back; no write allocate | S bit | + +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+ + | 001 | 0 | 0 | Normal | Outer and inner Non-cacheable | S bit | + +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+ + | 001 | 0 | 1 | Reserved | Reserved | Reserved | + +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+ + | 001 | 1 | 0 | IMPLEMENTATION DEFINED | IMPLEMENTATION DEFINED | IMPLEMENTATION DEFINED | + +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+ + | 001 | 1 | 1 | Normal | Outer and inner write-back; write and read allocate | S bit | + +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+ + | 010 | 0 | 0 | Device | Non-shared device | Not shareable | + +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+ + | 010 | 0 | 1 | Reserved | Reserved | Reserved | + +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+ + | 010 | 1 | X | Reserved | Reserved | Reserved | + +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+ + | 011 | X | X | Reserved | Reserved | Reserved | + +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+ + | 1BB | A | A | Normal | Cached memory, with AA and BB indicating the inner and | Reserved | + | | | | | outer cacheability rules that must be exported on the | | + | | | | | bus. See the table below for the cacheability policy | | + | | | | | encoding. memory, BB=Outer policy, AA=Inner policy. | | + +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+ + + +-----------------------------------------+----------------------------------------+ + | AA or BB subfield of {TEX,C,B} encoding | Cacheability policy | + +-----------------------------------------+----------------------------------------+ + | 00 | Non-cacheable | + +-----------------------------------------+----------------------------------------+ + | 01 | Write-back, write and read allocate | + +-----------------------------------------+----------------------------------------+ + | 10 | Write-through, no write allocate | + +-----------------------------------------+----------------------------------------+ + | 11 | Write-back, no write allocate | + +-----------------------------------------+----------------------------------------+ + */ + + /* TEX, Shareable (S), Cacheable (C) and Bufferable (B) bits for flash + * region. */ + #ifndef configTEX_S_C_B_FLASH + /* Default to TEX=000, S=1, C=1, B=1 for backward compatibility. */ + #define configTEX_S_C_B_FLASH ( 0x07UL ) + #endif + + /* TEX, Shareable (S), Cacheable (C) and Bufferable (B) bits for RAM + * region. */ + #ifndef configTEX_S_C_B_SRAM + /* Default to TEX=000, S=1, C=1, B=1 for backward compatibility. */ + #define configTEX_S_C_B_SRAM ( 0x07UL ) + #endif + #define portUNPRIVILEGED_FLASH_REGION ( 0UL ) #define portPRIVILEGED_FLASH_REGION ( 1UL ) #define portPRIVILEGED_RAM_REGION ( 2UL ) diff --git a/portable/GCC/ARM_CR5/port.c b/portable/GCC/ARM_CR5/port.c index 418020f9d..0658218a0 100644 --- a/portable/GCC/ARM_CR5/port.c +++ b/portable/GCC/ARM_CR5/port.c @@ -147,6 +147,19 @@ #define portTASK_RETURN_ADDRESS prvTaskExitError #endif + +/* Adding the necessary stuff in order to be able to determine from C code wheter or not the IRQs are enabled at the processor level (not interrupt controller level) */ +#define GET_CPSR() ({u32 rval = 0U; \ + __asm__ __volatile__(\ + "mrs %0, cpsr\n"\ + : "=r" (rval)\ + );\ + rval;\ + }) + +#define CPSR_IRQ_ENABLE_MASK 0x80U + +#define IS_IRQ_DISABLED() ({unsigned int val = 0; val = (GET_CPSR() & CPSR_IRQ_ENABLE_MASK) ? 1 : 0; val;}) /*-----------------------------------------------------------*/ /* @@ -468,7 +481,13 @@ void vPortClearInterruptMask( uint32_t ulNewMaskValue ) uint32_t ulPortSetInterruptMask( void ) { uint32_t ulReturn; - + uint32_t wasIRQDisabled; + + /* We keep track of if the IRQ are enabled in the CPU (as opposed to interrupts masked in the interrupt controller, like the intend of this function). + * This is very important because when the CPU is interrupted, among other things, the hardware clears the IRQ Enable bit in the CPSR of the IRQ CPU Mode in which + * we enter. */ + wasIRQDisabled = IS_IRQ_DISABLED(); + /* Interrupt in the CPU must be turned off while the ICCPMR is being * updated. */ portCPU_IRQ_DISABLE(); @@ -486,7 +505,18 @@ uint32_t ulPortSetInterruptMask( void ) "isb \n"::: "memory" ); } - portCPU_IRQ_ENABLE(); + /* Just like this function returns a value of wether or not the interrupts where masked in the interrupt controller in order to avoid race condition when + * calling its matching vPortClearInterruptMask function, we needed a 'wasIRQDisabled' variable holding the state of the IRQ Enable bit in the CPSR in order + * to leave that bit in it's original state. Like mentioned above, hardware automatically clear the IRQEnable bit upon trapping into IRQ Mode, so the programmer + * cannot make assumption about it's state. Very rare, but very important race condition is avoided with this when this function is called in an ISR. The race + * condition in question was discovered when integrating tracealyzer code. Inside the function 'void vTaskSwitchContext( void )' in tasks.c, there is a macro 'traceTASK_SWITCHED_IN();' + * which gets replaced by something when using the tracing capabilities. That macro protects some critical section with matching calls to 'ulPortSetInterruptMask' + * and 'vPortClearInterruptMask'. At the time of calling those functions, the interrupt mask is not set in the interrupt controller, thus the only protecting barrier + * against the CPU traping into recursive interrupt was the IRQ Enable bit in the CPSR. By not taking it into acount, the very code that protects the CPU against + * critical section violation just enabled it to happen : A SysTick was waiting to happen, and calling 'portCPU_IRQ_ENABLE' would enable it to occur... Thus triggering a + * switch of context while already performing a switch context. */ + if(!wasIRQDisabled) + portCPU_IRQ_ENABLE(); return ulReturn; } diff --git a/portable/GCC/AVR_AVRDx/port.c b/portable/GCC/AVR_AVRDx/port.c index 8fca32953..9d5cb9683 100644 --- a/portable/GCC/AVR_AVRDx/port.c +++ b/portable/GCC/AVR_AVRDx/port.c @@ -38,7 +38,7 @@ *----------------------------------------------------------*/ /* Start tasks with interrupts enables. */ -#define portFLAGS_INT_ENABLED ((StackType_t) 0x80) +#define portFLAGS_INT_ENABLED ((StackType_t) 0x80) /*-----------------------------------------------------------*/ @@ -63,103 +63,102 @@ extern volatile RTOS_TCB_t *volatile pxCurrentTCB; * * The interrupts will have been disabled during the call to portSAVE_CONTEXT() * so we need not worry about reading/writing to the stack pointer. - */ -#define portSAVE_CONTEXT() \ - asm volatile("push r0 \n\t" \ - "in r0, __SREG__ \n\t" \ - "cli \n\t" \ - "push r0 \n\t" \ - "in r0, __RAMPZ__ \n\t" \ - "push r0 \n\t" \ - "push r1 \n\t" \ - "clr r1 \n\t" \ - "push r2 \n\t" \ - "push r3 \n\t" \ - "push r4 \n\t" \ - "push r5 \n\t" \ - "push r6 \n\t" \ - "push r7 \n\t" \ - "push r8 \n\t" \ - "push r9 \n\t" \ - "push r10 \n\t" \ - "push r11 \n\t" \ - "push r12 \n\t" \ - "push r13 \n\t" \ - "push r14 \n\t" \ - "push r15 \n\t" \ - "push r16 \n\t" \ - "push r17 \n\t" \ - "push r18 \n\t" \ - "push r19 \n\t" \ - "push r20 \n\t" \ - "push r21 \n\t" \ - "push r22 \n\t" \ - "push r23 \n\t" \ - "push r24 \n\t" \ - "push r25 \n\t" \ - "push r26 \n\t" \ - "push r27 \n\t" \ - "push r28 \n\t" \ - "push r29 \n\t" \ - "push r30 \n\t" \ - "push r31 \n\t" \ - "lds r26, pxCurrentTCB \n\t" \ - "lds r27, pxCurrentTCB + 1 \n\t" \ - "in r0, __SP_L__ \n\t" \ - "st x+, r0 \n\t" \ - "in r0, __SP_H__ \n\t" \ - "st x+, r0 \n\t"); +#define portSAVE_CONTEXT() \ + asm volatile("push r0 \n\t" \ + "in r0, __SREG__ \n\t" \ + "cli \n\t" \ + "push r0 \n\t" \ + "in r0, __RAMPZ__ \n\t" \ + "push r0 \n\t" \ + "push r1 \n\t" \ + "clr r1 \n\t" \ + "push r2 \n\t" \ + "push r3 \n\t" \ + "push r4 \n\t" \ + "push r5 \n\t" \ + "push r6 \n\t" \ + "push r7 \n\t" \ + "push r8 \n\t" \ + "push r9 \n\t" \ + "push r10 \n\t" \ + "push r11 \n\t" \ + "push r12 \n\t" \ + "push r13 \n\t" \ + "push r14 \n\t" \ + "push r15 \n\t" \ + "push r16 \n\t" \ + "push r17 \n\t" \ + "push r18 \n\t" \ + "push r19 \n\t" \ + "push r20 \n\t" \ + "push r21 \n\t" \ + "push r22 \n\t" \ + "push r23 \n\t" \ + "push r24 \n\t" \ + "push r25 \n\t" \ + "push r26 \n\t" \ + "push r27 \n\t" \ + "push r28 \n\t" \ + "push r29 \n\t" \ + "push r30 \n\t" \ + "push r31 \n\t" \ + "lds r26, pxCurrentTCB \n\t" \ + "lds r27, pxCurrentTCB + 1 \n\t" \ + "in r0, __SP_L__ \n\t" \ + "st x+, r0 \n\t" \ + "in r0, __SP_H__ \n\t" \ + "st x+, r0 \n\t"); /* * Opposite to portSAVE_CONTEXT(). Interrupts will have been disabled during * the context save so we can write to the stack pointer. */ -#define portRESTORE_CONTEXT() \ - asm volatile("lds r26, pxCurrentTCB \n\t" \ - "lds r27, pxCurrentTCB + 1 \n\t" \ - "ld r28, x+ \n\t" \ - "out __SP_L__, r28 \n\t" \ - "ld r29, x+ \n\t" \ - "out __SP_H__, r29 \n\t" \ - "pop r31 \n\t" \ - "pop r30 \n\t" \ - "pop r29 \n\t" \ - "pop r28 \n\t" \ - "pop r27 \n\t" \ - "pop r26 \n\t" \ - "pop r25 \n\t" \ - "pop r24 \n\t" \ - "pop r23 \n\t" \ - "pop r22 \n\t" \ - "pop r21 \n\t" \ - "pop r20 \n\t" \ - "pop r19 \n\t" \ - "pop r18 \n\t" \ - "pop r17 \n\t" \ - "pop r16 \n\t" \ - "pop r15 \n\t" \ - "pop r14 \n\t" \ - "pop r13 \n\t" \ - "pop r12 \n\t" \ - "pop r11 \n\t" \ - "pop r10 \n\t" \ - "pop r9 \n\t" \ - "pop r8 \n\t" \ - "pop r7 \n\t" \ - "pop r6 \n\t" \ - "pop r5 \n\t" \ - "pop r4 \n\t" \ - "pop r3 \n\t" \ - "pop r2 \n\t" \ - "pop r1 \n\t" \ - "pop r0 \n\t" \ - "out __RAMPZ__, r0 \n\t" \ - "pop r0 \n\t" \ - "out __SREG__, r0 \n\t" \ - "pop r0 \n\t"); +#define portRESTORE_CONTEXT() \ + asm volatile("lds r26, pxCurrentTCB \n\t" \ + "lds r27, pxCurrentTCB + 1 \n\t" \ + "ld r28, x+ \n\t" \ + "out __SP_L__, r28 \n\t" \ + "ld r29, x+ \n\t" \ + "out __SP_H__, r29 \n\t" \ + "pop r31 \n\t" \ + "pop r30 \n\t" \ + "pop r29 \n\t" \ + "pop r28 \n\t" \ + "pop r27 \n\t" \ + "pop r26 \n\t" \ + "pop r25 \n\t" \ + "pop r24 \n\t" \ + "pop r23 \n\t" \ + "pop r22 \n\t" \ + "pop r21 \n\t" \ + "pop r20 \n\t" \ + "pop r19 \n\t" \ + "pop r18 \n\t" \ + "pop r17 \n\t" \ + "pop r16 \n\t" \ + "pop r15 \n\t" \ + "pop r14 \n\t" \ + "pop r13 \n\t" \ + "pop r12 \n\t" \ + "pop r11 \n\t" \ + "pop r10 \n\t" \ + "pop r9 \n\t" \ + "pop r8 \n\t" \ + "pop r7 \n\t" \ + "pop r6 \n\t" \ + "pop r5 \n\t" \ + "pop r4 \n\t" \ + "pop r3 \n\t" \ + "pop r2 \n\t" \ + "pop r1 \n\t" \ + "pop r0 \n\t" \ + "out __RAMPZ__, r0 \n\t" \ + "pop r0 \n\t" \ + "out __SREG__, r0 \n\t" \ + "pop r0 \n\t"); /*-----------------------------------------------------------*/ @@ -174,11 +173,11 @@ static void prvSetupTimerInterrupt(void); */ StackType_t *pxPortInitialiseStack(StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters) { - uint16_t usAddress; + uint16_t usAddress; - /*lint -e950 -e611 -e923 Lint doesn't like this much - but nothing I can do about it. */ + /*lint -e950 -e611 -e923 Lint doesn't like this much - but nothing I can do about it. */ - /* Place a few bytes of known values on the bottom of the stack. + /* Place a few bytes of known values on the bottom of the stack. This is just useful for debugging. Uncomment if needed. */ // *pxTopOfStack = 0x11; // pxTopOfStack--; @@ -187,70 +186,70 @@ StackType_t *pxPortInitialiseStack(StackType_t *pxTopOfStack, TaskFunction_t pxC // *pxTopOfStack = 0x33; // pxTopOfStack--; - /* The start of the task code will be popped off the stack last, so place - it on first. */ - usAddress = (uint16_t)pxCode; - *pxTopOfStack = (StackType_t)(usAddress & (uint16_t)0x00ff); - pxTopOfStack--; + /* The start of the task code will be popped off the stack last, so place + it on first. */ + usAddress = (uint16_t)pxCode; + *pxTopOfStack = (StackType_t)(usAddress & (uint16_t)0x00ff); + pxTopOfStack--; - usAddress >>= 8; - *pxTopOfStack = (StackType_t)(usAddress & (uint16_t)0x00ff); - pxTopOfStack--; + usAddress >>= 8; + *pxTopOfStack = (StackType_t)(usAddress & (uint16_t)0x00ff); + pxTopOfStack--; - /* Next simulate the stack as if after a call to portSAVE_CONTEXT(). - portSAVE_CONTEXT places the flags on the stack immediately after r0 - to ensure the interrupts get disabled as soon as possible, and so ensuring - the stack use is minimal should a context switch interrupt occur. */ - *pxTopOfStack = (StackType_t)0x00; /* R0 */ - pxTopOfStack--; - *pxTopOfStack = portFLAGS_INT_ENABLED; - pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) 0x00; /* RAMPZ */ - pxTopOfStack--; - - /* Now the remaining registers. The compiler expects R1 to be 0. */ - *pxTopOfStack = (StackType_t)0x00; /* R1 */ + /* Next simulate the stack as if after a call to portSAVE_CONTEXT(). + portSAVE_CONTEXT places the flags on the stack immediately after r0 + to ensure the interrupts get disabled as soon as possible, and so ensuring + the stack use is minimal should a context switch interrupt occur. */ + *pxTopOfStack = (StackType_t)0x00; /* R0 */ + pxTopOfStack--; + *pxTopOfStack = portFLAGS_INT_ENABLED; + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) 0x00; /* RAMPZ */ + pxTopOfStack--; + + /* Now the remaining registers. The compiler expects R1 to be 0. */ + *pxTopOfStack = (StackType_t)0x00; /* R1 */ - /* Leave R2 - R23 untouched */ - pxTopOfStack -= 23; + /* Leave R2 - R23 untouched */ + pxTopOfStack -= 23; - /* Place the parameter on the stack in the expected location. */ - usAddress = (uint16_t)pvParameters; - *pxTopOfStack = (StackType_t)(usAddress & (uint16_t)0x00ff); - pxTopOfStack--; + /* Place the parameter on the stack in the expected location. */ + usAddress = (uint16_t)pvParameters; + *pxTopOfStack = (StackType_t)(usAddress & (uint16_t)0x00ff); + pxTopOfStack--; - usAddress >>= 8; - *pxTopOfStack = (StackType_t)(usAddress & (uint16_t)0x00ff); + usAddress >>= 8; + *pxTopOfStack = (StackType_t)(usAddress & (uint16_t)0x00ff); - /* Leave register R26 - R31 untouched */ - pxTopOfStack -= 7; + /* Leave register R26 - R31 untouched */ + pxTopOfStack -= 7; - /*lint +e950 +e611 +e923 */ + /*lint +e950 +e611 +e923 */ - return pxTopOfStack; + return pxTopOfStack; } /*-----------------------------------------------------------*/ BaseType_t xPortStartScheduler(void) { - /* Setup the hardware to generate the tick. */ - prvSetupTimerInterrupt(); + /* Setup the hardware to generate the tick. */ + prvSetupTimerInterrupt(); - /* Restore the context of the first task that is going to run. */ - portRESTORE_CONTEXT(); + /* Restore the context of the first task that is going to run. */ + portRESTORE_CONTEXT(); - /* Simulate a function call end as generated by the compiler. We will now - jump to the start of the task the context of which we have just restored. */ - asm volatile("ret"); + /* Simulate a function call end as generated by the compiler. We will now + jump to the start of the task the context of which we have just restored. */ + asm volatile("ret"); - /* Should not get here. */ - return pdTRUE; + /* Should not get here. */ + return pdTRUE; } /*-----------------------------------------------------------*/ void vPortEndScheduler(void) { - /* vPortEndScheduler is not implemented in this port. */ + /* vPortEndScheduler is not implemented in this port. */ } /*-----------------------------------------------------------*/ @@ -261,10 +260,10 @@ void vPortEndScheduler(void) void vPortYield(void) __attribute__((naked)); void vPortYield(void) { - portSAVE_CONTEXT(); - vTaskSwitchContext(); - portRESTORE_CONTEXT(); - asm volatile("ret"); + portSAVE_CONTEXT(); + vTaskSwitchContext(); + portRESTORE_CONTEXT(); + asm volatile("ret"); } /*-----------------------------------------------------------*/ @@ -275,10 +274,10 @@ void vPortYield(void) void vPortYieldFromISR(void) __attribute__((naked)); void vPortYieldFromISR(void) { - portSAVE_CONTEXT(); - vTaskSwitchContext(); - portRESTORE_CONTEXT(); - asm volatile("reti"); + portSAVE_CONTEXT(); + vTaskSwitchContext(); + portRESTORE_CONTEXT(); + asm volatile("reti"); } /*-----------------------------------------------------------*/ @@ -291,15 +290,14 @@ void vPortYieldFromISR(void) void vPortYieldFromTick(void) __attribute__((naked)); void vPortYieldFromTick(void) { - portSAVE_CONTEXT(); - - if (xTaskIncrementTick() != pdFALSE) { - vTaskSwitchContext(); - } + portSAVE_CONTEXT(); + if (xTaskIncrementTick() != pdFALSE) { + vTaskSwitchContext(); + } - portRESTORE_CONTEXT(); + portRESTORE_CONTEXT(); - asm volatile("reti"); + asm volatile("reti"); } /*-----------------------------------------------------------*/ @@ -308,7 +306,7 @@ void vPortYieldFromTick(void) */ static void prvSetupTimerInterrupt(void) { - TICK_init(); + TICK_init(); } /*-----------------------------------------------------------*/ @@ -319,17 +317,15 @@ static void prvSetupTimerInterrupt(void) * the context is saved at the start of vPortYieldFromTick(). The tick * count is incremented after the context is saved. */ - ISR(TICK_INT_vect, ISR_NAKED) { - /* Clear tick interrupt flag. */ - CLR_INT(INT_FLAGS, INT_MASK); + /* Clear tick interrupt flag. */ + CLR_INT(INT_FLAGS, INT_MASK); - vPortYieldFromTick(); + vPortYieldFromTick(); - asm volatile("reti"); + asm volatile("reti"); } - #else /* @@ -337,14 +333,10 @@ ISR(TICK_INT_vect, ISR_NAKED) * tick count. We don't need to switch context, this can only be done by * manual calls to taskYIELD(); */ - ISR(TICK_INT_vect) { - /* Clear tick interrupt flag. */ - INT_FLAGS = INT_MASK; - - xTaskIncrementTick(); + /* Clear tick interrupt flag. */ + INT_FLAGS = INT_MASK; + xTaskIncrementTick(); } - - #endif diff --git a/portable/GCC/AVR_AVRDx/porthardware.h b/portable/GCC/AVR_AVRDx/porthardware.h index 4b0e04be0..cf2377844 100644 --- a/portable/GCC/AVR_AVRDx/porthardware.h +++ b/portable/GCC/AVR_AVRDx/porthardware.h @@ -6,126 +6,96 @@ /*-----------------------------------------------------------*/ #define CLR_INT(FLAG_REG, FLAG_MASK) \ - asm volatile( "push r16\n\t" \ - "ldi r16, %1\n\t" \ - "sts %0, r16\n\t" \ - "pop r16\n\t" \ - : \ - : "i"(_SFR_MEM_ADDR(FLAG_REG)),"i"((uint8_t)(FLAG_MASK)) \ - ); + asm volatile( \ + "push r16\n\t" \ + "ldi r16, %1\n\t" \ + "sts %0, r16\n\t" \ + "pop r16\n\t" \ + : \ + : "i"(_SFR_MEM_ADDR(FLAG_REG)),"i"((uint8_t)(FLAG_MASK)) \ + ); #if ( configUSE_TIMER_INSTANCE == 0 ) - #define TICK_INT_vect TCB0_INT_vect - #define INT_FLAGS TCB0_INTFLAGS - #define INT_MASK TCB_CAPT_bm - - #define TICK_init() { \ - TCB0.CCMP = configCPU_CLOCK_HZ / configTICK_RATE_HZ; \ - TCB0.INTCTRL = TCB_CAPT_bm; \ - TCB0.CTRLA = TCB_ENABLE_bm; \ - } - - #define TICK_stop() { \ - TCB0.INTCTRL &= ~TCB_CAPT_bm;\ - TCB0.CTRLA &= ~TCB_ENABLE_bm; \ - } + #define TICK_INT_vect TCB0_INT_vect + #define INT_FLAGS TCB0_INTFLAGS + #define INT_MASK TCB_CAPT_bm + + #define TICK_init() { \ + TCB0.CCMP = configCPU_CLOCK_HZ / configTICK_RATE_HZ; \ + TCB0.INTCTRL = TCB_CAPT_bm; \ + TCB0.CTRLA = TCB_ENABLE_bm; \ + } #elif ( configUSE_TIMER_INSTANCE == 1 ) - #define TICK_INT_vect TCB1_INT_vect - #define INT_FLAGS TCB1_INTFLAGS - #define INT_MASK TCB_CAPT_bm - - #define TICK_init() { \ - TCB1.CCMP = configCPU_CLOCK_HZ / configTICK_RATE_HZ; \ - TCB1.INTCTRL = TCB_CAPT_bm; \ - TCB1.CTRLA = TCB_ENABLE_bm; \ - } - - #define TICK_stop() { \ - TCB1.INTCTRL &= ~TCB_CAPT_bm; \ - TCB1.CTRLA &= ~TCB_ENABLE_bm; \ - } - + #define TICK_INT_vect TCB1_INT_vect + #define INT_FLAGS TCB1_INTFLAGS + #define INT_MASK TCB_CAPT_bm + + #define TICK_init() { \ + TCB1.CCMP = configCPU_CLOCK_HZ / configTICK_RATE_HZ; \ + TCB1.INTCTRL = TCB_CAPT_bm; \ + TCB1.CTRLA = TCB_ENABLE_bm; \ + } + #elif ( configUSE_TIMER_INSTANCE == 2 ) - #define TICK_INT_vect TCB2_INT_vect - #define INT_FLAGS TCB2_INTFLAGS - #define INT_MASK TCB_CAPT_bm + #define TICK_INT_vect TCB2_INT_vect + #define INT_FLAGS TCB2_INTFLAGS + #define INT_MASK TCB_CAPT_bm - #define TICK_init() { \ - TCB2.CCMP = configCPU_CLOCK_HZ / configTICK_RATE_HZ; \ - TCB2.INTCTRL = TCB_CAPT_bm; \ - TCB2.CTRLA = TCB_ENABLE_bm; \ - } - - #define TICK_stop() { \ - TCB2.INTCTRL &= ~TCB_CAPT_bm; \ - TCB2.CTRLA &= ~TCB_ENABLE_bm; \ - } - + #define TICK_init() { \ + TCB2.CCMP = configCPU_CLOCK_HZ / configTICK_RATE_HZ; \ + TCB2.INTCTRL = TCB_CAPT_bm; \ + TCB2.CTRLA = TCB_ENABLE_bm; \ + } + #elif ( configUSE_TIMER_INSTANCE == 3 ) - #define TICK_INT_vect TCB3_INT_vect - #define INT_FLAGS TCB3_INTFLAGS - #define INT_MASK TCB_CAPT_bm - - #define TICK_init() { \ - TCB3.CCMP = configCPU_CLOCK_HZ / configTICK_RATE_HZ; \ - TCB3.INTCTRL = TCB_CAPT_bm; \ - TCB3.CTRLA = TCB_ENABLE_bm; \ - } - - #define TICK_stop() { \ - TCB3.INTCTRL &= ~TCB_CAPT_bm; \ - TCB3.CTRLA &= ~TCB_ENABLE_bm; \ - } - + #define TICK_INT_vect TCB3_INT_vect + #define INT_FLAGS TCB3_INTFLAGS + #define INT_MASK TCB_CAPT_bm + + #define TICK_init() { \ + TCB3.CCMP = configCPU_CLOCK_HZ / configTICK_RATE_HZ; \ + TCB3.INTCTRL = TCB_CAPT_bm; \ + TCB3.CTRLA = TCB_ENABLE_bm; \ + } + #elif ( configUSE_TIMER_INSTANCE == 4 ) - #define TICK_INT_vect TCB4_INT_vect - #define INT_FLAGS TCB4_INTFLAGS - #define INT_MASK TCB_CAPT_bm - - #define TICK_init() { \ - TCB4.CCMP = configCPU_CLOCK_HZ / configTICK_RATE_HZ; \ - TCB4.INTCTRL = TCB_CAPT_bm; \ - TCB4.CTRLA = TCB_ENABLE_bm; \ - } - - #define TICK_stop() { \ - TCB4.INTCTRL &= ~TCB_CAPT_bm; \ - TCB4.CTRLA &= ~TCB_ENABLE_bm; \ - } - + #define TICK_INT_vect TCB4_INT_vect + #define INT_FLAGS TCB4_INTFLAGS + #define INT_MASK TCB_CAPT_bm + + #define TICK_init() { \ + TCB4.CCMP = configCPU_CLOCK_HZ / configTICK_RATE_HZ; \ + TCB4.INTCTRL = TCB_CAPT_bm; \ + TCB4.CTRLA = TCB_ENABLE_bm; \ + } + #elif ( configUSE_TIMER_INSTANCE == 5 ) - - /* Hertz to period for RTC setup */ - #define RTC_PERIOD_HZ(x) (32768 * ((1.0 / x))) - - #define TICK_INT_vect RTC_CNT_vect - #define INT_FLAGS RTC_INTFLAGS - #define INT_MASK RTC_OVF_bm - - #define TICK_init() { \ - while (RTC.STATUS > 0); \ - RTC.CTRLA = RTC_PRESCALER_DIV1_gc | 1 << RTC_RTCEN_bp; \ - RTC.PER = RTC_PERIOD_HZ(configTICK_RATE_HZ); \ - RTC.INTCTRL |= 1 << RTC_OVF_bp; \ - } - - #define TICK_stop() { \ - RTC.CTRLA &= ~(1 << RTC_RTCEN_bp); \ - RTC.INTCTRL &= ~(1 << RTC_OVF_bp); \ - } + + #define TICK_INT_vect RTC_CNT_vect + #define INT_FLAGS RTC_INTFLAGS + #define INT_MASK RTC_OVF_bm + + /* Hertz to period for RTC setup */ + #define RTC_PERIOD_HZ(x) ( 32768 * ( ( 1.0 / x ) ) ) + #define TICK_init() { \ + while (RTC.STATUS > 0); \ + RTC.CTRLA = RTC_PRESCALER_DIV1_gc | 1 << RTC_RTCEN_bp; \ + RTC.PER = RTC_PERIOD_HZ(configTICK_RATE_HZ); \ + RTC.INTCTRL |= 1 << RTC_OVF_bp; \ + } #else - #undef TICK_INT_vect - #undef INT_FLAGS - #undef INT_MASK - #undef TICK_init() - #error Invalid timer setting. + #undef TICK_INT_vect + #undef INT_FLAGS + #undef INT_MASK + #undef TICK_init() + #error Invalid timer setting. #endif /*-----------------------------------------------------------*/ diff --git a/portable/GCC/AVR_AVRDx/portmacro.h b/portable/GCC/AVR_AVRDx/portmacro.h index 83d41d31e..085a27fc1 100644 --- a/portable/GCC/AVR_AVRDx/portmacro.h +++ b/portable/GCC/AVR_AVRDx/portmacro.h @@ -64,18 +64,17 @@ typedef uint16_t TickType_t; typedef uint32_t TickType_t; #define portMAX_DELAY (TickType_t)0xffffffffUL #endif - /*-----------------------------------------------------------*/ /* Critical section management. */ #define portENTER_CRITICAL() \ - asm volatile("in __tmp_reg__, __SREG__"); \ - asm volatile("cli"); \ - asm volatile("push __tmp_reg__") + asm volatile("in __tmp_reg__, __SREG__"); \ + asm volatile("cli"); \ + asm volatile("push __tmp_reg__") #define portEXIT_CRITICAL() \ - asm volatile("pop __tmp_reg__"); \ - asm volatile("out __SREG__, __tmp_reg__") + asm volatile("pop __tmp_reg__"); \ + asm volatile("out __SREG__, __tmp_reg__") #define portDISABLE_INTERRUPTS() asm volatile("cli" ::); #define portENABLE_INTERRUPTS() asm volatile("sei" ::); diff --git a/portable/GCC/AVR_Mega0/port.c b/portable/GCC/AVR_Mega0/port.c index 39cdd843a..8c4684294 100644 --- a/portable/GCC/AVR_Mega0/port.c +++ b/portable/GCC/AVR_Mega0/port.c @@ -29,9 +29,7 @@ #include #include - #include "porthardware.h" - #include "FreeRTOS.h" #include "task.h" @@ -40,7 +38,7 @@ *----------------------------------------------------------*/ /* Start tasks with interrupts enables. */ -#define portFLAGS_INT_ENABLED ((StackType_t) 0x80) +#define portFLAGS_INT_ENABLED ((StackType_t) 0x80) /*-----------------------------------------------------------*/ @@ -67,96 +65,96 @@ extern volatile RTOS_TCB_t *volatile pxCurrentTCB; * so we need not worry about reading/writing to the stack pointer. */ -#define portSAVE_CONTEXT() \ - asm volatile("push r0 \n\t" \ - "in r0, __SREG__ \n\t" \ - "cli \n\t" \ - "push r0 \n\t" \ - "push r1 \n\t" \ - "clr r1 \n\t" \ - "push r2 \n\t" \ - "push r3 \n\t" \ - "push r4 \n\t" \ - "push r5 \n\t" \ - "push r6 \n\t" \ - "push r7 \n\t" \ - "push r8 \n\t" \ - "push r9 \n\t" \ - "push r10 \n\t" \ - "push r11 \n\t" \ - "push r12 \n\t" \ - "push r13 \n\t" \ - "push r14 \n\t" \ - "push r15 \n\t" \ - "push r16 \n\t" \ - "push r17 \n\t" \ - "push r18 \n\t" \ - "push r19 \n\t" \ - "push r20 \n\t" \ - "push r21 \n\t" \ - "push r22 \n\t" \ - "push r23 \n\t" \ - "push r24 \n\t" \ - "push r25 \n\t" \ - "push r26 \n\t" \ - "push r27 \n\t" \ - "push r28 \n\t" \ - "push r29 \n\t" \ - "push r30 \n\t" \ - "push r31 \n\t" \ - "lds r26, pxCurrentTCB \n\t" \ - "lds r27, pxCurrentTCB + 1 \n\t" \ - "in r0, __SP_L__ \n\t" \ - "st x+, r0 \n\t" \ - "in r0, __SP_H__ \n\t" \ - "st x+, r0 \n\t"); +#define portSAVE_CONTEXT() \ + asm volatile("push r0 \n\t" \ + "in r0, __SREG__ \n\t" \ + "cli \n\t" \ + "push r0 \n\t" \ + "push r1 \n\t" \ + "clr r1 \n\t" \ + "push r2 \n\t" \ + "push r3 \n\t" \ + "push r4 \n\t" \ + "push r5 \n\t" \ + "push r6 \n\t" \ + "push r7 \n\t" \ + "push r8 \n\t" \ + "push r9 \n\t" \ + "push r10 \n\t" \ + "push r11 \n\t" \ + "push r12 \n\t" \ + "push r13 \n\t" \ + "push r14 \n\t" \ + "push r15 \n\t" \ + "push r16 \n\t" \ + "push r17 \n\t" \ + "push r18 \n\t" \ + "push r19 \n\t" \ + "push r20 \n\t" \ + "push r21 \n\t" \ + "push r22 \n\t" \ + "push r23 \n\t" \ + "push r24 \n\t" \ + "push r25 \n\t" \ + "push r26 \n\t" \ + "push r27 \n\t" \ + "push r28 \n\t" \ + "push r29 \n\t" \ + "push r30 \n\t" \ + "push r31 \n\t" \ + "lds r26, pxCurrentTCB \n\t" \ + "lds r27, pxCurrentTCB + 1 \n\t" \ + "in r0, __SP_L__ \n\t" \ + "st x+, r0 \n\t" \ + "in r0, __SP_H__ \n\t" \ + "st x+, r0 \n\t"); /* * Opposite to portSAVE_CONTEXT(). Interrupts will have been disabled during * the context save so we can write to the stack pointer. */ -#define portRESTORE_CONTEXT() \ - asm volatile("lds r26, pxCurrentTCB \n\t" \ - "lds r27, pxCurrentTCB + 1 \n\t" \ - "ld r28, x+ \n\t" \ - "out __SP_L__, r28 \n\t" \ - "ld r29, x+ \n\t" \ - "out __SP_H__, r29 \n\t" \ - "pop r31 \n\t" \ - "pop r30 \n\t" \ - "pop r29 \n\t" \ - "pop r28 \n\t" \ - "pop r27 \n\t" \ - "pop r26 \n\t" \ - "pop r25 \n\t" \ - "pop r24 \n\t" \ - "pop r23 \n\t" \ - "pop r22 \n\t" \ - "pop r21 \n\t" \ - "pop r20 \n\t" \ - "pop r19 \n\t" \ - "pop r18 \n\t" \ - "pop r17 \n\t" \ - "pop r16 \n\t" \ - "pop r15 \n\t" \ - "pop r14 \n\t" \ - "pop r13 \n\t" \ - "pop r12 \n\t" \ - "pop r11 \n\t" \ - "pop r10 \n\t" \ - "pop r9 \n\t" \ - "pop r8 \n\t" \ - "pop r7 \n\t" \ - "pop r6 \n\t" \ - "pop r5 \n\t" \ - "pop r4 \n\t" \ - "pop r3 \n\t" \ - "pop r2 \n\t" \ - "pop r1 \n\t" \ - "pop r0 \n\t" \ - "out __SREG__, r0 \n\t" \ - "pop r0 \n\t"); +#define portRESTORE_CONTEXT() \ + asm volatile("lds r26, pxCurrentTCB \n\t" \ + "lds r27, pxCurrentTCB + 1 \n\t" \ + "ld r28, x+ \n\t" \ + "out __SP_L__, r28 \n\t" \ + "ld r29, x+ \n\t" \ + "out __SP_H__, r29 \n\t" \ + "pop r31 \n\t" \ + "pop r30 \n\t" \ + "pop r29 \n\t" \ + "pop r28 \n\t" \ + "pop r27 \n\t" \ + "pop r26 \n\t" \ + "pop r25 \n\t" \ + "pop r24 \n\t" \ + "pop r23 \n\t" \ + "pop r22 \n\t" \ + "pop r21 \n\t" \ + "pop r20 \n\t" \ + "pop r19 \n\t" \ + "pop r18 \n\t" \ + "pop r17 \n\t" \ + "pop r16 \n\t" \ + "pop r15 \n\t" \ + "pop r14 \n\t" \ + "pop r13 \n\t" \ + "pop r12 \n\t" \ + "pop r11 \n\t" \ + "pop r10 \n\t" \ + "pop r9 \n\t" \ + "pop r8 \n\t" \ + "pop r7 \n\t" \ + "pop r6 \n\t" \ + "pop r5 \n\t" \ + "pop r4 \n\t" \ + "pop r3 \n\t" \ + "pop r2 \n\t" \ + "pop r1 \n\t" \ + "pop r0 \n\t" \ + "out __SREG__, r0 \n\t" \ + "pop r0 \n\t"); /*-----------------------------------------------------------*/ @@ -171,81 +169,81 @@ static void prvSetupTimerInterrupt(void); */ StackType_t *pxPortInitialiseStack(StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters) { - uint16_t usAddress; + uint16_t usAddress; - /*lint -e950 -e611 -e923 Lint doesn't like this much - but nothing I can do about it. */ - - /* Place a few bytes of known values on the bottom of the stack. - This is just useful for debugging. Uncomment if needed. */ - // *pxTopOfStack = 0x11; + /*lint -e950 -e611 -e923 Lint doesn't like this much - but nothing I can do about it. */ + + /* Place a few bytes of known values on the bottom of the stack. + This is just useful for debugging. Uncomment if needed. */ + // *pxTopOfStack = 0x11; // pxTopOfStack--; // *pxTopOfStack = 0x22; // pxTopOfStack--; // *pxTopOfStack = 0x33; // pxTopOfStack--; - /* The start of the task code will be popped off the stack last, so place - it on first. */ - usAddress = (uint16_t)pxCode; - *pxTopOfStack = (StackType_t)(usAddress & (uint16_t)0x00ff); - pxTopOfStack--; + /* The start of the task code will be popped off the stack last, so place + it on first. */ + usAddress = (uint16_t)pxCode; + *pxTopOfStack = (StackType_t)(usAddress & (uint16_t)0x00ff); + pxTopOfStack--; - usAddress >>= 8; - *pxTopOfStack = (StackType_t)(usAddress & (uint16_t)0x00ff); - pxTopOfStack--; + usAddress >>= 8; + *pxTopOfStack = (StackType_t)(usAddress & (uint16_t)0x00ff); + pxTopOfStack--; - /* Next simulate the stack as if after a call to portSAVE_CONTEXT(). - portSAVE_CONTEXT places the flags on the stack immediately after r0 - to ensure the interrupts get disabled as soon as possible, and so ensuring - the stack use is minimal should a context switch interrupt occur. */ - *pxTopOfStack = (StackType_t)0x00; /* R0 */ - pxTopOfStack--; - *pxTopOfStack = portFLAGS_INT_ENABLED; - pxTopOfStack--; + /* Next simulate the stack as if after a call to portSAVE_CONTEXT(). + portSAVE_CONTEXT places the flags on the stack immediately after r0 + to ensure the interrupts get disabled as soon as possible, and so ensuring + the stack use is minimal should a context switch interrupt occur. */ + *pxTopOfStack = (StackType_t)0x00; /* R0 */ + pxTopOfStack--; + *pxTopOfStack = portFLAGS_INT_ENABLED; + pxTopOfStack--; - /* Now the remaining registers. The compiler expects R1 to be 0. */ - *pxTopOfStack = (StackType_t)0x00; /* R1 */ + /* Now the remaining registers. The compiler expects R1 to be 0. */ + *pxTopOfStack = (StackType_t)0x00; /* R1 */ - /* Leave R2 - R23 untouched */ - pxTopOfStack -= 23; + /* Leave R2 - R23 untouched */ + pxTopOfStack -= 23; - /* Place the parameter on the stack in the expected location. */ - usAddress = (uint16_t)pvParameters; - *pxTopOfStack = (StackType_t)(usAddress & (uint16_t)0x00ff); - pxTopOfStack--; + /* Place the parameter on the stack in the expected location. */ + usAddress = (uint16_t)pvParameters; + *pxTopOfStack = (StackType_t)(usAddress & (uint16_t)0x00ff); + pxTopOfStack--; - usAddress >>= 8; - *pxTopOfStack = (StackType_t)(usAddress & (uint16_t)0x00ff); + usAddress >>= 8; + *pxTopOfStack = (StackType_t)(usAddress & (uint16_t)0x00ff); - /* Leave register R26 - R31 untouched */ - pxTopOfStack -= 7; + /* Leave register R26 - R31 untouched */ + pxTopOfStack -= 7; - /*lint +e950 +e611 +e923 */ + /*lint +e950 +e611 +e923 */ - return pxTopOfStack; + return pxTopOfStack; } /*-----------------------------------------------------------*/ BaseType_t xPortStartScheduler(void) { - /* Setup the hardware to generate the tick. */ - prvSetupTimerInterrupt(); + /* Setup the hardware to generate the tick. */ + prvSetupTimerInterrupt(); - /* Restore the context of the first task that is going to run. */ - portRESTORE_CONTEXT(); + /* Restore the context of the first task that is going to run. */ + portRESTORE_CONTEXT(); - /* Simulate a function call end as generated by the compiler. We will now - jump to the start of the task the context of which we have just restored. */ - asm volatile("ret"); + /* Simulate a function call end as generated by the compiler. We will now + jump to the start of the task the context of which we have just restored. */ + asm volatile("ret"); - /* Should not get here. */ - return pdTRUE; + /* Should not get here. */ + return pdTRUE; } /*-----------------------------------------------------------*/ void vPortEndScheduler(void) { - /* vPortEndScheduler is not implemented in this port. */ + /* vPortEndScheduler is not implemented in this port. */ } /*-----------------------------------------------------------*/ @@ -256,10 +254,10 @@ void vPortEndScheduler(void) void vPortYield(void) __attribute__((naked)); void vPortYield(void) { - portSAVE_CONTEXT(); - vTaskSwitchContext(); - portRESTORE_CONTEXT(); - asm volatile("ret"); + portSAVE_CONTEXT(); + vTaskSwitchContext(); + portRESTORE_CONTEXT(); + asm volatile("ret"); } /*-----------------------------------------------------------*/ @@ -270,10 +268,10 @@ void vPortYield(void) void vPortYieldFromISR(void) __attribute__((naked)); void vPortYieldFromISR(void) { - portSAVE_CONTEXT(); - vTaskSwitchContext(); - portRESTORE_CONTEXT(); - asm volatile("reti"); + portSAVE_CONTEXT(); + vTaskSwitchContext(); + portRESTORE_CONTEXT(); + asm volatile("reti"); } /*-----------------------------------------------------------*/ @@ -286,14 +284,14 @@ void vPortYieldFromISR(void) void vPortYieldFromTick(void) __attribute__((naked)); void vPortYieldFromTick(void) { - portSAVE_CONTEXT(); - if (xTaskIncrementTick() != pdFALSE) { - vTaskSwitchContext(); - } + portSAVE_CONTEXT(); + if (xTaskIncrementTick() != pdFALSE) { + vTaskSwitchContext(); + } - portRESTORE_CONTEXT(); + portRESTORE_CONTEXT(); - asm volatile("reti"); + asm volatile("reti"); } /*-----------------------------------------------------------*/ @@ -302,7 +300,7 @@ void vPortYieldFromTick(void) */ static void prvSetupTimerInterrupt(void) { - TICK_init(); + TICK_init(); } /*-----------------------------------------------------------*/ @@ -315,12 +313,12 @@ static void prvSetupTimerInterrupt(void) */ ISR(TICK_INT_vect, ISR_NAKED) { - /* Clear tick interrupt flag. */ - CLR_INT(INT_FLAGS, INT_MASK); + /* Clear tick interrupt flag. */ + CLR_INT(INT_FLAGS, INT_MASK); - vPortYieldFromTick(); + vPortYieldFromTick(); - asm volatile("reti"); + asm volatile("reti"); } #else @@ -331,8 +329,8 @@ ISR(TICK_INT_vect, ISR_NAKED) */ ISR(TICK_INT_vect) { - /* Clear tick interrupt flag. */ - INT_FLAGS = INT_MASK; - xTaskIncrementTick(); + /* Clear tick interrupt flag. */ + INT_FLAGS = INT_MASK; + xTaskIncrementTick(); } #endif diff --git a/portable/GCC/AVR_Mega0/porthardware.h b/portable/GCC/AVR_Mega0/porthardware.h index b0d9002c1..aeeccf534 100644 --- a/portable/GCC/AVR_Mega0/porthardware.h +++ b/portable/GCC/AVR_Mega0/porthardware.h @@ -6,106 +6,84 @@ /*-----------------------------------------------------------*/ #define CLR_INT(FLAG_REG, FLAG_MASK) \ - asm volatile( "push r16\n\t" \ - "ldi r16, %1\n\t" \ - "sts %0, r16\n\t" \ - "pop r16\n\t" \ - : \ - : "i"(_SFR_MEM_ADDR(FLAG_REG)),"i"((uint8_t)(FLAG_MASK)) \ - ); + asm volatile( \ + "push r16\n\t" \ + "ldi r16, %1\n\t" \ + "sts %0, r16\n\t" \ + "pop r16\n\t" \ + : \ + : "i"(_SFR_MEM_ADDR(FLAG_REG)),"i"((uint8_t)(FLAG_MASK)) \ + ); #if ( configUSE_TIMER_INSTANCE == 0 ) - #define TICK_INT_vect TCB0_INT_vect - #define INT_FLAGS TCB0_INTFLAGS - #define INT_MASK TCB_CAPT_bm + #define TICK_INT_vect TCB0_INT_vect + #define INT_FLAGS TCB0_INTFLAGS + #define INT_MASK TCB_CAPT_bm - #define TICK_init() { \ - TCB0.CCMP = configCPU_CLOCK_HZ / configTICK_RATE_HZ; \ - TCB0.INTCTRL = TCB_CAPT_bm; \ - TCB0.CTRLA = TCB_ENABLE_bm; \ - } - - #define TICK_stop() { \ - TCB0.INTCTRL &= ~TCB_CAPT_bm;\ - TCB0.CTRLA &= ~TCB_ENABLE_bm; \ - } + #define TICK_init() { \ + TCB0.CCMP = configCPU_CLOCK_HZ / configTICK_RATE_HZ; \ + TCB0.INTCTRL = TCB_CAPT_bm; \ + TCB0.CTRLA = TCB_ENABLE_bm; \ + } #elif ( configUSE_TIMER_INSTANCE == 1 ) - #define TICK_INT_vect TCB1_INT_vect - #define INT_FLAGS TCB1_INTFLAGS - #define INT_MASK TCB_CAPT_bm + #define TICK_INT_vect TCB1_INT_vect + #define INT_FLAGS TCB1_INTFLAGS + #define INT_MASK TCB_CAPT_bm - #define TICK_init() { \ - TCB1.CCMP = configCPU_CLOCK_HZ / configTICK_RATE_HZ; \ - TCB1.INTCTRL = TCB_CAPT_bm; \ - TCB1.CTRLA = TCB_ENABLE_bm; \ - } - - #define TICK_stop() { \ - TCB1.INTCTRL &= ~TCB_CAPT_bm; \ - TCB1.CTRLA &= ~TCB_ENABLE_bm; \ - } + #define TICK_init() { \ + TCB1.CCMP = configCPU_CLOCK_HZ / configTICK_RATE_HZ; \ + TCB1.INTCTRL = TCB_CAPT_bm; \ + TCB1.CTRLA = TCB_ENABLE_bm; \ + } #elif ( configUSE_TIMER_INSTANCE == 2 ) - #define TICK_INT_vect TCB2_INT_vect - #define INT_FLAGS TCB2_INTFLAGS - #define INT_MASK TCB_CAPT_bm + #define TICK_INT_vect TCB2_INT_vect + #define INT_FLAGS TCB2_INTFLAGS + #define INT_MASK TCB_CAPT_bm - #define TICK_init() { \ - TCB2.CCMP = configCPU_CLOCK_HZ / configTICK_RATE_HZ; \ - TCB2.INTCTRL = TCB_CAPT_bm; \ - TCB2.CTRLA = TCB_ENABLE_bm; \ - } - - #define TICK_stop() { \ - TCB2.INTCTRL &= ~TCB_CAPT_bm; \ - TCB2.CTRLA &= ~TCB_ENABLE_bm; \ - } + #define TICK_init() { \ + TCB2.CCMP = configCPU_CLOCK_HZ / configTICK_RATE_HZ; \ + TCB2.INTCTRL = TCB_CAPT_bm; \ + TCB2.CTRLA = TCB_ENABLE_bm; \ + } #elif ( configUSE_TIMER_INSTANCE == 3 ) - #define TICK_INT_vect TCB3_INT_vect - #define INT_FLAGS TCB3_INTFLAGS - #define INT_MASK TCB_CAPT_bm + #define TICK_INT_vect TCB3_INT_vect + #define INT_FLAGS TCB3_INTFLAGS + #define INT_MASK TCB_CAPT_bm - #define TICK_init() { \ - TCB3.CCMP = configCPU_CLOCK_HZ / configTICK_RATE_HZ; \ - TCB3.INTCTRL = TCB_CAPT_bm; \ - TCB3.CTRLA = TCB_ENABLE_bm; \ - } - - #define TICK_stop() { \ - TCB3.INTCTRL &= ~TCB_CAPT_bm; \ - TCB3.CTRLA &= ~TCB_ENABLE_bm; \ - } + #define TICK_init() { \ + TCB3.CCMP = configCPU_CLOCK_HZ / configTICK_RATE_HZ; \ + TCB3.INTCTRL = TCB_CAPT_bm; \ + TCB3.CTRLA = TCB_ENABLE_bm; \ + } #elif ( configUSE_TIMER_INSTANCE == 4 ) - #define TICK_INT_vect RTC_CNT_vect - #define INT_FLAGS RTC_INTFLAGS - #define INT_MASK RTC_OVF_bm + #define TICK_INT_vect RTC_CNT_vect + #define INT_FLAGS RTC_INTFLAGS + #define INT_MASK RTC_OVF_bm - #define RTC_PERIOD_HZ(x) (32768 * ( (1.0 / x) ) ) - #define TICK_init() { \ - while (RTC.STATUS > 0); \ - RTC.CTRLA = RTC_PRESCALER_DIV1_gc | 1 << RTC_RTCEN_bp; \ - RTC.PER = RTC_PERIOD_HZ(configTICK_RATE_HZ); \ - RTC.INTCTRL |= 1 << RTC_OVF_bp; \ - } - - #define TICK_stop() { \ - RTC.CTRLA &= ~(1 << RTC_RTCEN_bp); \ - RTC.INTCTRL &= ~(1 << RTC_OVF_bp); \ - } + /* Hertz to period for RTC setup */ + #define RTC_PERIOD_HZ(x) ( 32768 * ( ( 1.0 / x ) ) ) + #define TICK_init() { \ + while (RTC.STATUS > 0); \ + RTC.CTRLA = RTC_PRESCALER_DIV1_gc | 1 << RTC_RTCEN_bp; \ + RTC.PER = RTC_PERIOD_HZ(configTICK_RATE_HZ); \ + RTC.INTCTRL |= 1 << RTC_OVF_bp; \ + } #else -#undef TICK_INT_vect -#undef INT_FLAGS -#undef INT_MASK -#error Invalid timer setting + #undef TICK_INT_vect + #undef INT_FLAGS + #undef INT_MASK + #undef TICK_init() + #error Invalid timer setting. #endif /*-----------------------------------------------------------*/ diff --git a/portable/GCC/AVR_Mega0/portmacro.h b/portable/GCC/AVR_Mega0/portmacro.h index 040f498fb..085a27fc1 100644 --- a/portable/GCC/AVR_Mega0/portmacro.h +++ b/portable/GCC/AVR_Mega0/portmacro.h @@ -68,13 +68,13 @@ typedef uint32_t TickType_t; /* Critical section management. */ #define portENTER_CRITICAL() \ - asm volatile("in __tmp_reg__, __SREG__"); \ - asm volatile("cli"); \ - asm volatile("push __tmp_reg__") + asm volatile("in __tmp_reg__, __SREG__"); \ + asm volatile("cli"); \ + asm volatile("push __tmp_reg__") #define portEXIT_CRITICAL() \ - asm volatile("pop __tmp_reg__"); \ - asm volatile("out __SREG__, __tmp_reg__") + asm volatile("pop __tmp_reg__"); \ + asm volatile("out __SREG__, __tmp_reg__") #define portDISABLE_INTERRUPTS() asm volatile("cli" ::); #define portENABLE_INTERRUPTS() asm volatile("sei" ::); @@ -85,7 +85,6 @@ typedef uint32_t TickType_t; #define portTICK_PERIOD_MS ((TickType_t)1000 / configTICK_RATE_HZ) #define portBYTE_ALIGNMENT 1 #define portNOP() asm volatile("nop"); - /*-----------------------------------------------------------*/ /* Kernel utilities. */ @@ -94,7 +93,6 @@ extern void vPortYield(void) __attribute__((naked)); extern void vPortYieldFromISR(void) __attribute__((naked)); #define portYIELD_FROM_ISR() vPortYieldFromISR() - /*-----------------------------------------------------------*/ /* Task function macros as described on the FreeRTOS.org WEB site. */ @@ -106,4 +104,3 @@ extern void vPortYieldFromISR(void) __attribute__((naked)); #endif #endif /* PORTMACRO_H */ - diff --git a/portable/IAR/ARM_CM0/port.c b/portable/IAR/ARM_CM0/port.c index d99af0fe2..f38d0e1a8 100644 --- a/portable/IAR/ARM_CM0/port.c +++ b/portable/IAR/ARM_CM0/port.c @@ -96,7 +96,6 @@ static UBaseType_t uxCriticalNesting = 0xaaaaaaaa; * file is weak to allow application writers to change the timer used to * generate the tick interrupt. */ -#pragma weak vPortSetupTimerInterrupt void vPortSetupTimerInterrupt( void ); /* @@ -242,7 +241,7 @@ void xPortSysTickHandler( void ) * Setup the systick timer to generate the tick interrupts at the required * frequency. */ -void vPortSetupTimerInterrupt( void ) +__weak void vPortSetupTimerInterrupt( void ) { /* Calculate the constants required to configure the tick interrupt. */ #if ( configUSE_TICKLESS_IDLE == 1 ) diff --git a/portable/IAR/ARM_CM23/non_secure/port.c b/portable/IAR/ARM_CM23/non_secure/port.c index b0bb8d9b1..3f39bc3b1 100644 --- a/portable/IAR/ARM_CM23/non_secure/port.c +++ b/portable/IAR/ARM_CM23/non_secure/port.c @@ -567,7 +567,7 @@ __attribute__( ( weak ) ) void vPortSetupTimerInterrupt( void ) /* PRIVILEGED_FU portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; /* Configure SysTick to interrupt at the requested rate. */ - portNVIC_SYSTICK_LOAD_REG = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; + portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT; } /*-----------------------------------------------------------*/ diff --git a/portable/IAR/ARM_CM23_NTZ/non_secure/port.c b/portable/IAR/ARM_CM23_NTZ/non_secure/port.c index b0bb8d9b1..3f39bc3b1 100644 --- a/portable/IAR/ARM_CM23_NTZ/non_secure/port.c +++ b/portable/IAR/ARM_CM23_NTZ/non_secure/port.c @@ -567,7 +567,7 @@ __attribute__( ( weak ) ) void vPortSetupTimerInterrupt( void ) /* PRIVILEGED_FU portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; /* Configure SysTick to interrupt at the requested rate. */ - portNVIC_SYSTICK_LOAD_REG = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; + portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT; } /*-----------------------------------------------------------*/ diff --git a/portable/IAR/ARM_CM33/non_secure/port.c b/portable/IAR/ARM_CM33/non_secure/port.c index b0bb8d9b1..3f39bc3b1 100644 --- a/portable/IAR/ARM_CM33/non_secure/port.c +++ b/portable/IAR/ARM_CM33/non_secure/port.c @@ -567,7 +567,7 @@ __attribute__( ( weak ) ) void vPortSetupTimerInterrupt( void ) /* PRIVILEGED_FU portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; /* Configure SysTick to interrupt at the requested rate. */ - portNVIC_SYSTICK_LOAD_REG = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; + portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT; } /*-----------------------------------------------------------*/ diff --git a/portable/IAR/ARM_CM33_NTZ/non_secure/port.c b/portable/IAR/ARM_CM33_NTZ/non_secure/port.c index b0bb8d9b1..3f39bc3b1 100644 --- a/portable/IAR/ARM_CM33_NTZ/non_secure/port.c +++ b/portable/IAR/ARM_CM33_NTZ/non_secure/port.c @@ -567,7 +567,7 @@ __attribute__( ( weak ) ) void vPortSetupTimerInterrupt( void ) /* PRIVILEGED_FU portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; /* Configure SysTick to interrupt at the requested rate. */ - portNVIC_SYSTICK_LOAD_REG = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; + portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT; } /*-----------------------------------------------------------*/ diff --git a/portable/IAR/ARM_CM4F_MPU/port.c b/portable/IAR/ARM_CM4F_MPU/port.c index ba83d86a1..05112ddb5 100644 --- a/portable/IAR/ARM_CM4F_MPU/port.c +++ b/portable/IAR/ARM_CM4F_MPU/port.c @@ -542,7 +542,7 @@ static void prvSetupMPU( void ) ( portUNPRIVILEGED_FLASH_REGION ); portMPU_REGION_ATTRIBUTE_REG = ( portMPU_REGION_READ_ONLY ) | - ( portMPU_REGION_CACHEABLE_BUFFERABLE ) | + ( ( configTEX_S_C_B_FLASH & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) | ( prvGetMPURegionSizeSetting( ( uint32_t ) __FLASH_segment_end__ - ( uint32_t ) __FLASH_segment_start__ ) ) | ( portMPU_REGION_ENABLE ); @@ -553,7 +553,7 @@ static void prvSetupMPU( void ) ( portPRIVILEGED_FLASH_REGION ); portMPU_REGION_ATTRIBUTE_REG = ( portMPU_REGION_PRIVILEGED_READ_ONLY ) | - ( portMPU_REGION_CACHEABLE_BUFFERABLE ) | + ( ( configTEX_S_C_B_FLASH & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) | ( prvGetMPURegionSizeSetting( ( uint32_t ) __privileged_functions_end__ - ( uint32_t ) __privileged_functions_start__ ) ) | ( portMPU_REGION_ENABLE ); @@ -564,7 +564,7 @@ static void prvSetupMPU( void ) ( portPRIVILEGED_RAM_REGION ); portMPU_REGION_ATTRIBUTE_REG = ( portMPU_REGION_PRIVILEGED_READ_WRITE ) | - ( portMPU_REGION_CACHEABLE_BUFFERABLE ) | + ( ( configTEX_S_C_B_SRAM & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) | prvGetMPURegionSizeSetting( ( uint32_t ) __privileged_data_end__ - ( uint32_t ) __privileged_data_start__ ) | ( portMPU_REGION_ENABLE ); @@ -633,7 +633,7 @@ void vPortStoreTaskMPUSettings( xMPU_SETTINGS * xMPUSettings, xMPUSettings->xRegion[ 0 ].ulRegionAttribute = ( portMPU_REGION_READ_WRITE ) | - ( portMPU_REGION_CACHEABLE_BUFFERABLE ) | + ( ( configTEX_S_C_B_SRAM & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) | ( prvGetMPURegionSizeSetting( ( uint32_t ) __SRAM_segment_end__ - ( uint32_t ) __SRAM_segment_start__ ) ) | ( portMPU_REGION_ENABLE ); @@ -646,7 +646,7 @@ void vPortStoreTaskMPUSettings( xMPU_SETTINGS * xMPUSettings, xMPUSettings->xRegion[ 1 ].ulRegionAttribute = ( portMPU_REGION_PRIVILEGED_READ_WRITE ) | - ( portMPU_REGION_CACHEABLE_BUFFERABLE ) | + ( ( configTEX_S_C_B_SRAM & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) | prvGetMPURegionSizeSetting( ( uint32_t ) __privileged_data_end__ - ( uint32_t ) __privileged_data_start__ ) | ( portMPU_REGION_ENABLE ); @@ -674,7 +674,7 @@ void vPortStoreTaskMPUSettings( xMPU_SETTINGS * xMPUSettings, xMPUSettings->xRegion[ 0 ].ulRegionAttribute = ( portMPU_REGION_READ_WRITE ) | /* Read and write. */ ( prvGetMPURegionSizeSetting( ulStackDepth * ( uint32_t ) sizeof( StackType_t ) ) ) | - ( portMPU_REGION_CACHEABLE_BUFFERABLE ) | + ( ( configTEX_S_C_B_SRAM & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) | ( portMPU_REGION_ENABLE ); } diff --git a/portable/IAR/ARM_CM4F_MPU/portmacro.h b/portable/IAR/ARM_CM4F_MPU/portmacro.h index 3214a1766..dc72bb934 100644 --- a/portable/IAR/ARM_CM4F_MPU/portmacro.h +++ b/portable/IAR/ARM_CM4F_MPU/portmacro.h @@ -83,6 +83,10 @@ #define portMPU_REGION_PRIVILEGED_READ_WRITE_UNPRIV_READ_ONLY ( 0x02UL << 24UL ) #define portMPU_REGION_CACHEABLE_BUFFERABLE ( 0x07UL << 16UL ) #define portMPU_REGION_EXECUTE_NEVER ( 0x01UL << 28UL ) + /* Location of the TEX,S,C,B bits in the MPU Region Attribute and Size + * Register (RASR). */ + #define portMPU_RASR_TEX_S_C_B_LOCATION ( 16UL ) + #define portMPU_RASR_TEX_S_C_B_MASK ( 0x3FUL ) /* MPU settings that can be overriden in FreeRTOSConfig.h. */ #ifndef configTOTAL_MPU_REGIONS @@ -90,6 +94,82 @@ #define configTOTAL_MPU_REGIONS ( 8UL ) #endif + /* + * The TEX, Shareable (S), Cacheable (C) and Bufferable (B) bits define the + * memory type, and where necessary the cacheable and shareable properties + * of the memory region. + * + * The TEX, C, and B bits together indicate the memory type of the region, + * and: + * - For Normal memory, the cacheable properties of the region. + * - For Device memory, whether the region is shareable. + * + * For Normal memory regions, the S bit indicates whether the region is + * shareable. For Strongly-ordered and Device memory, the S bit is ignored. + * + * See the following two tables for setting TEX, S, C and B bits for + * unprivileged flash, privileged flash and privileged RAM regions. + * + +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+ + | TEX | C | B | Memory type | Description or Normal region cacheability | Shareable? | + +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+ + | 000 | 0 | 0 | Strongly-ordered | Strongly ordered | Shareable | + +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+ + | 000 | 0 | 1 | Device | Shared device | Shareable | + +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+ + | 000 | 1 | 0 | Normal | Outer and inner write-through; no write allocate | S bit | + +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+ + | 000 | 1 | 1 | Normal | Outer and inner write-back; no write allocate | S bit | + +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+ + | 001 | 0 | 0 | Normal | Outer and inner Non-cacheable | S bit | + +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+ + | 001 | 0 | 1 | Reserved | Reserved | Reserved | + +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+ + | 001 | 1 | 0 | IMPLEMENTATION DEFINED | IMPLEMENTATION DEFINED | IMPLEMENTATION DEFINED | + +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+ + | 001 | 1 | 1 | Normal | Outer and inner write-back; write and read allocate | S bit | + +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+ + | 010 | 0 | 0 | Device | Non-shared device | Not shareable | + +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+ + | 010 | 0 | 1 | Reserved | Reserved | Reserved | + +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+ + | 010 | 1 | X | Reserved | Reserved | Reserved | + +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+ + | 011 | X | X | Reserved | Reserved | Reserved | + +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+ + | 1BB | A | A | Normal | Cached memory, with AA and BB indicating the inner and | Reserved | + | | | | | outer cacheability rules that must be exported on the | | + | | | | | bus. See the table below for the cacheability policy | | + | | | | | encoding. memory, BB=Outer policy, AA=Inner policy. | | + +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+ + + +-----------------------------------------+----------------------------------------+ + | AA or BB subfield of {TEX,C,B} encoding | Cacheability policy | + +-----------------------------------------+----------------------------------------+ + | 00 | Non-cacheable | + +-----------------------------------------+----------------------------------------+ + | 01 | Write-back, write and read allocate | + +-----------------------------------------+----------------------------------------+ + | 10 | Write-through, no write allocate | + +-----------------------------------------+----------------------------------------+ + | 11 | Write-back, no write allocate | + +-----------------------------------------+----------------------------------------+ + */ + + /* TEX, Shareable (S), Cacheable (C) and Bufferable (B) bits for flash + * region. */ + #ifndef configTEX_S_C_B_FLASH + /* Default to TEX=000, S=1, C=1, B=1 for backward compatibility. */ + #define configTEX_S_C_B_FLASH ( 0x07UL ) + #endif + + /* TEX, Shareable (S), Cacheable (C) and Bufferable (B) bits for RAM + * region. */ + #ifndef configTEX_S_C_B_SRAM + /* Default to TEX=000, S=1, C=1, B=1 for backward compatibility. */ + #define configTEX_S_C_B_SRAM ( 0x07UL ) + #endif + #define portUNPRIVILEGED_FLASH_REGION ( 0UL ) #define portPRIVILEGED_FLASH_REGION ( 1UL ) #define portPRIVILEGED_RAM_REGION ( 2UL ) diff --git a/portable/IAR/AVR_AVRDx/port.c b/portable/IAR/AVR_AVRDx/port.c new file mode 100644 index 000000000..824c1aa4e --- /dev/null +++ b/portable/IAR/AVR_AVRDx/port.c @@ -0,0 +1,293 @@ +/* + * FreeRTOS Kernel V10.0.0 + * Copyright (C) 2017 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. If you wish to use our Amazon + * FreeRTOS name, please do so in a fair use way that does not cause confusion. + * + * 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! + */ + +#include +#include "porthardware.h" +#include "FreeRTOS.h" +#include "task.h" + +/*----------------------------------------------------------- + * Implementation of functions defined in portable.h for the AVR port. + *----------------------------------------------------------*/ + +/* Start tasks with interrupts enables. */ +#define portFLAGS_INT_ENABLED ((StackType_t) 0x80) + +/*-----------------------------------------------------------*/ + + +#define portBYTES_USED_BY_RETURN_ADDRESS 2 +#define portNO_CRITICAL_NESTING ( ( UBaseType_t ) 0 ) + +/* Stores the critical section nesting. This must not be initialised to 0. +It will be initialised when a task starts. */ +UBaseType_t uxCriticalNesting = 0x50; +/* + * Setup timer to generate a tick interrupt. + */ +static void prvSetupTimerInterrupt(void); + +/* + * The IAR compiler does not have full support for inline assembler, so + * these are defined in the portmacro assembler file. + */ +extern void vPortYieldFromTick( void ); +extern void vPortStart( void ); + +/*-----------------------------------------------------------*/ + +/* + * See header file for description. + */ +StackType_t *pxPortInitialiseStack(StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters) +{ +uint16_t usAddress; +StackType_t *pxTopOfHardwareStack; + /* Simulate how the stack would look after a call to vPortYield(). */ + + /*lint -e950 -e611 -e923 Lint doesn't like this much - but nothing I can do about it. */ + + /* The IAR compiler requires two stacks per task. First there is the + hardware call stack which uses the AVR stack pointer. Second there is the + software stack (local variables, parameter passing, etc.) which uses the + AVR Y register. + This function places both stacks within the memory block passed in as the + first parameter. The hardware stack is placed at the bottom of the memory + block. A gap is then left for the hardware stack to grow. Next the software + stack is placed. The amount of space between the software and hardware + stacks is defined by configCALL_STACK_SIZE. + The first part of the stack is the hardware stack. Place the start + address of the task on the hardware stack. */ + + /* Place a few bytes of known values on the bottom of the stack. + This is just useful for debugging. */ + //*pxTopOfStack = 0x11; + //pxTopOfStack--; + //*pxTopOfStack = 0x22; + //pxTopOfStack--; + //*pxTopOfStack = 0x33; + //pxTopOfStack--; + + /* Remember where the top of the hardware stack is - this is required + below. */ + pxTopOfHardwareStack = pxTopOfStack; + + usAddress = ( uint16_t ) pxCode; + *pxTopOfStack = ( StackType_t ) ( usAddress & ( uint16_t ) 0x00ff ); + pxTopOfStack--; + + usAddress >>= 8; + *pxTopOfStack = ( StackType_t ) ( usAddress & ( uint16_t ) 0x00ff ); + pxTopOfStack--; + + /* Leave enough space for the hardware stack before starting the software + stack. The '- 2' is because we have already used two spaces for the + address of the start of the task. */ + pxTopOfStack -= ( configCALL_STACK_SIZE - 2 ); + + /* Next simulate the stack as if after a call to portSAVE_CONTEXT(). + portSAVE_CONTEXT places the flags on the stack immediately after r0 + to ensure the interrupts get disabled as soon as possible, and so ensuring + the stack use is minimal should a context switch interrupt occur. */ + *pxTopOfStack = ( StackType_t ) 0x00; /* R0 */ + pxTopOfStack--; + *pxTopOfStack = portFLAGS_INT_ENABLED; + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) 0x00; /* RAMPZ */ + pxTopOfStack--; + + /* Next place the address of the hardware stack. This is required so + the AVR stack pointer can be restored to point to the hardware stack. */ + pxTopOfHardwareStack -= portBYTES_USED_BY_RETURN_ADDRESS; + usAddress = ( uint16_t ) pxTopOfHardwareStack; + + /* SPL */ + *pxTopOfStack = ( StackType_t ) ( usAddress & ( uint16_t ) 0x00ff ); + pxTopOfStack--; + + /* SPH */ + usAddress >>= 8; + *pxTopOfStack = ( StackType_t ) ( usAddress & ( uint16_t ) 0x00ff ); + pxTopOfStack--; + + /* Now the remaining registers. */ + *pxTopOfStack = ( StackType_t ) 0x01; /* R1 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) 0x02; /* R2 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) 0x03; /* R3 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) 0x04; /* R4 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) 0x05; /* R5 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) 0x06; /* R6 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) 0x07; /* R7 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) 0x08; /* R8 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) 0x09; /* R9 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) 0x10; /* R10 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) 0x11; /* R11 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) 0x12; /* R12 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) 0x13; /* R13 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) 0x14; /* R14 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) 0x15; /* R15 */ + pxTopOfStack--; + + /* Place the parameter on the stack in the expected location. */ + usAddress = (uint16_t) pvParameters; + *pxTopOfStack = (StackType_t) (usAddress & (uint16_t) 0x00ff); + pxTopOfStack--; + + usAddress >>= 8; + *pxTopOfStack = (StackType_t) (usAddress & (uint16_t) 0x00ff); + pxTopOfStack--; + + *pxTopOfStack = ( StackType_t ) 0x18; /* R18 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) 0x19; /* R19 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) 0x20; /* R20 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) 0x21; /* R21 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) 0x22; /* R22 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) 0x23; /* R23 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) 0x24; /* R24 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) 0x25; /* R25 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) 0x26; /* R26 X */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) 0x27; /* R27 */ + pxTopOfStack--; + + /* The Y register is not stored as it is used as the software stack and + gets saved into the task control block. */ + + *pxTopOfStack = ( StackType_t ) 0x30; /* R30 Z */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) 0x031; /* R31 */ + + pxTopOfStack--; + *pxTopOfStack = portNO_CRITICAL_NESTING; /* Critical nesting is zero when the task starts. */ + + /*lint +e950 +e611 +e923 */ + + return pxTopOfStack; +} +/*-----------------------------------------------------------*/ + +BaseType_t xPortStartScheduler(void) +{ + /* Setup the hardware to generate the tick. */ + prvSetupTimerInterrupt(); + + /* Restore the context of the first task that is going to run. + Normally we would just call portRESTORE_CONTEXT() here, but as the IAR + compiler does not fully support inline assembler we have to make a call.*/ + vPortStart(); + + /* Should not get here. */ + return pdTRUE; +} +/*-----------------------------------------------------------*/ + +void vPortEndScheduler(void) +{ + /* vPortEndScheduler is not implemented in this port. */ +} + +/*-----------------------------------------------------------*/ + +/* + * Setup timer to generate a tick interrupt. + */ +static void prvSetupTimerInterrupt(void) +{ + TICK_init(); +} + +/*-----------------------------------------------------------*/ + +#if configUSE_PREEMPTION == 1 +/* + * Tick ISR for preemptive scheduler. We can use a naked attribute as + * the context is saved at the start of vPortYieldFromTick(). The tick + * count is incremented after the context is saved. + */ + +__task void TICK_INT(void) +{ + vPortYieldFromTick(); + asm("reti"); +} +#else +/* + * Tick ISR for the cooperative scheduler. All this does is increment the + * tick count. We don't need to switch context, this can only be done by + * manual calls to taskYIELD(); + */ + +__interrupt void TICK_INT(void) +{ + /* Clear tick interrupt flag. */ + INT_FLAGS = INT_MASK; + + xTaskIncrementTick(); +} +#endif + +/*-----------------------------------------------------------*/ + +void vPortEnterCritical( void ) +{ + portDISABLE_INTERRUPTS(); + uxCriticalNesting++; +} + +/*-----------------------------------------------------------*/ + +void vPortExitCritical( void ) +{ + uxCriticalNesting--; + if( uxCriticalNesting == portNO_CRITICAL_NESTING ) + { + portENABLE_INTERRUPTS(); + } +} diff --git a/portable/IAR/AVR_AVRDx/porthardware.h b/portable/IAR/AVR_AVRDx/porthardware.h new file mode 100644 index 000000000..195d881aa --- /dev/null +++ b/portable/IAR/AVR_AVRDx/porthardware.h @@ -0,0 +1,94 @@ +#ifndef PORTHARDWARE_H +#define PORTHARDWARE_H + +#include +#include "FreeRTOSConfig.h" + +/*-----------------------------------------------------------*/ + +#if ( configUSE_TIMER_INSTANCE == 0 ) + + #define TICK_INT_vect TCB0_INT_vect + #define INT_FLAGS TCB0_INTFLAGS + #define INT_MASK TCB_CAPT_bm + + #define TICK_init() { \ + TCB0.CCMP = configCPU_CLOCK_HZ / configTICK_RATE_HZ; \ + TCB0.INTCTRL = TCB_CAPT_bm; \ + TCB0.CTRLA = TCB_ENABLE_bm; \ + } + +#elif ( configUSE_TIMER_INSTANCE == 1 ) + + #define TICK_INT_vect TCB1_INT_vect + #define INT_FLAGS TCB1_INTFLAGS + #define INT_MASK TCB_CAPT_bm + + #define TICK_init() { \ + TCB1.CCMP = configCPU_CLOCK_HZ / configTICK_RATE_HZ; \ + TCB1.INTCTRL = TCB_CAPT_bm; \ + TCB1.CTRLA = TCB_ENABLE_bm; \ + } + +#elif ( configUSE_TIMER_INSTANCE == 2 ) + + #define TICK_INT_vect TCB2_INT_vect + #define INT_FLAGS TCB2_INTFLAGS + #define INT_MASK TCB_CAPT_bm + + #define TICK_init() { \ + TCB2.CCMP = configCPU_CLOCK_HZ / configTICK_RATE_HZ; \ + TCB2.INTCTRL = TCB_CAPT_bm; \ + TCB2.CTRLA = TCB_ENABLE_bm; \ + } + +#elif ( configUSE_TIMER_INSTANCE == 3 ) + + #define TICK_INT_vect TCB3_INT_vect + #define INT_FLAGS TCB3_INTFLAGS + #define INT_MASK TCB_CAPT_bm + + #define TICK_init() { \ + TCB3.CCMP = configCPU_CLOCK_HZ / configTICK_RATE_HZ; \ + TCB3.INTCTRL = TCB_CAPT_bm; \ + TCB3.CTRLA = TCB_ENABLE_bm; \ + } + +#elif ( configUSE_TIMER_INSTANCE == 4 ) + + #define TICK_INT_vect TCB4_INT_vect + #define INT_FLAGS TCB4_INTFLAGS + #define INT_MASK TCB_CAPT_bm + + #define TICK_init() { \ + TCB4.CCMP = configCPU_CLOCK_HZ / configTICK_RATE_HZ; \ + TCB4.INTCTRL = TCB_CAPT_bm; \ + TCB4.CTRLA = TCB_ENABLE_bm; \ + } + +#elif ( configUSE_TIMER_INSTANCE == 5 ) + + #define TICK_INT_vect RTC_CNT_vect + #define INT_FLAGS RTC_INTFLAGS + #define INT_MASK RTC_OVF_bm + + /* Hertz to period for RTC setup */ + #define RTC_PERIOD_HZ(x) ( 32768 * ( ( 1.0 / x ) ) ) + #define TICK_init() { \ + while (RTC.STATUS > 0); \ + RTC.CTRLA = RTC_PRESCALER_DIV1_gc | 1 << RTC_RTCEN_bp; \ + RTC.PER = RTC_PERIOD_HZ(configTICK_RATE_HZ); \ + RTC.INTCTRL |= 1 << RTC_OVF_bp; \ + } + +#else + #undef TICK_INT_vect + #undef INT_FLAGS + #undef INT_MASK + #undef TICK_init() + #error Invalid timer setting. +#endif + +/*-----------------------------------------------------------*/ + +#endif /* PORTHARDWARE_H */ diff --git a/portable/IAR/AVR_AVRDx/portmacro.h b/portable/IAR/AVR_AVRDx/portmacro.h new file mode 100644 index 000000000..555f41e10 --- /dev/null +++ b/portable/IAR/AVR_AVRDx/portmacro.h @@ -0,0 +1,105 @@ +/* + * FreeRTOS Kernel V10.0.0 + * Copyright (C) 2017 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. If you wish to use our Amazon + * FreeRTOS name, please do so in a fair use way that does not cause confusion. + * + * 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! + */ + +#ifndef PORTMACRO_H +#define PORTMACRO_H + +#ifdef __cplusplus +extern "C" { +#endif + +/*----------------------------------------------------------- + * Port specific definitions. + * + * The settings in this file configure FreeRTOS correctly for the + * given hardware and compiler. + * + * These settings should not be altered. + *----------------------------------------------------------- + */ + +/* Type definitions. */ +#define portCHAR char +#define portFLOAT float +#define portDOUBLE double +#define portLONG long +#define portSHORT int +#define portSTACK_TYPE uint8_t +#define portBASE_TYPE char + +#define portPOINTER_SIZE_TYPE uint16_t + +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)0xffffffffUL +#endif + +/*-----------------------------------------------------------*/ + +/* Critical section management. */ +extern void vPortEnterCritical( void ); +extern void vPortExitCritical( void ); + +#define portENTER_CRITICAL() vPortEnterCritical() +#define portEXIT_CRITICAL() vPortExitCritical() + +#define portDISABLE_INTERRUPTS() asm( "cli" ) +#define portENABLE_INTERRUPTS() asm( "sei" ) +/*-----------------------------------------------------------*/ + +/* Architecture specifics. */ +#define portSTACK_GROWTH (-1) +#define portTICK_PERIOD_MS ((TickType_t)1000 / configTICK_RATE_HZ) +#define portBYTE_ALIGNMENT 1 +#define portNOP() asm( "nop" ) +/*-----------------------------------------------------------*/ + +/* Kernel utilities. */ +extern void vPortYield(void); +#define portYIELD() vPortYield() + +extern void vPortYieldFromISR(void); +#define portYIELD_FROM_ISR() vPortYieldFromISR() +/*-----------------------------------------------------------*/ + +/* Task function macros as described on the FreeRTOS.org WEB site. */ +#define portTASK_FUNCTION_PROTO(vFunction, pvParameters) void vFunction(void *pvParameters) +#define portTASK_FUNCTION(vFunction, pvParameters) void vFunction(void *pvParameters) + +#ifdef __cplusplus +} +#endif + +#endif /* PORTMACRO_H */ diff --git a/portable/IAR/AVR_AVRDx/portmacro.s90 b/portable/IAR/AVR_AVRDx/portmacro.s90 new file mode 100644 index 000000000..70a12ec44 --- /dev/null +++ b/portable/IAR/AVR_AVRDx/portmacro.s90 @@ -0,0 +1,254 @@ +;/* +; * FreeRTOS Kernel V10.3.1 +; * Copyright (C) 2020 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! +; */ + +#include "porthardware.h" + +; Declare all extern symbols here - including any ISRs that are referenced in +; the vector table. + +; ISR functions +; ------------- +EXTERN TICK_INT + +; Functions used by scheduler +; --------------------------- +EXTERN vTaskSwitchContext +EXTERN pxCurrentTCB +EXTERN xTaskIncrementTick +EXTERN uxCriticalNesting + +; Functions implemented in this file +; ---------------------------------- +PUBLIC vPortYield +PUBLIC vPortYieldFromTick +PUBLIC vPortYieldFromISR +PUBLIC vPortStart + +; Interrupt vector table. +; ----------------------- +; +; For simplicity the RTOS tick interrupt routine uses the __task keyword. +; As the IAR compiler does not permit a function to be declared using both +; __task and __interrupt, the use of __task necessitates that the interrupt +; vector table be setup manually. +; +; To write an ISR, implement the ISR function using the __interrupt keyword +; but do not install the interrupt using the "#pragma vector=ABC" method. +; Instead manually place the name of the ISR in the vector table using an +; ORG and jmp instruction as demonstrated below. +; You will also have to add an EXTERN statement at the top of the file. + + ASEG + + ORG TICK_INT_vect ; Vector address + jmp TICK_INT ; ISR + + RSEG CODE + +CLR_INT MACRO FLAG_REG, FLAG_MASK + st -y, r16 + ldi r16, FLAG_MASK + sts FLAG_REG, r16 + ld r16, y+ + + ENDM + +; Saving and Restoring a Task Context and Task Switching +; ------------------------------------------------------ +; +; The IAR compiler does not fully support inline assembler, so saving and +; restoring a task context has to be written in an asm file. +; +; vPortYield() and vPortYieldFromTick() are usually written in C. Doing +; so in this case would required calls to be made to portSAVE_CONTEXT() and +; portRESTORE_CONTEXT(). This is dis-advantageous as the context switch +; function would require two extra jump and return instructions over the +; WinAVR equivalent. +; +; To avoid this I have opted to implement both vPortYield() and +; vPortYieldFromTick() in this assembly file. For convenience +; portSAVE_CONTEXT and portRESTORE_CONTEXT are implemented as macros. + +portSAVE_CONTEXT MACRO + st -y, r0 ; First save the r0 register - we need to use this. + in r0, SREG ; Obtain the SREG value so we can disable interrupts... + cli ; ... as soon as possible. + st -y, r0 ; Store the SREG as it was before we disabled interrupts. + + in r0, RAMPZ + st -y, r0 + + in r0, SPL ; Next store the hardware stack pointer. The IAR... + st -y, r0 ; ... compiler uses the hardware stack as a call stack ... + in r0, SPH ; ... only. + st -y, r0 + + st -y, r1 ; Now store the rest of the registers. Dont store the ... + st -y, r2 ; ... the Y register here as it is used as the software + st -y, r3 ; stack pointer and will get saved into the TCB. + st -y, r4 + st -y, r5 + st -y, r6 + st -y, r7 + st -y, r8 + st -y, r9 + st -y, r10 + st -y, r11 + st -y, r12 + st -y, r13 + st -y, r14 + st -y, r15 + st -y, r16 + st -y, r17 + st -y, r18 + st -y, r19 + st -y, r20 + st -y, r21 + st -y, r22 + st -y, r23 + st -y, r24 + st -y, r25 + st -y, r26 + st -y, r27 + st -y, r30 + st -y, r31 + + lds r0, uxCriticalNesting + st -y, r0 ; Store the critical nesting counter. + + lds r26, pxCurrentTCB ; Finally save the software stack pointer (Y ... + lds r27, pxCurrentTCB + 1 ; ... register) into the TCB. + st x+, r28 + st x+, r29 + + ENDM + + +portRESTORE_CONTEXT MACRO + lds r26, pxCurrentTCB + lds r27, pxCurrentTCB + 1 ; Restore the software stack pointer from ... + ld r28, x+ ; the TCB into the software stack pointer (... + ld r29, x+ ; ... the Y register). + + ld r0, y+ + sts uxCriticalNesting, r0 + + ld r31, y+ ; Restore the registers down to R0. The Y + ld r30, y+ ; register is missing from this list as it + ld r27, y+ ; has already been restored. + ld r26, y+ + ld r25, y+ + ld r24, y+ + ld r23, y+ + ld r22, y+ + ld r21, y+ + ld r20, y+ + ld r19, y+ + ld r18, y+ + ld r17, y+ + ld r16, y+ + ld r15, y+ + ld r14, y+ + ld r13, y+ + ld r12, y+ + ld r11, y+ + ld r10, y+ + ld r9, y+ + ld r8, y+ + ld r7, y+ + ld r6, y+ + ld r5, y+ + ld r4, y+ + ld r3, y+ + ld r2, y+ + ld r1, y+ + + ld r0, y+ ; The next thing on the stack is the ... + out SPH, r0 ; ... hardware stack pointer. + ld r0, y+ + out SPL, r0 + + ld r0, y+ + out RAMPZ, r0 + + ld r0, y+ ; Next there is the SREG register. + out SREG, r0 + + ld r0, y+ ; Finally we have finished with r0, so restore r0. + + ENDM + + + +; vPortYield(), vPortYieldFromTick() and vPortYieldFromISR() +; ------------------------------------- +; +; Manual and preemptive context switch functions respectively. +; The IAR compiler does not fully support inline assembler, +; so these are implemented here rather than the more usually +; place of within port.c. + +vPortYield: + portSAVE_CONTEXT ; Save the context of the current task. + call vTaskSwitchContext ; Call the scheduler. + portRESTORE_CONTEXT ; Restore the context of whichever task the ... + ret ; ... scheduler decided should run. + +vPortYieldFromTick: + CLR_INT INT_FLAGS, INT_MASK ; Clear tick interrupt flag + + portSAVE_CONTEXT ; Save the context of the current task. + call xTaskIncrementTick ; Call the timer tick function. + tst r16 + breq SkipTaskSwitch + call vTaskSwitchContext ; Call the scheduler. + +SkipTaskSwitch: + portRESTORE_CONTEXT ; Restore the context of whichever task the ... + reti ; ... scheduler decided should run. + +vPortYieldFromISR: + portSAVE_CONTEXT ; Save the context of the current task. + call vTaskSwitchContext ; Call the scheduler. + portRESTORE_CONTEXT ; Restore the context of whichever task the ... + reti ; ... scheduler decided should run. + +; vPortStart() +; ------------ +; +; Again due to the lack of inline assembler, this is required +; to get access to the portRESTORE_CONTEXT macro. + +vPortStart: + portRESTORE_CONTEXT + ret + +; Just a filler for unused interrupt vectors. +vNoISR: + reti + + END diff --git a/portable/IAR/AVR_Mega0/port.c b/portable/IAR/AVR_Mega0/port.c new file mode 100644 index 000000000..9e34e1b5e --- /dev/null +++ b/portable/IAR/AVR_Mega0/port.c @@ -0,0 +1,291 @@ +/* + * FreeRTOS Kernel V10.0.0 + * Copyright (C) 2017 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. If you wish to use our Amazon + * FreeRTOS name, please do so in a fair use way that does not cause confusion. + * + * 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! + */ + +#include +#include "porthardware.h" +#include "FreeRTOS.h" +#include "task.h" + +/*----------------------------------------------------------- + * Implementation of functions defined in portable.h for the AVR port. + *----------------------------------------------------------*/ + +/* Start tasks with interrupts enables. */ +#define portFLAGS_INT_ENABLED ((StackType_t) 0x80) + +/*-----------------------------------------------------------*/ + + +#define portBYTES_USED_BY_RETURN_ADDRESS 2 +#define portNO_CRITICAL_NESTING ( ( UBaseType_t ) 0 ) + +/* Stores the critical section nesting. This must not be initialised to 0. +It will be initialised when a task starts. */ +UBaseType_t uxCriticalNesting = 0x50; +/* + * Setup timer to generate a tick interrupt. + */ +static void prvSetupTimerInterrupt(void); + +/* + * The IAR compiler does not have full support for inline assembler, so + * these are defined in the portmacro assembler file. + */ +extern void vPortYieldFromTick( void ); +extern void vPortStart( void ); + +/*-----------------------------------------------------------*/ + +/* + * See header file for description. + */ +StackType_t *pxPortInitialiseStack(StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters) +{ +uint16_t usAddress; +StackType_t *pxTopOfHardwareStack; + /* Simulate how the stack would look after a call to vPortYield(). */ + + /*lint -e950 -e611 -e923 Lint doesn't like this much - but nothing I can do about it. */ + + /* The IAR compiler requires two stacks per task. First there is the + hardware call stack which uses the AVR stack pointer. Second there is the + software stack (local variables, parameter passing, etc.) which uses the + AVR Y register. + This function places both stacks within the memory block passed in as the + first parameter. The hardware stack is placed at the bottom of the memory + block. A gap is then left for the hardware stack to grow. Next the software + stack is placed. The amount of space between the software and hardware + stacks is defined by configCALL_STACK_SIZE. + The first part of the stack is the hardware stack. Place the start + address of the task on the hardware stack. */ + + /* Place a few bytes of known values on the bottom of the stack. + This is just useful for debugging. */ + //*pxTopOfStack = 0x11; + //pxTopOfStack--; + //*pxTopOfStack = 0x22; + //pxTopOfStack--; + //*pxTopOfStack = 0x33; + //pxTopOfStack--; + + /* Remember where the top of the hardware stack is - this is required + below. */ + pxTopOfHardwareStack = pxTopOfStack; + + usAddress = ( uint16_t ) pxCode; + *pxTopOfStack = ( StackType_t ) ( usAddress & ( uint16_t ) 0x00ff ); + pxTopOfStack--; + + usAddress >>= 8; + *pxTopOfStack = ( StackType_t ) ( usAddress & ( uint16_t ) 0x00ff ); + pxTopOfStack--; + + /* Leave enough space for the hardware stack before starting the software + stack. The '- 2' is because we have already used two spaces for the + address of the start of the task. */ + pxTopOfStack -= ( configCALL_STACK_SIZE - 2 ); + + /* Next simulate the stack as if after a call to portSAVE_CONTEXT(). + portSAVE_CONTEXT places the flags on the stack immediately after r0 + to ensure the interrupts get disabled as soon as possible, and so ensuring + the stack use is minimal should a context switch interrupt occur. */ + *pxTopOfStack = ( StackType_t ) 0x00; /* R0 */ + pxTopOfStack--; + *pxTopOfStack = portFLAGS_INT_ENABLED; + pxTopOfStack--; + + /* Next place the address of the hardware stack. This is required so + the AVR stack pointer can be restored to point to the hardware stack. */ + pxTopOfHardwareStack -= portBYTES_USED_BY_RETURN_ADDRESS; + usAddress = ( uint16_t ) pxTopOfHardwareStack; + + /* SPL */ + *pxTopOfStack = ( StackType_t ) ( usAddress & ( uint16_t ) 0x00ff ); + pxTopOfStack--; + + /* SPH */ + usAddress >>= 8; + *pxTopOfStack = ( StackType_t ) ( usAddress & ( uint16_t ) 0x00ff ); + pxTopOfStack--; + + /* Now the remaining registers. */ + *pxTopOfStack = ( StackType_t ) 0x01; /* R1 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) 0x02; /* R2 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) 0x03; /* R3 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) 0x04; /* R4 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) 0x05; /* R5 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) 0x06; /* R6 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) 0x07; /* R7 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) 0x08; /* R8 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) 0x09; /* R9 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) 0x10; /* R10 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) 0x11; /* R11 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) 0x12; /* R12 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) 0x13; /* R13 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) 0x14; /* R14 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) 0x15; /* R15 */ + pxTopOfStack--; + + /* Place the parameter on the stack in the expected location. */ + usAddress = (uint16_t) pvParameters; + *pxTopOfStack = (StackType_t) (usAddress & (uint16_t) 0x00ff); + pxTopOfStack--; + + usAddress >>= 8; + *pxTopOfStack = (StackType_t) (usAddress & (uint16_t) 0x00ff); + pxTopOfStack--; + + *pxTopOfStack = ( StackType_t ) 0x18; /* R18 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) 0x19; /* R19 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) 0x20; /* R20 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) 0x21; /* R21 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) 0x22; /* R22 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) 0x23; /* R23 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) 0x24; /* R24 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) 0x25; /* R25 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) 0x26; /* R26 X */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) 0x27; /* R27 */ + pxTopOfStack--; + + /* The Y register is not stored as it is used as the software stack and + gets saved into the task control block. */ + + *pxTopOfStack = ( StackType_t ) 0x30; /* R30 Z */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) 0x031; /* R31 */ + + pxTopOfStack--; + *pxTopOfStack = portNO_CRITICAL_NESTING; /* Critical nesting is zero when the task starts. */ + + /*lint +e950 +e611 +e923 */ + + return pxTopOfStack; +} +/*-----------------------------------------------------------*/ + +BaseType_t xPortStartScheduler(void) +{ + /* Setup the hardware to generate the tick. */ + prvSetupTimerInterrupt(); + + /* Restore the context of the first task that is going to run. + Normally we would just call portRESTORE_CONTEXT() here, but as the IAR + compiler does not fully support inline assembler we have to make a call.*/ + vPortStart(); + + /* Should not get here. */ + return pdTRUE; +} +/*-----------------------------------------------------------*/ + +void vPortEndScheduler(void) +{ + /* vPortEndScheduler is not implemented in this port. */ +} + +/*-----------------------------------------------------------*/ + +/* + * Setup timer to generate a tick interrupt. + */ +static void prvSetupTimerInterrupt(void) +{ + TICK_init(); +} + +/*-----------------------------------------------------------*/ + +#if configUSE_PREEMPTION == 1 +/* + * Tick ISR for preemptive scheduler. We can use a naked attribute as + * the context is saved at the start of vPortYieldFromTick(). The tick + * count is incremented after the context is saved. + */ + +__task void TICK_INT(void) +{ + vPortYieldFromTick(); + asm("reti"); +} +#else +/* + * Tick ISR for the cooperative scheduler. All this does is increment the + * tick count. We don't need to switch context, this can only be done by + * manual calls to taskYIELD(); + */ + +__interrupt void TICK_INT(void) +{ + /* Clear tick interrupt flag. */ + INT_FLAGS = INT_MASK; + + xTaskIncrementTick(); +} +#endif + +/*-----------------------------------------------------------*/ + +void vPortEnterCritical( void ) +{ + portDISABLE_INTERRUPTS(); + uxCriticalNesting++; +} + +/*-----------------------------------------------------------*/ + +void vPortExitCritical( void ) +{ + uxCriticalNesting--; + if( uxCriticalNesting == portNO_CRITICAL_NESTING ) + { + portENABLE_INTERRUPTS(); + } +} diff --git a/portable/IAR/AVR_Mega0/porthardware.h b/portable/IAR/AVR_Mega0/porthardware.h new file mode 100644 index 000000000..5468bdabe --- /dev/null +++ b/portable/IAR/AVR_Mega0/porthardware.h @@ -0,0 +1,82 @@ +#ifndef PORTHARDWARE_H +#define PORTHARDWARE_H + +#include +#include "FreeRTOSConfig.h" + +/*-----------------------------------------------------------*/ + +#if ( configUSE_TIMER_INSTANCE == 0 ) + + #define TICK_INT_vect TCB0_INT_vect + #define INT_FLAGS TCB0_INTFLAGS + #define INT_MASK TCB_CAPT_bm + + #define TICK_init() { \ + TCB0.CCMP = configCPU_CLOCK_HZ / configTICK_RATE_HZ; \ + TCB0.INTCTRL = TCB_CAPT_bm; \ + TCB0.CTRLA = TCB_ENABLE_bm; \ + } + +#elif ( configUSE_TIMER_INSTANCE == 1 ) + + #define TICK_INT_vect TCB1_INT_vect + #define INT_FLAGS TCB1_INTFLAGS + #define INT_MASK TCB_CAPT_bm + + #define TICK_init() { \ + TCB1.CCMP = configCPU_CLOCK_HZ / configTICK_RATE_HZ; \ + TCB1.INTCTRL = TCB_CAPT_bm; \ + TCB1.CTRLA = TCB_ENABLE_bm; \ + } + +#elif ( configUSE_TIMER_INSTANCE == 2 ) + + #define TICK_INT_vect TCB2_INT_vect + #define INT_FLAGS TCB2_INTFLAGS + #define INT_MASK TCB_CAPT_bm + + #define TICK_init() { \ + TCB2.CCMP = configCPU_CLOCK_HZ / configTICK_RATE_HZ; \ + TCB2.INTCTRL = TCB_CAPT_bm; \ + TCB2.CTRLA = TCB_ENABLE_bm; \ + } + +#elif ( configUSE_TIMER_INSTANCE == 3 ) + + #define TICK_INT_vect TCB3_INT_vect + #define INT_FLAGS TCB3_INTFLAGS + #define INT_MASK TCB_CAPT_bm + + #define TICK_init() { \ + TCB3.CCMP = configCPU_CLOCK_HZ / configTICK_RATE_HZ; \ + TCB3.INTCTRL = TCB_CAPT_bm; \ + TCB3.CTRLA = TCB_ENABLE_bm; \ + } + +#elif ( configUSE_TIMER_INSTANCE == 4 ) + + #define TICK_INT_vect RTC_CNT_vect + #define INT_FLAGS RTC_INTFLAGS + #define INT_MASK RTC_OVF_bm + + /* Hertz to period for RTC setup */ + #define RTC_PERIOD_HZ(x) ( 32768 * ( ( 1.0 / x ) ) ) + #define TICK_init() { \ + while (RTC.STATUS > 0); \ + RTC.CTRLA = RTC_PRESCALER_DIV1_gc | 1 << RTC_RTCEN_bp; \ + RTC.PER = RTC_PERIOD_HZ(configTICK_RATE_HZ); \ + RTC.INTCTRL |= 1 << RTC_OVF_bp; \ + } + +#else + #undef TICK_INT_vect + #undef INT_FLAGS + #undef INT_MASK + #undef TICK_init() + #error Invalid timer setting. +#endif + +/*-----------------------------------------------------------*/ + +#endif /* PORTHARDWARE_H */ diff --git a/portable/IAR/AVR_Mega0/portmacro.h b/portable/IAR/AVR_Mega0/portmacro.h new file mode 100644 index 000000000..555f41e10 --- /dev/null +++ b/portable/IAR/AVR_Mega0/portmacro.h @@ -0,0 +1,105 @@ +/* + * FreeRTOS Kernel V10.0.0 + * Copyright (C) 2017 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. If you wish to use our Amazon + * FreeRTOS name, please do so in a fair use way that does not cause confusion. + * + * 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! + */ + +#ifndef PORTMACRO_H +#define PORTMACRO_H + +#ifdef __cplusplus +extern "C" { +#endif + +/*----------------------------------------------------------- + * Port specific definitions. + * + * The settings in this file configure FreeRTOS correctly for the + * given hardware and compiler. + * + * These settings should not be altered. + *----------------------------------------------------------- + */ + +/* Type definitions. */ +#define portCHAR char +#define portFLOAT float +#define portDOUBLE double +#define portLONG long +#define portSHORT int +#define portSTACK_TYPE uint8_t +#define portBASE_TYPE char + +#define portPOINTER_SIZE_TYPE uint16_t + +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)0xffffffffUL +#endif + +/*-----------------------------------------------------------*/ + +/* Critical section management. */ +extern void vPortEnterCritical( void ); +extern void vPortExitCritical( void ); + +#define portENTER_CRITICAL() vPortEnterCritical() +#define portEXIT_CRITICAL() vPortExitCritical() + +#define portDISABLE_INTERRUPTS() asm( "cli" ) +#define portENABLE_INTERRUPTS() asm( "sei" ) +/*-----------------------------------------------------------*/ + +/* Architecture specifics. */ +#define portSTACK_GROWTH (-1) +#define portTICK_PERIOD_MS ((TickType_t)1000 / configTICK_RATE_HZ) +#define portBYTE_ALIGNMENT 1 +#define portNOP() asm( "nop" ) +/*-----------------------------------------------------------*/ + +/* Kernel utilities. */ +extern void vPortYield(void); +#define portYIELD() vPortYield() + +extern void vPortYieldFromISR(void); +#define portYIELD_FROM_ISR() vPortYieldFromISR() +/*-----------------------------------------------------------*/ + +/* Task function macros as described on the FreeRTOS.org WEB site. */ +#define portTASK_FUNCTION_PROTO(vFunction, pvParameters) void vFunction(void *pvParameters) +#define portTASK_FUNCTION(vFunction, pvParameters) void vFunction(void *pvParameters) + +#ifdef __cplusplus +} +#endif + +#endif /* PORTMACRO_H */ diff --git a/portable/IAR/AVR_Mega0/portmacro.s90 b/portable/IAR/AVR_Mega0/portmacro.s90 new file mode 100644 index 000000000..4b117d7b6 --- /dev/null +++ b/portable/IAR/AVR_Mega0/portmacro.s90 @@ -0,0 +1,248 @@ +;/* +; * FreeRTOS Kernel V10.3.1 +; * Copyright (C) 2020 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! +; */ + +#include "porthardware.h" + +; Declare all extern symbols here - including any ISRs that are referenced in +; the vector table. + +; ISR functions +; ------------- +EXTERN TICK_INT + +; Functions used by scheduler +; --------------------------- +EXTERN vTaskSwitchContext +EXTERN pxCurrentTCB +EXTERN xTaskIncrementTick +EXTERN uxCriticalNesting + +; Functions implemented in this file +; ---------------------------------- +PUBLIC vPortYield +PUBLIC vPortYieldFromTick +PUBLIC vPortYieldFromISR +PUBLIC vPortStart + +; Interrupt vector table. +; ----------------------- +; +; For simplicity the RTOS tick interrupt routine uses the __task keyword. +; As the IAR compiler does not permit a function to be declared using both +; __task and __interrupt, the use of __task necessitates that the interrupt +; vector table be setup manually. +; +; To write an ISR, implement the ISR function using the __interrupt keyword +; but do not install the interrupt using the "#pragma vector=ABC" method. +; Instead manually place the name of the ISR in the vector table using an +; ORG and jmp instruction as demonstrated below. +; You will also have to add an EXTERN statement at the top of the file. + + ASEG + + ORG TICK_INT_vect ; Vector address + jmp TICK_INT ; ISR + + RSEG CODE + +CLR_INT MACRO FLAG_REG, FLAG_MASK + st -y, r16 + ldi r16, FLAG_MASK + sts FLAG_REG, r16 + ld r16, y+ + + ENDM + +; Saving and Restoring a Task Context and Task Switching +; ------------------------------------------------------ +; +; The IAR compiler does not fully support inline assembler, so saving and +; restoring a task context has to be written in an asm file. +; +; vPortYield() and vPortYieldFromTick() are usually written in C. Doing +; so in this case would required calls to be made to portSAVE_CONTEXT() and +; portRESTORE_CONTEXT(). This is dis-advantageous as the context switch +; function would require two extra jump and return instructions over the +; WinAVR equivalent. +; +; To avoid this I have opted to implement both vPortYield() and +; vPortYieldFromTick() in this assembly file. For convenience +; portSAVE_CONTEXT and portRESTORE_CONTEXT are implemented as macros. + +portSAVE_CONTEXT MACRO + st -y, r0 ; First save the r0 register - we need to use this. + in r0, SREG ; Obtain the SREG value so we can disable interrupts... + cli ; ... as soon as possible. + st -y, r0 ; Store the SREG as it was before we disabled interrupts. + + in r0, SPL ; Next store the hardware stack pointer. The IAR... + st -y, r0 ; ... compiler uses the hardware stack as a call stack ... + in r0, SPH ; ... only. + st -y, r0 + + st -y, r1 ; Now store the rest of the registers. Dont store the ... + st -y, r2 ; ... the Y register here as it is used as the software + st -y, r3 ; stack pointer and will get saved into the TCB. + st -y, r4 + st -y, r5 + st -y, r6 + st -y, r7 + st -y, r8 + st -y, r9 + st -y, r10 + st -y, r11 + st -y, r12 + st -y, r13 + st -y, r14 + st -y, r15 + st -y, r16 + st -y, r17 + st -y, r18 + st -y, r19 + st -y, r20 + st -y, r21 + st -y, r22 + st -y, r23 + st -y, r24 + st -y, r25 + st -y, r26 + st -y, r27 + st -y, r30 + st -y, r31 + + lds r0, uxCriticalNesting + st -y, r0 ; Store the critical nesting counter. + + lds r26, pxCurrentTCB ; Finally save the software stack pointer (Y ... + lds r27, pxCurrentTCB + 1 ; ... register) into the TCB. + st x+, r28 + st x+, r29 + + ENDM + + +portRESTORE_CONTEXT MACRO + lds r26, pxCurrentTCB + lds r27, pxCurrentTCB + 1 ; Restore the software stack pointer from ... + ld r28, x+ ; the TCB into the software stack pointer (... + ld r29, x+ ; ... the Y register). + + ld r0, y+ + sts uxCriticalNesting, r0 + + ld r31, y+ ; Restore the registers down to R0. The Y + ld r30, y+ ; register is missing from this list as it + ld r27, y+ ; has already been restored. + ld r26, y+ + ld r25, y+ + ld r24, y+ + ld r23, y+ + ld r22, y+ + ld r21, y+ + ld r20, y+ + ld r19, y+ + ld r18, y+ + ld r17, y+ + ld r16, y+ + ld r15, y+ + ld r14, y+ + ld r13, y+ + ld r12, y+ + ld r11, y+ + ld r10, y+ + ld r9, y+ + ld r8, y+ + ld r7, y+ + ld r6, y+ + ld r5, y+ + ld r4, y+ + ld r3, y+ + ld r2, y+ + ld r1, y+ + + ld r0, y+ ; The next thing on the stack is the ... + out SPH, r0 ; ... hardware stack pointer. + ld r0, y+ + out SPL, r0 + + ld r0, y+ ; Next there is the SREG register. + out SREG, r0 + + ld r0, y+ ; Finally we have finished with r0, so restore r0. + + ENDM + + + +; vPortYield(), vPortYieldFromTick() and vPortYieldFromISR() +; ------------------------------------- +; +; Manual and preemptive context switch functions respectively. +; The IAR compiler does not fully support inline assembler, +; so these are implemented here rather than the more usually +; place of within port.c. + +vPortYield: + portSAVE_CONTEXT ; Save the context of the current task. + call vTaskSwitchContext ; Call the scheduler. + portRESTORE_CONTEXT ; Restore the context of whichever task the ... + ret ; ... scheduler decided should run. + +vPortYieldFromTick: + CLR_INT INT_FLAGS, INT_MASK ; Clear tick interrupt flag + + portSAVE_CONTEXT ; Save the context of the current task. + call xTaskIncrementTick ; Call the timer tick function. + tst r16 + breq SkipTaskSwitch + call vTaskSwitchContext ; Call the scheduler. + +SkipTaskSwitch: + portRESTORE_CONTEXT ; Restore the context of whichever task the ... + reti ; ... scheduler decided should run. + +vPortYieldFromISR: + portSAVE_CONTEXT ; Save the context of the current task. + call vTaskSwitchContext ; Call the scheduler. + portRESTORE_CONTEXT ; Restore the context of whichever task the ... + reti ; ... scheduler decided should run. + +; vPortStart() +; ------------ +; +; Again due to the lack of inline assembler, this is required +; to get access to the portRESTORE_CONTEXT macro. + +vPortStart: + portRESTORE_CONTEXT + ret + +; Just a filler for unused interrupt vectors. +vNoISR: + reti + +END diff --git a/portable/RVDS/ARM_CM4_MPU/port.c b/portable/RVDS/ARM_CM4_MPU/port.c index ec7c286b4..18228f45e 100644 --- a/portable/RVDS/ARM_CM4_MPU/port.c +++ b/portable/RVDS/ARM_CM4_MPU/port.c @@ -690,7 +690,7 @@ static void prvSetupMPU( void ) ( portUNPRIVILEGED_FLASH_REGION ); portMPU_REGION_ATTRIBUTE_REG = ( portMPU_REGION_READ_ONLY ) | - ( portMPU_REGION_CACHEABLE_BUFFERABLE ) | + ( ( configTEX_S_C_B_FLASH & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) | ( prvGetMPURegionSizeSetting( ( uint32_t ) __FLASH_segment_end__ - ( uint32_t ) __FLASH_segment_start__ ) ) | ( portMPU_REGION_ENABLE ); @@ -701,7 +701,7 @@ static void prvSetupMPU( void ) ( portPRIVILEGED_FLASH_REGION ); portMPU_REGION_ATTRIBUTE_REG = ( portMPU_REGION_PRIVILEGED_READ_ONLY ) | - ( portMPU_REGION_CACHEABLE_BUFFERABLE ) | + ( ( configTEX_S_C_B_FLASH & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) | ( prvGetMPURegionSizeSetting( ( uint32_t ) __privileged_functions_end__ - ( uint32_t ) __privileged_functions_start__ ) ) | ( portMPU_REGION_ENABLE ); @@ -712,7 +712,7 @@ static void prvSetupMPU( void ) ( portPRIVILEGED_RAM_REGION ); portMPU_REGION_ATTRIBUTE_REG = ( portMPU_REGION_PRIVILEGED_READ_WRITE ) | - ( portMPU_REGION_CACHEABLE_BUFFERABLE ) | + ( ( configTEX_S_C_B_SRAM & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) | prvGetMPURegionSizeSetting( ( uint32_t ) __privileged_data_end__ - ( uint32_t ) __privileged_data_start__ ) | ( portMPU_REGION_ENABLE ); @@ -807,7 +807,7 @@ void vPortStoreTaskMPUSettings( xMPU_SETTINGS * xMPUSettings, xMPUSettings->xRegion[ 0 ].ulRegionAttribute = ( portMPU_REGION_READ_WRITE ) | - ( portMPU_REGION_CACHEABLE_BUFFERABLE ) | + ( ( configTEX_S_C_B_SRAM & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) | ( prvGetMPURegionSizeSetting( ( uint32_t ) __SRAM_segment_end__ - ( uint32_t ) __SRAM_segment_start__ ) ) | ( portMPU_REGION_ENABLE ); @@ -820,7 +820,7 @@ void vPortStoreTaskMPUSettings( xMPU_SETTINGS * xMPUSettings, xMPUSettings->xRegion[ 1 ].ulRegionAttribute = ( portMPU_REGION_PRIVILEGED_READ_WRITE ) | - ( portMPU_REGION_CACHEABLE_BUFFERABLE ) | + ( ( configTEX_S_C_B_SRAM & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) | prvGetMPURegionSizeSetting( ( uint32_t ) __privileged_data_end__ - ( uint32_t ) __privileged_data_start__ ) | ( portMPU_REGION_ENABLE ); @@ -848,7 +848,7 @@ void vPortStoreTaskMPUSettings( xMPU_SETTINGS * xMPUSettings, xMPUSettings->xRegion[ 0 ].ulRegionAttribute = ( portMPU_REGION_READ_WRITE ) | /* Read and write. */ ( prvGetMPURegionSizeSetting( ulStackDepth * ( uint32_t ) sizeof( StackType_t ) ) ) | - ( portMPU_REGION_CACHEABLE_BUFFERABLE ) | + ( ( configTEX_S_C_B_SRAM & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) | ( portMPU_REGION_ENABLE ); } diff --git a/portable/RVDS/ARM_CM4_MPU/portmacro.h b/portable/RVDS/ARM_CM4_MPU/portmacro.h index 1cbb8b6e1..e5f5b1234 100644 --- a/portable/RVDS/ARM_CM4_MPU/portmacro.h +++ b/portable/RVDS/ARM_CM4_MPU/portmacro.h @@ -80,6 +80,10 @@ #define portMPU_REGION_PRIVILEGED_READ_WRITE_UNPRIV_READ_ONLY ( 0x02UL << 24UL ) #define portMPU_REGION_CACHEABLE_BUFFERABLE ( 0x07UL << 16UL ) #define portMPU_REGION_EXECUTE_NEVER ( 0x01UL << 28UL ) + /* Location of the TEX,S,C,B bits in the MPU Region Attribute and Size + * Register (RASR). */ + #define portMPU_RASR_TEX_S_C_B_LOCATION ( 16UL ) + #define portMPU_RASR_TEX_S_C_B_MASK ( 0x3FUL ) /* MPU settings that can be overriden in FreeRTOSConfig.h. */ #ifndef configTOTAL_MPU_REGIONS @@ -87,6 +91,82 @@ #define configTOTAL_MPU_REGIONS ( 8UL ) #endif + /* + * The TEX, Shareable (S), Cacheable (C) and Bufferable (B) bits define the + * memory type, and where necessary the cacheable and shareable properties + * of the memory region. + * + * The TEX, C, and B bits together indicate the memory type of the region, + * and: + * - For Normal memory, the cacheable properties of the region. + * - For Device memory, whether the region is shareable. + * + * For Normal memory regions, the S bit indicates whether the region is + * shareable. For Strongly-ordered and Device memory, the S bit is ignored. + * + * See the following two tables for setting TEX, S, C and B bits for + * unprivileged flash, privileged flash and privileged RAM regions. + * + +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+ + | TEX | C | B | Memory type | Description or Normal region cacheability | Shareable? | + +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+ + | 000 | 0 | 0 | Strongly-ordered | Strongly ordered | Shareable | + +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+ + | 000 | 0 | 1 | Device | Shared device | Shareable | + +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+ + | 000 | 1 | 0 | Normal | Outer and inner write-through; no write allocate | S bit | + +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+ + | 000 | 1 | 1 | Normal | Outer and inner write-back; no write allocate | S bit | + +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+ + | 001 | 0 | 0 | Normal | Outer and inner Non-cacheable | S bit | + +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+ + | 001 | 0 | 1 | Reserved | Reserved | Reserved | + +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+ + | 001 | 1 | 0 | IMPLEMENTATION DEFINED | IMPLEMENTATION DEFINED | IMPLEMENTATION DEFINED | + +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+ + | 001 | 1 | 1 | Normal | Outer and inner write-back; write and read allocate | S bit | + +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+ + | 010 | 0 | 0 | Device | Non-shared device | Not shareable | + +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+ + | 010 | 0 | 1 | Reserved | Reserved | Reserved | + +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+ + | 010 | 1 | X | Reserved | Reserved | Reserved | + +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+ + | 011 | X | X | Reserved | Reserved | Reserved | + +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+ + | 1BB | A | A | Normal | Cached memory, with AA and BB indicating the inner and | Reserved | + | | | | | outer cacheability rules that must be exported on the | | + | | | | | bus. See the table below for the cacheability policy | | + | | | | | encoding. memory, BB=Outer policy, AA=Inner policy. | | + +-----+---+---+------------------------+--------------------------------------------------------+-------------------------+ + + +-----------------------------------------+----------------------------------------+ + | AA or BB subfield of {TEX,C,B} encoding | Cacheability policy | + +-----------------------------------------+----------------------------------------+ + | 00 | Non-cacheable | + +-----------------------------------------+----------------------------------------+ + | 01 | Write-back, write and read allocate | + +-----------------------------------------+----------------------------------------+ + | 10 | Write-through, no write allocate | + +-----------------------------------------+----------------------------------------+ + | 11 | Write-back, no write allocate | + +-----------------------------------------+----------------------------------------+ + */ + + /* TEX, Shareable (S), Cacheable (C) and Bufferable (B) bits for Flash + * region. */ + #ifndef configTEX_S_C_B_FLASH + /* Default to TEX=000, S=1, C=1, B=1 for backward compatibility. */ + #define configTEX_S_C_B_FLASH ( 0x07UL ) + #endif + + /* TEX, Shareable (S), Cacheable (C) and Bufferable (B) bits for SRAM + * region. */ + #ifndef configTEX_S_C_B_SRAM + /* Default to TEX=000, S=1, C=1, B=1 for backward compatibility. */ + #define configTEX_S_C_B_SRAM ( 0x07UL ) + #endif + #define portUNPRIVILEGED_FLASH_REGION ( 0UL ) #define portPRIVILEGED_FLASH_REGION ( 1UL ) #define portPRIVILEGED_RAM_REGION ( 2UL ) diff --git a/portable/ThirdParty/GCC/Xtensa_ESP32/include/portmacro.h b/portable/ThirdParty/GCC/Xtensa_ESP32/include/portmacro.h index cf3973547..cce0bd02c 100644 --- a/portable/ThirdParty/GCC/Xtensa_ESP32/include/portmacro.h +++ b/portable/ThirdParty/GCC/Xtensa_ESP32/include/portmacro.h @@ -305,12 +305,32 @@ uint32_t compare, uint32_t * set ) { - __asm__ __volatile__ ( - "WSR %2,SCOMPARE1 \n" - "S32C1I %0, %1, 0 \n" - : "=r" ( *set ) - : "r" ( addr ), "r" ( compare ), "0" ( *set ) - ); + #if ( XCHAL_HAVE_S32C1I > 0 ) + __asm__ __volatile__ ( + "WSR %2,SCOMPARE1 \n" + "S32C1I %0, %1, 0 \n" + : "=r" ( *set ) + : "r" ( addr ), "r" ( compare ), "0" ( *set ) + ); + #else + /* No S32C1I, so do this by disabling and re-enabling interrupts (slower) */ + uint32_t intlevel, old_value; + __asm__ __volatile__ ( "rsil %0, " XTSTR( XCHAL_EXCM_LEVEL ) "\n" + : "=r" ( intlevel ) ); + + old_value = *addr; + + if( old_value == compare ) + { + *addr = *set; + } + + __asm__ __volatile__ ( "memw \n" + "wsr %0, ps\n" + : : "r" ( intlevel ) ); + + *set = old_value; + #endif /* if ( XCHAL_HAVE_S32C1I > 0 ) */ } void uxPortCompareSetExtram( volatile uint32_t * addr, @@ -407,13 +427,6 @@ #define xPortGetFreeHeapSize esp_get_free_heap_size #define xPortGetMinimumEverFreeHeapSize esp_get_minimum_free_heap_size -/* - * Send an interrupt to another core in order to make the task running - * on it yield for a higher-priority task. - */ - - void vPortYieldOtherCore( BaseType_t coreid ) PRIVILEGED_FUNCTION; - /* * Callback to set a watchpoint on the end of the stack. Called every context switch to change the stack diff --git a/portable/ThirdParty/GCC/Xtensa_ESP32/port.c b/portable/ThirdParty/GCC/Xtensa_ESP32/port.c index 932496938..414dbfdc0 100644 --- a/portable/ThirdParty/GCC/Xtensa_ESP32/port.c +++ b/portable/ThirdParty/GCC/Xtensa_ESP32/port.c @@ -96,17 +96,23 @@ #include "xtensa_rtos.h" -#include "rom/ets_sys.h" +#if CONFIG_IDF_TARGET_ESP32S2 + #include "esp32s2/rom/ets_sys.h" +#elif CONFIG_IDF_TARGET_ESP32 + #include "esp32/rom/ets_sys.h" +#endif #include "soc/cpu.h" #include "FreeRTOS.h" #include "task.h" -#include "esp_panic.h" +#include "esp_private/panic_reason.h" +#include "esp_debug_helpers.h" #include "esp_heap_caps.h" -#include "esp_crosscore_int.h" +#include "esp_private/crosscore_int.h" #include "esp_intr_alloc.h" +#include "esp_log.h" /* Defined in portasm.h */ extern void _frxt_tick_timer_init( void ); @@ -132,6 +138,19 @@ unsigned port_interruptNesting[ portNUM_PROCESSORS ] = { 0 }; /* Interrupt nest /* User exception dispatcher when exiting */ void _xt_user_exit( void ); +#if CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER +/* Wrapper to allow task functions to return (increases stack overhead by 16 bytes) */ + static void vPortTaskWrapper( TaskFunction_t pxCode, + void * pvParameters ) + { + pxCode( pvParameters ); + /*FreeRTOS tasks should not return. Log the task name and abort. */ + char * pcTaskName = pcTaskGetTaskName( NULL ); + ESP_LOGE( "FreeRTOS", "FreeRTOS Task \"%s\" should not return, Aborting now!", pcTaskName ); + abort(); + } +#endif /* if CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER */ + /* * Stack initialization */ @@ -165,21 +184,35 @@ void _xt_user_exit( void ); frame = ( XtExcFrame * ) sp; /* Explicitly initialize certain saved registers */ - frame->pc = ( UBaseType_t ) pxCode; /* task entrypoint */ - frame->a0 = 0; /* to terminate GDB backtrace */ - frame->a1 = ( UBaseType_t ) sp + XT_STK_FRMSZ; /* physical top of stack frame */ - frame->exit = ( UBaseType_t ) _xt_user_exit; /* user exception exit dispatcher */ + #if CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER + frame->pc = ( UBaseType_t ) vPortTaskWrapper; /* task wrapper */ + #else + frame->pc = ( UBaseType_t ) pxCode; /* task entrypoint */ + #endif + frame->a0 = 0; /* to terminate GDB backtrace */ + frame->a1 = ( UBaseType_t ) sp + XT_STK_FRMSZ; /* physical top of stack frame */ + frame->exit = ( UBaseType_t ) _xt_user_exit; /* user exception exit dispatcher */ /* Set initial PS to int level 0, EXCM disabled ('rfe' will enable), user mode. */ /* Also set entry point argument parameter. */ #ifdef __XTENSA_CALL0_ABI__ - frame->a2 = ( UBaseType_t ) pvParameters; + #if CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER + frame->a2 = ( UBaseType_t ) pxCode; + frame->a3 = ( UBaseType_t ) pvParameters; + #else + frame->a2 = ( UBaseType_t ) pvParameters; + #endif frame->ps = PS_UM | PS_EXCM; #else /* + for windowed ABI also set WOE and CALLINC (pretend task was 'call4'd). */ - frame->a6 = ( UBaseType_t ) pvParameters; + #if CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER + frame->a6 = ( UBaseType_t ) pxCode; + frame->a7 = ( UBaseType_t ) pvParameters; + #else + frame->a6 = ( UBaseType_t ) pvParameters; + #endif frame->ps = PS_UM | PS_EXCM | PS_WOE | PS_CALLINC( 1 ); - #endif + #endif /* ifdef __XTENSA_CALL0_ABI__ */ #ifdef XT_USE_SWPRI /* Set the initial virtual priority mask value to all 1's. */ diff --git a/portable/ThirdParty/GCC/Xtensa_ESP32/portasm.S b/portable/ThirdParty/GCC/Xtensa_ESP32/portasm.S index b43e9be84..7884cf459 100644 --- a/portable/ThirdParty/GCC/Xtensa_ESP32/portasm.S +++ b/portable/ThirdParty/GCC/Xtensa_ESP32/portasm.S @@ -138,8 +138,24 @@ _frxt_int_enter: mull a2, a4, a2 add a1, a1, a2 /* for current proc */ + #ifdef CONFIG_FREERTOS_FPU_IN_ISR + #if XCHAL_CP_NUM > 0 + rsr a3, CPENABLE /* Restore thread scope CPENABLE */ + addi sp, sp,-4 /* ISR will manage FPU coprocessor by forcing */ + s32i a3, a1, 0 /* its trigger */ + #endif + #endif + .Lnested: 1: + #ifdef CONFIG_FREERTOS_FPU_IN_ISR + #if XCHAL_CP_NUM > 0 + movi a3, 0 /* whilst ISRs pending keep CPENABLE exception active */ + wsr a3, CPENABLE + rsync + #endif + #endif + mov a0, a12 /* restore return addr and return */ ret @@ -176,6 +192,15 @@ _frxt_int_exit: s32i a2, a3, 0 /* save nesting count */ bnez a2, .Lnesting /* !=0 after decr so still nested */ + #ifdef CONFIG_FREERTOS_FPU_IN_ISR + #if XCHAL_CP_NUM > 0 + l32i a3, sp, 0 /* Grab last CPENABLE before leave ISR */ + addi sp, sp, 4 + wsr a3, CPENABLE + rsync /* ensure CPENABLE was modified */ + #endif + #endif + movi a2, pxCurrentTCB addx4 a2, a4, a2 l32i a2, a2, 0 /* a2 = current TCB */ @@ -642,7 +667,6 @@ _frxt_task_coproc_state: addx4 a15, a3, a15 l32i a15, a15, 0 /* && pxCurrentTCB != 0) { */ - beqz a15, 2f l32i a15, a15, CP_TOPOFSTACK_OFFS ret diff --git a/portable/ThirdParty/GCC/Xtensa_ESP32/xtensa_init.c b/portable/ThirdParty/GCC/Xtensa_ESP32/xtensa_init.c index 6aaea0b09..2bf1da7ef 100644 --- a/portable/ThirdParty/GCC/Xtensa_ESP32/xtensa_init.c +++ b/portable/ThirdParty/GCC/Xtensa_ESP32/xtensa_init.c @@ -34,7 +34,11 @@ #endif #include "xtensa_rtos.h" -#include "esp_clk.h" +#if CONFIG_IDF_TARGET_ESP32S2 +#include "esp32s2/clk.h" +#elif CONFIG_IDF_TARGET_ESP32 +#include "esp32/clk.h" +#endif #ifdef XT_RTOS_TIMER_INT diff --git a/portable/ThirdParty/GCC/Xtensa_ESP32/xtensa_intr.c b/portable/ThirdParty/GCC/Xtensa_ESP32/xtensa_intr.c index 6d05ae5f9..93e416068 100644 --- a/portable/ThirdParty/GCC/Xtensa_ESP32/xtensa_intr.c +++ b/portable/ThirdParty/GCC/Xtensa_ESP32/xtensa_intr.c @@ -34,7 +34,11 @@ #include "freertos/xtensa_api.h" #include "freertos/portable.h" -#include "rom/ets_sys.h" +#if CONFIG_IDF_TARGET_ESP32S2 +#include "esp32s2/rom/ets_sys.h" +#elif CONFIG_IDF_TARGET_ESP32 +#include "esp32/rom/ets_sys.h" +#endif #if XCHAL_HAVE_EXCEPTIONS diff --git a/portable/ThirdParty/GCC/Xtensa_ESP32/xtensa_vector_defaults.S b/portable/ThirdParty/GCC/Xtensa_ESP32/xtensa_vector_defaults.S index f6c34a313..6ce34dd07 100644 --- a/portable/ThirdParty/GCC/Xtensa_ESP32/xtensa_vector_defaults.S +++ b/portable/ThirdParty/GCC/Xtensa_ESP32/xtensa_vector_defaults.S @@ -13,7 +13,7 @@ // limitations under the License. #include "xtensa_rtos.h" -#include "esp_panic.h" +#include "esp_private/panic_reason.h" #include "sdkconfig.h" #include "soc/soc.h" diff --git a/portable/ThirdParty/GCC/Xtensa_ESP32/xtensa_vectors.S b/portable/ThirdParty/GCC/Xtensa_ESP32/xtensa_vectors.S index 5c8601d1c..eb0729f06 100644 --- a/portable/ThirdParty/GCC/Xtensa_ESP32/xtensa_vectors.S +++ b/portable/ThirdParty/GCC/Xtensa_ESP32/xtensa_vectors.S @@ -91,10 +91,9 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *******************************************************************************/ #include "xtensa_rtos.h" -#include "esp_panic.h" +#include "esp_private/panic_reason.h" #include "sdkconfig.h" #include "soc/soc.h" -#include "soc/dport_reg.h" /* Define for workaround: pin no-cpu-affinity tasks to a cpu when fpu is used. @@ -103,7 +102,25 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define TASKTCB_XCOREID_OFFSET (0x38+configMAX_TASK_NAME_LEN+3)&~3 .extern pxCurrentTCB -/* Enable stack backtrace across exception/interrupt - see below */ +/* +-------------------------------------------------------------------------------- + In order for backtracing to be able to trace from the pre-exception stack + across to the exception stack (including nested interrupts), we need to create + a pseudo base-save area to make it appear like the exception dispatcher was + triggered by a CALL4 from the pre-exception code. In reality, the exception + dispatcher uses the same window as pre-exception code, and only CALL0s are + used within the exception dispatcher. + + To create the pseudo base-save area, we need to store a copy of the pre-exception's + base save area (a0 to a4) below the exception dispatcher's SP. EXCSAVE_x will + be used to store a copy of the SP that points to the interrupted code's exception + frame just in case the exception dispatcher's SP does not point to the exception + frame (which is the case when switching from task to interrupt stack). + + Clearing the pseudo base-save area is uncessary as the interrupt dispatcher + will restore the current SP to that of the pre-exception SP. +-------------------------------------------------------------------------------- +*/ #ifdef CONFIG_FREERTOS_INTERRUPT_BACKTRACE #define XT_DEBUG_BACKTRACE 1 #endif @@ -202,9 +219,22 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. /* This bit of code provides a nice debug backtrace in the debugger. It does take a few more instructions, so undef XT_DEBUG_BACKTRACE if you want to save the cycles. + At this point, the exception frame should have been allocated and filled, + and current sp points to the interrupt stack (for non-nested interrupt) + or below the allocated exception frame (for nested interrupts). Copy the + pre-exception's base save area below the current SP. */ #ifdef XT_DEBUG_BACKTRACE #ifndef __XTENSA_CALL0_ABI__ + rsr a0, EXCSAVE_1 + \level - 1 /* Get exception frame pointer stored in EXCSAVE_x */ + l32i a3, a0, XT_STK_A0 /* Copy pre-exception a0 (return address) */ + s32e a3, a1, -16 + l32i a3, a0, XT_STK_A1 /* Copy pre-exception a1 (stack pointer) */ + s32e a3, a1, -12 + /* Backtracing only needs a0 and a1, no need to create full base save area. + Also need to change current frame's return address to point to pre-exception's + last run instruction. + */ rsr a0, EPC_1 + \level - 1 /* return address */ movi a4, 0xC0000000 /* constant with top 2 bits set (call size) */ or a0, a0, a4 /* set top 2 bits */ @@ -698,8 +728,16 @@ _xt_user_exc: #endif wsr a0, PS + /* + Create pseudo base save area. At this point, sp is still pointing to the + allocated and filled exception stack frame. + */ #ifdef XT_DEBUG_BACKTRACE #ifndef __XTENSA_CALL0_ABI__ + l32i a3, sp, XT_STK_A0 /* Copy pre-exception a0 (return address) */ + s32e a3, sp, -16 + l32i a3, sp, XT_STK_A1 /* Copy pre-exception a1 (stack pointer) */ + s32e a3, sp, -12 rsr a0, EPC_1 /* return address for debug backtrace */ movi a5, 0xC0000000 /* constant with top 2 bits set (call size) */ rsync /* wait for WSR.PS to complete */ @@ -945,7 +983,12 @@ _xt_coproc_exc: /* Get co-processor state save area of new owner thread. */ call0 XT_RTOS_CP_STATE /* a15 = new owner's save area */ - beqz a15, .L_goto_invalid /* not in a thread (invalid) */ + + #ifndef CONFIG_FREERTOS_FPU_IN_ISR + beqz a15, .L_goto_invalid + #endif + + /*When FPU in ISR is enabled we could deal with zeroed a15 */ /* Enable the co-processor's bit in CPENABLE. */ movi a0, _xt_coproc_mask @@ -987,7 +1030,13 @@ locking. rsync /* ensure wsr.CPENABLE is complete */ /* Only need to context switch if new owner != old owner. */ + /* If float is necessary on ISR, we need to remove this check */ + /* below, because on restoring from ISR we may have new == old condition used + * to force cp restore to next thread + */ + #ifndef CONFIG_FREERTOS_FPU_IN_ISR beq a15, a2, .L_goto_done /* new owner == old, we're done */ + #endif /* If no old owner then nothing to save. */ beqz a2, .L_check_new @@ -1029,6 +1078,7 @@ locking. .L_check_new: /* Check if any state has to be restored for new owner. */ /* NOTE: a15 = new owner's save area, cannot be zero when we get here. */ + beqz a15, .L_xt_coproc_done l16ui a3, a15, XT_CPSTORED /* a3 = new owner's CPSTORED */ movi a4, _xt_coproc_sa_offset @@ -1114,6 +1164,16 @@ _xt_lowint1: movi a0, _xt_user_exit /* save exit point for dispatch */ s32i a0, sp, XT_STK_EXIT + /* EXCSAVE_1 should now be free to use. Use it to keep a copy of the + current stack pointer that points to the exception frame (XT_STK_FRAME).*/ + #ifdef XT_DEBUG_BACKTRACE + #ifndef __XTENSA_CALL0_ABI__ + mov a0, sp + wsr a0, EXCSAVE_1 + #endif + #endif + + /* Save rest of interrupt context and enter RTOS. */ call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */ @@ -1194,6 +1254,16 @@ _xt_medint2: movi a0, _xt_medint2_exit /* save exit point for dispatch */ s32i a0, sp, XT_STK_EXIT + /* EXCSAVE_2 should now be free to use. Use it to keep a copy of the + current stack pointer that points to the exception frame (XT_STK_FRAME).*/ + #ifdef XT_DEBUG_BACKTRACE + #ifndef __XTENSA_CALL0_ABI__ + mov a0, sp + wsr a0, EXCSAVE_2 + #endif + #endif + + /* Save rest of interrupt context and enter RTOS. */ call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */ @@ -1265,6 +1335,16 @@ _xt_medint3: movi a0, _xt_medint3_exit /* save exit point for dispatch */ s32i a0, sp, XT_STK_EXIT + /* EXCSAVE_3 should now be free to use. Use it to keep a copy of the + current stack pointer that points to the exception frame (XT_STK_FRAME).*/ + #ifdef XT_DEBUG_BACKTRACE + #ifndef __XTENSA_CALL0_ABI__ + mov a0, sp + wsr a0, EXCSAVE_3 + #endif + #endif + + /* Save rest of interrupt context and enter RTOS. */ call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */ @@ -1335,6 +1415,16 @@ _xt_medint4: movi a0, _xt_medint4_exit /* save exit point for dispatch */ s32i a0, sp, XT_STK_EXIT + /* EXCSAVE_4 should now be free to use. Use it to keep a copy of the + current stack pointer that points to the exception frame (XT_STK_FRAME).*/ + #ifdef XT_DEBUG_BACKTRACE + #ifndef __XTENSA_CALL0_ABI__ + mov a0, sp + wsr a0, EXCSAVE_4 + #endif + #endif + + /* Save rest of interrupt context and enter RTOS. */ call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */ @@ -1405,6 +1495,15 @@ _xt_medint5: movi a0, _xt_medint5_exit /* save exit point for dispatch */ s32i a0, sp, XT_STK_EXIT + /* EXCSAVE_5 should now be free to use. Use it to keep a copy of the + current stack pointer that points to the exception frame (XT_STK_FRAME).*/ + #ifdef XT_DEBUG_BACKTRACE + #ifndef __XTENSA_CALL0_ABI__ + mov a0, sp + wsr a0, EXCSAVE_5 + #endif + #endif + /* Save rest of interrupt context and enter RTOS. */ call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */ @@ -1475,6 +1574,15 @@ _xt_medint6: movi a0, _xt_medint6_exit /* save exit point for dispatch */ s32i a0, sp, XT_STK_EXIT + /* EXCSAVE_6 should now be free to use. Use it to keep a copy of the + current stack pointer that points to the exception frame (XT_STK_FRAME).*/ + #ifdef XT_DEBUG_BACKTRACE + #ifndef __XTENSA_CALL0_ABI__ + mov a0, sp + wsr a0, EXCSAVE_6 + #endif + #endif + /* Save rest of interrupt context and enter RTOS. */ call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */ diff --git a/stream_buffer.c b/stream_buffer.c index bef8214e2..cb76d9543 100644 --- a/stream_buffer.c +++ b/stream_buffer.c @@ -518,7 +518,11 @@ size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer, size_t xReturn, xSpace = 0; size_t xRequiredSpace = xDataLengthBytes; TimeOut_t xTimeOut; - + + /* Having a 'isFeasible' variable allows to respect the convention that there is only a return statement at the end. Othewise, return + * could be done as soon as we realise the send cannot happen. We will let the call to 'prvWriteMessageToBuffer' dealing with this scenario. */ + BaseType_t xIsFeasible; + configASSERT( pvTxData ); configASSERT( pxStreamBuffer ); @@ -532,13 +536,56 @@ size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer, /* Overflow? */ configASSERT( xRequiredSpace > xDataLengthBytes ); + + /* In the case of the message buffer, one has to be able to write the complete message as opposed to + * a stream buffer for semantic reasons. Check if it is physically possible to write the message given + * the length of the buffer. */ + if(xRequiredSpace > pxStreamBuffer->xLength) + { + /* The message could never be written because it is greater than the buffer length. + * By setting xIsFeasable to FALSE, we skip over the following do..while loop, thus avoiding + * a deadlock. The call to 'prvWriteMessageToBuffer' toward the end of this function with + * xRequiredSpace greater than xSpace will suffice in not writing anything to the internal buffer. + * Now, the function will return 0 because the message could not be written. Should an error code be + * returned instead ??? In my opinion, probably.. But the return type doesn't allow for negative + * values to be returned. A confusion could exist to the caller. Returning 0 because a timeout occurred + * and a subsequent send attempts could eventually succeed, and returning 0 because a write could never + * happen because of the size are two scenarios to me :/ */ + xIsFeasible = pdFALSE; + } + else + { + /* It is possible to write the message completely in the buffer. This is the intended route. + * Let's continue with the regular timeout logic. */ + xIsFeasible = pdTRUE; + } } else { - mtCOVERAGE_TEST_MARKER(); + /* In the case of the stream buffer, not being able to completely write the message in the buffer + * is an acceptable scenario, but it has to be dealt with properly */ + if(xRequiredSpace > pxStreamBuffer->xLength) + { + /* Not enough buffer space. We will attempt to write as much as we can in this run + * so that the caller can send the remaining in subsequent calls. We avoid a deadlock by + * offering the possibility to take the 'else' branch in the 'if( xSpace < xRequiredSpace )' + * condition inside the following do..while loop */ + xRequiredSpace = pxStreamBuffer->xLength; + + /* TODO FIXME: Is there a check we should do with the xTriggerLevelBytes value ? */ + + /* With the adjustment to 'xRequiredSpace', the deadlock is avoided, thus it's now feasible. */ + xIsFeasible = pdTRUE; + } + else + { + /* It is possible to write the message completely in the buffer. */ + xIsFeasible = pdTRUE; + } } - if( xTicksToWait != ( TickType_t ) 0 ) + /* Added check against xIsFeasible. If it's not feasible, don't even wait for notification, let the call to 'prvWriteMessageToBuffer' do nothing and return 0 */ + if( xTicksToWait != ( TickType_t ) 0 && xIsFeasible == pdTRUE ) { vTaskSetTimeOutState( &xTimeOut ); diff --git a/tasks.c b/tasks.c index 347fb78b8..f69fd6b57 100644 --- a/tasks.c +++ b/tasks.c @@ -144,7 +144,7 @@ } \ \ /* listGET_OWNER_OF_NEXT_ENTRY indexes through the list, so the tasks of \ - * the same priority get an equal share of the processor time. */ \ + * the same priority get an equal share of the processor time. */ \ listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) ); \ uxTopReadyPriority = uxTopPriority; \ } /* taskSELECT_HIGHEST_PRIORITY_TASK */ @@ -954,7 +954,7 @@ static void prvInitialiseNewTask( TaskFunction_t pxTaskCode, vListInitialiseItem( &( pxNewTCB->xEventListItem ) ); /* Set the pxNewTCB as a link back from the ListItem_t. This is so we can get - * back to the containing TCB from a generic item in a list. */ + * back to the containing TCB from a generic item in a list. */ listSET_LIST_ITEM_OWNER( &( pxNewTCB->xStateListItem ), pxNewTCB ); /* Event lists are always in priority order. */ @@ -1287,7 +1287,7 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) { /* The tick count has overflowed since this function was * lasted called. In this case the only time we should ever - * actually delay is if the wake time has also overflowed, + * actually delay is if the wake time has also overflowed, * and the wake time is greater than the tick time. When this * is the case it is as if neither time had overflowed. */ if( ( xTimeToWake < *pxPreviousWakeTime ) && ( xTimeToWake > xConstTickCount ) ) @@ -1519,8 +1519,8 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) UBaseType_t uxReturn, uxSavedInterruptState; /* RTOS ports that support interrupt nesting have the concept of a - * maximum system call (or maximum API call) interrupt priority. - * Interrupts that are above the maximum system call priority are keep + * maximum system call (or maximum API call) interrupt priority. + * Interrupts that are above the maximum system call priority are keep * permanently enabled, even when the RTOS kernel is in a critical section, * but cannot make any calls to FreeRTOS API functions. If configASSERT() * is defined in FreeRTOSConfig.h then @@ -1528,7 +1528,7 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) * failure if a FreeRTOS API function is called from an interrupt that has * been assigned a priority above the configured maximum system call * priority. Only FreeRTOS functions that end in FromISR can be called - * from interrupts that have been assigned a priority at or (logically) + * from interrupts that have been assigned a priority at or (logically) * below the maximum system call interrupt priority. FreeRTOS maintains a * separate interrupt safe API to ensure interrupt entry is as fast and as * simple as possible. More information (albeit Cortex-M specific) is @@ -1842,7 +1842,7 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) /* Has the task already been resumed from within an ISR? */ if( listIS_CONTAINED_WITHIN( &xPendingReadyList, &( pxTCB->xEventListItem ) ) == pdFALSE ) { - /* Is it in the suspended list because it is in the Suspended + /* Is it in the suspended list because it is in the Suspended * state, or because is is blocked with no timeout? */ if( listIS_CONTAINED_WITHIN( NULL, &( pxTCB->xEventListItem ) ) != pdFALSE ) /*lint !e961. The cast is only redundant when NULL is used. */ { @@ -1934,8 +1934,8 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) configASSERT( xTaskToResume ); /* RTOS ports that support interrupt nesting have the concept of a - * maximum system call (or maximum API call) interrupt priority. - * Interrupts that are above the maximum system call priority are keep + * maximum system call (or maximum API call) interrupt priority. + * Interrupts that are above the maximum system call priority are keep * permanently enabled, even when the RTOS kernel is in a critical section, * but cannot make any calls to FreeRTOS API functions. If configASSERT() * is defined in FreeRTOSConfig.h then @@ -1943,7 +1943,7 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) * failure if a FreeRTOS API function is called from an interrupt that has * been assigned a priority above the configured maximum system call * priority. Only FreeRTOS functions that end in FromISR can be called - * from interrupts that have been assigned a priority at or (logically) + * from interrupts that have been assigned a priority at or (logically) * below the maximum system call interrupt priority. FreeRTOS maintains a * separate interrupt safe API to ensure interrupt entry is as fast and as * simple as possible. More information (albeit Cortex-M specific) is @@ -2123,7 +2123,7 @@ void vTaskEndScheduler( void ) { /* Stop the scheduler interrupts and call the portable scheduler end * routine so the original ISRs can be restored if necessary. The port - * layer must ensure interrupts enable bit is left in the correct state. */ + * layer must ensure interrupts enable bit is left in the correct state. */ portDISABLE_INTERRUPTS(); xSchedulerRunning = pdFALSE; vPortEndScheduler(); @@ -2270,7 +2270,7 @@ BaseType_t xTaskResumeAll( void ) /* If any ticks occurred while the scheduler was suspended then * they should be processed now. This ensures the tick count does - * not slip, and that any delayed tasks are resumed at the correct + * not slip, and that any delayed tasks are resumed at the correct * time. */ { TickType_t xPendedCounts = xPendedTicks; /* Non-volatile copy. */ @@ -2355,7 +2355,7 @@ TickType_t xTaskGetTickCountFromISR( void ) * assigned a priority above the configured maximum system call priority. * Only FreeRTOS functions that end in FromISR can be called from interrupts * that have been assigned a priority at or (logically) below the maximum - * system call interrupt priority. FreeRTOS maintains a separate interrupt + * system call interrupt priority. FreeRTOS maintains a separate interrupt * safe API to ensure interrupt entry is as fast and as simple as possible. * More information (albeit Cortex-M specific) is provided on the following * link: https://www.freertos.org/RTOS-Cortex-M3-M4.html */ @@ -2760,7 +2760,7 @@ BaseType_t xTaskIncrementTick( void ) } /* See if this tick has made a timeout expire. Tasks are stored in - * the queue in the order of their wake time - meaning once one task + * the queue in the order of their wake time - meaning once one task * has been found whose block time has not expired there is no need to * look any further down the list. */ if( xConstTickCount >= xNextTaskUnblockTime ) @@ -2791,7 +2791,7 @@ BaseType_t xTaskIncrementTick( void ) /* It is not time to unblock this item yet, but the * item value is the time at which the task at the head * of the blocked list must be removed from the Blocked - * state - so record the item value in + * state - so record the item value in * xNextTaskUnblockTime. */ xNextTaskUnblockTime = xItemValue; break; /*lint !e9011 Code structure here is deedmed easier to understand with multiple breaks. */ @@ -3309,7 +3309,7 @@ void vTaskInternalSetTimeOutState( TimeOut_t * const pxTimeOut ) BaseType_t xTaskCheckForTimeOut( TimeOut_t * const pxTimeOut, TickType_t * const pxTicksToWait ) { - BaseType_t xReturn; +BaseType_t xReturn; configASSERT( pxTimeOut ); configASSERT( pxTicksToWait ); @@ -3320,7 +3320,7 @@ BaseType_t xTaskCheckForTimeOut( TimeOut_t * const pxTimeOut, const TickType_t xConstTickCount = xTickCount; const TickType_t xElapsedTime = xConstTickCount - pxTimeOut->xTimeOnEntering; - #if ( INCLUDE_xTaskAbortDelay == 1 ) + #if( INCLUDE_xTaskAbortDelay == 1 ) if( pxCurrentTCB->ucDelayAborted != ( uint8_t ) pdFALSE ) { /* The delay was aborted, which is not the same as a time out, @@ -3350,6 +3350,7 @@ BaseType_t xTaskCheckForTimeOut( TimeOut_t * const pxTimeOut, * around and gone past again. This passed since vTaskSetTimeout() * was called. */ xReturn = pdTRUE; + *pxTicksToWait = ( TickType_t ) 0; } else if( xElapsedTime < *pxTicksToWait ) /*lint !e961 Explicit casting is only redundant with some compilers, whereas others require it to prevent integer conversion errors. */ { @@ -3360,7 +3361,7 @@ BaseType_t xTaskCheckForTimeOut( TimeOut_t * const pxTimeOut, } else { - *pxTicksToWait = 0; + *pxTicksToWait = ( TickType_t ) 0; xReturn = pdTRUE; } } @@ -3492,7 +3493,7 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters ) /* This conditional compilation should use inequality to 0, not equality * to 1. This is to ensure portSUPPRESS_TICKS_AND_SLEEP() is called when - * user defined low power mode implementations require + * user defined low power mode implementations require * configUSE_TICKLESS_IDLE to be set to a value other than 1. */ #if ( configUSE_TICKLESS_IDLE != 0 ) { @@ -3996,7 +3997,7 @@ static void prvResetNextTaskUnblockTime( void ) if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE ) { /* The new current delayed list is empty. Set xNextTaskUnblockTime to - * the maximum possible value so it is extremely unlikely that the + * the maximum possible value so it is extremely unlikely that the * if( xTickCount >= xNextTaskUnblockTime ) test will pass until * there is an item in the delayed list. */ xNextTaskUnblockTime = portMAX_DELAY; @@ -4186,7 +4187,7 @@ static void prvResetNextTaskUnblockTime( void ) } /* Disinherit the priority before adding the task into the - * new ready list. */ + * new ready list. */ traceTASK_PRIORITY_DISINHERIT( pxTCB, pxTCB->uxBasePriority ); pxTCB->uxPriority = pxTCB->uxBasePriority; @@ -4344,7 +4345,7 @@ static void prvResetNextTaskUnblockTime( void ) ( pxCurrentTCB->uxCriticalNesting )++; /* This is not the interrupt safe version of the enter critical - * function so assert() if it is being called from an interrupt + * function so assert() if it is being called from an interrupt * context. Only API functions that end in "FromISR" can be used in an * interrupt. Only assert if the critical nesting count is 1 to * protect against recursive calls if the assert function also uses a @@ -4775,7 +4776,7 @@ TickType_t uxTaskResetEventItemValue( void ) if( pxCurrentTCB->ucNotifyState[ uxIndexToWait ] != taskNOTIFICATION_RECEIVED ) { /* Clear bits in the task's notification value as bits may get - * set by the notifying task or interrupt. This can be used to + * set by the notifying task or interrupt. This can be used to * clear the value to zero. */ pxCurrentTCB->ulNotifiedValue[ uxIndexToWait ] &= ~ulBitsToClearOnEntry; @@ -4984,8 +4985,8 @@ TickType_t uxTaskResetEventItemValue( void ) configASSERT( uxIndexToNotify < configTASK_NOTIFICATION_ARRAY_ENTRIES ); /* RTOS ports that support interrupt nesting have the concept of a - * maximum system call (or maximum API call) interrupt priority. - * Interrupts that are above the maximum system call priority are keep + * maximum system call (or maximum API call) interrupt priority. + * Interrupts that are above the maximum system call priority are keep * permanently enabled, even when the RTOS kernel is in a critical section, * but cannot make any calls to FreeRTOS API functions. If configASSERT() * is defined in FreeRTOSConfig.h then @@ -4993,7 +4994,7 @@ TickType_t uxTaskResetEventItemValue( void ) * failure if a FreeRTOS API function is called from an interrupt that has * been assigned a priority above the configured maximum system call * priority. Only FreeRTOS functions that end in FromISR can be called - * from interrupts that have been assigned a priority at or (logically) + * from interrupts that have been assigned a priority at or (logically) * below the maximum system call interrupt priority. FreeRTOS maintains a * separate interrupt safe API to ensure interrupt entry is as fast and as * simple as possible. More information (albeit Cortex-M specific) is @@ -5119,8 +5120,8 @@ TickType_t uxTaskResetEventItemValue( void ) configASSERT( uxIndexToNotify < configTASK_NOTIFICATION_ARRAY_ENTRIES ); /* RTOS ports that support interrupt nesting have the concept of a - * maximum system call (or maximum API call) interrupt priority. - * Interrupts that are above the maximum system call priority are keep + * maximum system call (or maximum API call) interrupt priority. + * Interrupts that are above the maximum system call priority are keep * permanently enabled, even when the RTOS kernel is in a critical section, * but cannot make any calls to FreeRTOS API functions. If configASSERT() * is defined in FreeRTOSConfig.h then @@ -5128,7 +5129,7 @@ TickType_t uxTaskResetEventItemValue( void ) * failure if a FreeRTOS API function is called from an interrupt that has * been assigned a priority above the configured maximum system call * priority. Only FreeRTOS functions that end in FromISR can be called - * from interrupts that have been assigned a priority at or (logically) + * from interrupts that have been assigned a priority at or (logically) * below the maximum system call interrupt priority. FreeRTOS maintains a * separate interrupt safe API to ensure interrupt entry is as fast and as * simple as possible. More information (albeit Cortex-M specific) is @@ -5245,7 +5246,7 @@ TickType_t uxTaskResetEventItemValue( void ) { /* Return the notification as it was before the bits were cleared, * then clear the bit mask. */ - ulReturn = pxCurrentTCB->ulNotifiedValue[ uxIndexToClear ]; + ulReturn = pxTCB->ulNotifiedValue[ uxIndexToClear ]; pxTCB->ulNotifiedValue[ uxIndexToClear ] &= ~ulBitsToClear; } taskEXIT_CRITICAL();