From 676d99e302e75342a0645232eef16ed536c98434 Mon Sep 17 00:00:00 2001 From: Gaurav-Aggarwal-AWS <33462878+aggarg@users.noreply.github.com> Date: Fri, 24 Jul 2020 09:45:42 -0700 Subject: [PATCH 01/10] Use configSYSTICK_CLOCK_HZ to configure SysTick (#103) configSYSTICK_CLOCK_HZ should be used to configure SysTick to support the use case when the clock for SysTick timer is scaled from the main CPU clock. configSYSTICK_CLOCK_HZ is defined to configCPU_CLOCK_HZ when it is not defined in FreeRTOSConfig.h. Signed-off-by: Gaurav Aggarwal --- portable/ARMv8M/non_secure/port.c | 2 +- portable/GCC/ARM_CM23/non_secure/port.c | 2 +- portable/GCC/ARM_CM23_NTZ/non_secure/port.c | 2 +- portable/GCC/ARM_CM33/non_secure/port.c | 2 +- portable/GCC/ARM_CM33_NTZ/non_secure/port.c | 2 +- portable/IAR/ARM_CM23/non_secure/port.c | 2 +- portable/IAR/ARM_CM23_NTZ/non_secure/port.c | 2 +- portable/IAR/ARM_CM33/non_secure/port.c | 2 +- portable/IAR/ARM_CM33_NTZ/non_secure/port.c | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) 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/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/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; } /*-----------------------------------------------------------*/ From 4383c8fae30c8a44c9fe07b7cef3b86f0c5cd72b Mon Sep 17 00:00:00 2001 From: Gaurav-Aggarwal-AWS <33462878+aggarg@users.noreply.github.com> Date: Thu, 30 Jul 2020 19:32:31 -0700 Subject: [PATCH 02/10] Change the xRunningPrivileged check from "!=true" to "==false" (#109) The expected behaviour of portIS_PRIVILEGED is: - return 0 if the processor is not running privileged. - return 1 if the processor is running privileged. Some TI ports do not return 1 when the processor is running privileged causing the following check to fail: if( xRunningPrivileged != pdTRUE ) This commit change the check to: if( xRunningPrivileged == pdFALSE ). It ensures that the check is successful even on the ports which return incorrect value from portIS_PRIVILEGED when the processor is running privileged. See https://forums.freertos.org/t/kernel-bug-nested-mpu-wrapper-calls-generate-an-exception/10391 Signed-off-by: Gaurav Aggarwal --- portable/Common/mpu_wrappers.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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(); } From adbfca54200d9665eb6b94da302b5268616072c0 Mon Sep 17 00:00:00 2001 From: Shubham Kulkarni <57181281+shubhamkulkarni97@users.noreply.github.com> Date: Fri, 31 Jul 2020 09:28:51 +0530 Subject: [PATCH 03/10] Update ESP32 port files (#92) Add changes required to support ESP32-S2 --- .../GCC/Xtensa_ESP32/include/portmacro.h | 39 ++++-- portable/ThirdParty/GCC/Xtensa_ESP32/port.c | 53 ++++++-- .../ThirdParty/GCC/Xtensa_ESP32/portasm.S | 26 +++- .../ThirdParty/GCC/Xtensa_ESP32/xtensa_init.c | 6 +- .../ThirdParty/GCC/Xtensa_ESP32/xtensa_intr.c | 6 +- .../GCC/Xtensa_ESP32/xtensa_vector_defaults.S | 2 +- .../GCC/Xtensa_ESP32/xtensa_vectors.S | 116 +++++++++++++++++- 7 files changed, 217 insertions(+), 31 deletions(-) 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 */ From bda986927169eabce3455ddd3d0f61382471271f Mon Sep 17 00:00:00 2001 From: DavidJurajdaNXP Date: Fri, 31 Jul 2020 06:00:10 +0200 Subject: [PATCH 04/10] IAR Embedded Workbench modified behaviour of weak declaration "#pragma weak" in release 8.50.5. (#83) This modification result in build error in case of FreeRTOS CM0 port. To fix the issue use __weak in function definition instead. --- portable/IAR/ARM_CM0/port.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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 ) From a2e00f0c6b19326b67d386d9f5d76b2a43f08c75 Mon Sep 17 00:00:00 2001 From: m17336 <45935231+m17336@users.noreply.github.com> Date: Fri, 7 Aug 2020 02:24:05 +0300 Subject: [PATCH 05/10] Update to AVR_Mega0 and AVR_Dx GCC ports + addition of their IAR equivalents (#106) * Removed TICK_stop() macro from portable/GCC/{AVR_AVRDx, AVR_Mega0}/porthardware.h because it is not used anywhere. * Updated indentation in portable/GCC/{AVR_AVRDx, AVR_Mega0}/* files. * Added portable/IAR/{AVR_AVRDx, AVR_Mega0 folders. --- portable/GCC/AVR_AVRDx/port.c | 322 +++++++++++++------------- portable/GCC/AVR_AVRDx/porthardware.h | 178 ++++++-------- portable/GCC/AVR_AVRDx/portmacro.h | 11 +- portable/GCC/AVR_Mega0/port.c | 308 ++++++++++++------------ portable/GCC/AVR_Mega0/porthardware.h | 134 +++++------ portable/GCC/AVR_Mega0/portmacro.h | 13 +- portable/IAR/AVR_AVRDx/port.c | 293 +++++++++++++++++++++++ portable/IAR/AVR_AVRDx/porthardware.h | 94 ++++++++ portable/IAR/AVR_AVRDx/portmacro.h | 105 +++++++++ portable/IAR/AVR_AVRDx/portmacro.s90 | 254 ++++++++++++++++++++ portable/IAR/AVR_Mega0/port.c | 291 +++++++++++++++++++++++ portable/IAR/AVR_Mega0/porthardware.h | 82 +++++++ portable/IAR/AVR_Mega0/portmacro.h | 105 +++++++++ portable/IAR/AVR_Mega0/portmacro.s90 | 248 ++++++++++++++++++++ 14 files changed, 1922 insertions(+), 516 deletions(-) create mode 100644 portable/IAR/AVR_AVRDx/port.c create mode 100644 portable/IAR/AVR_AVRDx/porthardware.h create mode 100644 portable/IAR/AVR_AVRDx/portmacro.h create mode 100644 portable/IAR/AVR_AVRDx/portmacro.s90 create mode 100644 portable/IAR/AVR_Mega0/port.c create mode 100644 portable/IAR/AVR_Mega0/porthardware.h create mode 100644 portable/IAR/AVR_Mega0/portmacro.h create mode 100644 portable/IAR/AVR_Mega0/portmacro.s90 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/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 From 287361091bee44770704ffa2b4ce2b7580ad716b Mon Sep 17 00:00:00 2001 From: Gaurav-Aggarwal-AWS <33462878+aggarg@users.noreply.github.com> Date: Sat, 8 Aug 2020 18:37:14 -0700 Subject: [PATCH 06/10] Allow application to override TEX,S,C and B bits for Flash and RAM (#113) 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 default values for these bits, as configured in our MPU ports, are sometimes not suitable for application. One such example is when the MCU has a cache, the application writer may not want to mark the memory as shareable to avoid disabling the cache. This change allows the application writer to override default vales for TEX, S C and B bits for Flash and RAM in their FreeRTOSConfig.h. The following two new configurations are introduced: - configTEX_S_C_B_FLASH - configTEX_S_C_B_SRAM If undefined, the default values for the above configurations are TEX=000, S=1, C=1, B=1. This ensures backward compatibility. Signed-off-by: Gaurav Aggarwal --- portable/GCC/ARM_CM4_MPU/port.c | 12 ++-- portable/GCC/ARM_CM4_MPU/portmacro.h | 80 +++++++++++++++++++++++++++ portable/IAR/ARM_CM4F_MPU/port.c | 12 ++-- portable/IAR/ARM_CM4F_MPU/portmacro.h | 80 +++++++++++++++++++++++++++ portable/RVDS/ARM_CM4_MPU/port.c | 12 ++-- portable/RVDS/ARM_CM4_MPU/portmacro.h | 80 +++++++++++++++++++++++++++ 6 files changed, 258 insertions(+), 18 deletions(-) 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/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/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 ) From 55da9591c02546e6b189a8dadf3923e7ef80bd1f Mon Sep 17 00:00:00 2001 From: RichardBarry <3073890+RichardBarry@users.noreply.github.com> Date: Sun, 9 Aug 2020 16:18:57 -0700 Subject: [PATCH 07/10] Fix: Two one line fixes, xTaskCheckForTimeOut() and ulTaskGenericNotifyValueClear(). (#82) ulTaskGenericNotifyValueClear() returned the notification value of the currently running task, not the target task. Now it returns the notification value of the target task. Some users expected xTaskCheckForTimeOut() to clear the 'last wake time' value each time a timeout occurred, whereas it only did that in one path. It now clears the last wake time in all paths that return that a timeout occurred. --- tasks.c | 61 +++++++++++++++++++++++++++++---------------------------- 1 file changed, 31 insertions(+), 30 deletions(-) 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(); From 61635d5b8b7ae1e783026f37eb66757509010130 Mon Sep 17 00:00:00 2001 From: Simon Beaudoin Date: Mon, 10 Aug 2020 12:46:39 -0400 Subject: [PATCH 08/10] Fix race condition when tracing is enabled (#95) * Update port.c I discovered a very snicky and tricky race condition scenario when integrating tracealyzer code into our project. A little background on CortexR5 : When the IRQ line (comming from the interrupt controller, to which every peripheral IRQ lines connect) of the processor rises and the IRQ Enable bit in the status register of the CPU permits it, the CPU traps into interrupt mode. Several things happen. First, the CPU finishes the instruction it was performing. Second, it places the content of the CPSR register into the SPSR_irq register. And third, the mode of the CPU is changed to IRQ_Mode and /!\ THE IRQ ENABLE BIT IN CPSR_irq IS AUTOMATICALLY CLEARED /!\. The reason is to ensure that upon landing into IRQ code, we find ourselves automatically in a critical section because we cannot be interrupted again because the bit is cleared. The programmer can, if he wants, re-enable IRQs inside IRQ code itself to allow interrupt nesting. But it has to be wanted and meditated. Now, inside portASM.S, at the end of 'FreeRTOS_IRQ_Handler' assembly function, a call to 'vTaskSwitchContextConst' is made if the variable 'ulPortYieldRequired' was set by someone while executing the interrupt. Before branching to that function, a 'CPSID i' instruction was placed to ensure that interrupts are disabled in case someone re-enabled it. Inside 'vTaskSwitchContext', there is the macro 'traceTASK_SWITCHED_OUT' that gets populated when tracing is enabled. The bug is right there.. If the macro is populated and inside that macro there is a matching call to 'ulPortSetInterruptMask' and 'vPortClearInterruptMask', a race condition can occure is there is a OS Tick timer interrupt waiting at the interrupt controller's door. Upon calling 'vTaskSwitchContext', the interrupts are not masked in the interrupt controller, the only barrier against the CPU servicing that tick interrupt while already performing the function is that the IRQ Enable bit cleared. 'ulPortSetInterruptMask' does what's its supposed to do, but doesn't take into account the IRQ Enable bit in CPSR. Wheter or not the bit was cleared, the function sets it at the end. When calling the matching 'vPortClearInterruptMask', the function clears the interrupt mask in the interrupt controller. Because the IRQ Enable bit (that was cleared) has been set no matter what in 'ulPortSetInterruptMask', the CPU services the OS Tick Interrupt right away. The bug is there : instead of completing the 'vTaskSwitchContext' function, the CPU re-enters the switch context path right after 'traceTASK_SWITCHED_OUT' thus corrupting the CPU state and eventually triggering either an undefined instruction, data or instruction abort. * Update port.c Error on my part, this is the right inline asm code to retreive CPSR register * Update port.c Forgot an * while writing comment.. --- portable/GCC/ARM_CR5/port.c | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) 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; } From 61fc74f0c5c50a7d8ac7fa7f4a2f6deb3a215036 Mon Sep 17 00:00:00 2001 From: Simon Beaudoin Date: Mon, 10 Aug 2020 12:55:04 -0400 Subject: [PATCH 09/10] Update stream_buffer.c (#94) Add necessary checks when sending data to the stream/message buffer in order to avoid a task deadlock when attempting to write a longer stream/message than the underlying buffer can write. --- stream_buffer.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 3 deletions(-) diff --git a/stream_buffer.c b/stream_buffer.c index bef8214e2..449c4febb 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 = FALSE; + } + 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 = TRUE; + } } 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 = TRUE; + } + else + { + /* It is possible to write the message completely in the buffer. */ + xIsFeasible = TRUE; + } } - 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 == TRUE ) { vTaskSetTimeOutState( &xTimeOut ); From 4bde12f223c5eb14e3dc75518b563d94d722fa03 Mon Sep 17 00:00:00 2001 From: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com> Date: Tue, 11 Aug 2020 21:44:57 -0700 Subject: [PATCH 10/10] Use pdTRUE/pdFALSE instead of TRUE/FALSE in xStreamBufferSend(). (#114) --- stream_buffer.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/stream_buffer.c b/stream_buffer.c index 449c4febb..cb76d9543 100644 --- a/stream_buffer.c +++ b/stream_buffer.c @@ -551,13 +551,13 @@ size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer, * 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 = FALSE; + 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 = TRUE; + xIsFeasible = pdTRUE; } } else @@ -575,17 +575,17 @@ size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer, /* 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 = TRUE; + xIsFeasible = pdTRUE; } else { /* It is possible to write the message completely in the buffer. */ - xIsFeasible = TRUE; + xIsFeasible = pdTRUE; } } /* 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 == TRUE ) + if( xTicksToWait != ( TickType_t ) 0 && xIsFeasible == pdTRUE ) { vTaskSetTimeOutState( &xTimeOut );