diff --git a/sdk/nrf5/external/freertos/config/FreeRTOSConfig.h b/sdk/nrf5/external/freertos/config/FreeRTOSConfig.h index 1dfd3e2..c531603 100644 --- a/sdk/nrf5/external/freertos/config/FreeRTOSConfig.h +++ b/sdk/nrf5/external/freertos/config/FreeRTOSConfig.h @@ -96,7 +96,7 @@ #define configUSE_TICKLESS_IDLE 0 #define configUSE_TICKLESS_IDLE_SIMPLE_DEBUG 1 /* See into vPortSuppressTicksAndSleep source code for explanation */ #define configCPU_CLOCK_HZ ( SystemCoreClock ) -#define configTICK_RATE_HZ 1000 +#define configTICK_RATE_HZ 1024 #define configMAX_PRIORITIES ( 3 ) #define configMINIMAL_STACK_SIZE ( 60 ) #define configTOTAL_HEAP_SIZE ( 4096 ) diff --git a/sdk/nrf5/external/freertos/portable/CMSIS/nrf51/port_cmsis_systick.c b/sdk/nrf5/external/freertos/portable/CMSIS/nrf51/port_cmsis_systick.c index 4a5dbe7..a3923fc 100644 --- a/sdk/nrf5/external/freertos/portable/CMSIS/nrf51/port_cmsis_systick.c +++ b/sdk/nrf5/external/freertos/portable/CMSIS/nrf51/port_cmsis_systick.c @@ -92,16 +92,42 @@ #include "nrf_drv_clock.h" +static volatile TickType_t tick_overflow_count = 0; +#define portNRF_RTC_BITWIDTH 24 /*-----------------------------------------------------------*/ void xPortSysTickHandler( void ) { + TickType_t diff; + nrf_rtc_event_clear(portNRF_RTC_REG, NRF_RTC_EVENT_TICK); #if configUSE_TICKLESS_IDLE == 1 nrf_rtc_event_clear(portNRF_RTC_REG, NRF_RTC_EVENT_COMPARE_0); #endif - uint32_t isrstate = portSET_INTERRUPT_MASK_FROM_ISR(); - /* Increment the RTOS tick. */ + + /* The SysTick runs at the lowest interrupt priority, so when this interrupt + executes all interrupts must be unmasked. There is therefore no need to + save and then restore the interrupt mask value as its value is already + known. */ + ( void ) portSET_INTERRUPT_MASK_FROM_ISR(); + + /* check for overflow in TICK counter */ + if(nrf_rtc_event_pending(portNRF_RTC_REG, NRF_RTC_EVENT_OVERFLOW)) + { + nrf_rtc_event_clear(portNRF_RTC_REG, NRF_RTC_EVENT_OVERFLOW); + tick_overflow_count++; + } + + diff = ((tick_overflow_count << portNRF_RTC_BITWIDTH) + nrf_rtc_counter_get(portNRF_RTC_REG)) - xTaskGetTickCount(); + + + if(diff > 1) + { + /* This could happen if this interupt was masked for more than one RTOS tick period */ + vTaskStepTick(diff - 1); + } + + /* Increment the RTOS tick as usual which checks if there is a need for rescheduling */ if ( xTaskIncrementTick() != pdFALSE ) { /* A context switch is required. Context switching is performed in @@ -109,7 +135,8 @@ void xPortSysTickHandler( void ) SCB->ICSR = SCB_ICSR_PENDSVSET_Msk; __SEV(); } - portCLEAR_INTERRUPT_MASK_FROM_ISR( isrstate ); + + portCLEAR_INTERRUPT_MASK_FROM_ISR( 0 ); } /* @@ -126,6 +153,7 @@ void vPortSetupTimerInterrupt( void ) nrf_rtc_int_enable (portNRF_RTC_REG, RTC_INTENSET_TICK_Msk); nrf_rtc_task_trigger (portNRF_RTC_REG, NRF_RTC_TASK_CLEAR); nrf_rtc_task_trigger (portNRF_RTC_REG, NRF_RTC_TASK_START); + nrf_rtc_event_enable(portNRF_RTC_REG, RTC_EVTEN_OVRFLW_Msk); NVIC_SetPriority(portNRF_RTC_IRQn, configKERNEL_INTERRUPT_PRIORITY); NVIC_EnableIRQ(portNRF_RTC_IRQn); @@ -152,8 +180,16 @@ void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime ) { xExpectedIdleTime = portNRF_RTC_MAXTICKS - configEXPECTED_IDLE_TIME_BEFORE_SLEEP; } - /* Block the scheduler now */ - portDISABLE_INTERRUPTS(); + /* Block all the interrupts globally */ +#ifdef SOFTDEVICE_PRESENT + do{ + uint8_t dummy = 0; + uint32_t err_code = sd_nvic_critical_region_enter(&dummy); + APP_ERROR_CHECK(err_code); + }while(0); +#else + __disable_irq(); +#endif /* Configure CTC interrupt */ enterTime = nrf_rtc_counter_get(portNRF_RTC_REG); @@ -182,26 +218,42 @@ void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime ) configPRE_SLEEP_PROCESSING( xModifiableIdleTime ); if ( xModifiableIdleTime > 0 ) { - do{ - __WFE(); - } while (0 == (NVIC->ISPR[0])); +#ifdef SOFTDEVICE_PRESENT + + uint32_t err_code = sd_app_evt_wait(); + APP_ERROR_CHECK(err_code); +#else + /* No SD - we would just block interrupts globally. + * BASEPRI cannot be used for that because it would prevent WFE from wake up. + */ + do{ + __WFE(); + } while (0 == (NVIC->ISPR[0])); +#endif } configPOST_SLEEP_PROCESSING( xExpectedIdleTime ); nrf_rtc_int_disable(portNRF_RTC_REG, NRF_RTC_INT_COMPARE0_MASK); + nrf_rtc_event_clear(portNRF_RTC_REG, NRF_RTC_EVENT_COMPARE_0); /* Correct the system ticks */ { TickType_t diff; - TickType_t hwTicks = nrf_rtc_counter_get(portNRF_RTC_REG); + nrf_rtc_event_clear(portNRF_RTC_REG, NRF_RTC_EVENT_TICK); nrf_rtc_int_enable (portNRF_RTC_REG, NRF_RTC_INT_TICK_MASK); - if(enterTime > hwTicks) + /* check for overflow in TICK counter */ + if(nrf_rtc_event_pending(portNRF_RTC_REG, NRF_RTC_EVENT_OVERFLOW)) { - hwTicks += portNRF_RTC_MAXTICKS + 1U; + nrf_rtc_event_clear(portNRF_RTC_REG, NRF_RTC_EVENT_OVERFLOW); + tick_overflow_count++; } - diff = (hwTicks - enterTime); + diff = ((tick_overflow_count << portNRF_RTC_BITWIDTH) + nrf_rtc_counter_get(portNRF_RTC_REG)) - xTaskGetTickCount(); + + /* It is important that we clear pending here so that our corrections are latest and in sync with tick_interrupt handler */ + NVIC_ClearPendingIRQ(portNRF_RTC_IRQn); + if((configUSE_TICKLESS_IDLE_SIMPLE_DEBUG) && (diff > xExpectedIdleTime)) { diff = xExpectedIdleTime; @@ -213,7 +265,12 @@ void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime ) } } } - portENABLE_INTERRUPTS(); +#ifdef SOFTDEVICE_PRESENT + uint32_t err_code = sd_nvic_critical_region_exit(0); + APP_ERROR_CHECK(err_code); +#else + __enable_irq(); +#endif } #endif // configUSE_TICKLESS_IDLE diff --git a/sdk/nrf5/external/freertos/portable/CMSIS/nrf52/port_cmsis_systick.c b/sdk/nrf5/external/freertos/portable/CMSIS/nrf52/port_cmsis_systick.c index a7bef47..521b4e4 100644 --- a/sdk/nrf5/external/freertos/portable/CMSIS/nrf52/port_cmsis_systick.c +++ b/sdk/nrf5/external/freertos/portable/CMSIS/nrf52/port_cmsis_systick.c @@ -71,6 +71,7 @@ #include "FreeRTOS.h" #include "task.h" #include "app_util.h" +#include "nrf_log.h" #ifdef SOFTDEVICE_PRESENT #include "nrf_soc.h" @@ -151,21 +152,42 @@ void vPortSetupTimerInterrupt( void ) #include "nrf_drv_clock.h" +static volatile TickType_t tick_overflow_count = 0; +#define portNRF_RTC_BITWIDTH 24 /*-----------------------------------------------------------*/ void xPortSysTickHandler( void ) { + TickType_t diff; + nrf_rtc_event_clear(portNRF_RTC_REG, NRF_RTC_EVENT_TICK); #if configUSE_TICKLESS_IDLE == 1 nrf_rtc_event_clear(portNRF_RTC_REG, NRF_RTC_EVENT_COMPARE_0); #endif - /* The SysTick runs at the lowest interrupt priority, so when this interrupt + /* The SysTick runs at the lowest interrupt priority, so when this interrupt executes all interrupts must be unmasked. There is therefore no need to save and then restore the interrupt mask value as its value is already known. */ - ( void ) portSET_INTERRUPT_MASK_FROM_ISR(); - /* Increment the RTOS tick. */ + ( void ) portSET_INTERRUPT_MASK_FROM_ISR(); + + /* check for overflow in TICK counter */ + if(nrf_rtc_event_pending(portNRF_RTC_REG, NRF_RTC_EVENT_OVERFLOW)) + { + nrf_rtc_event_clear(portNRF_RTC_REG, NRF_RTC_EVENT_OVERFLOW); + tick_overflow_count++; + } + + diff = ((tick_overflow_count << portNRF_RTC_BITWIDTH) + nrf_rtc_counter_get(portNRF_RTC_REG)) - xTaskGetTickCount(); + + + if(diff > 1) + { + /* This could happen if this interupt was masked for more than one RTOS tick period */ + vTaskStepTick(diff - 1); + } + + /* Increment the RTOS tick as usual which checks if there is a need for rescheduling */ if ( xTaskIncrementTick() != pdFALSE ) { /* A context switch is required. Context switching is performed in @@ -173,6 +195,7 @@ void xPortSysTickHandler( void ) SCB->ICSR = SCB_ICSR_PENDSVSET_Msk; __SEV(); } + portCLEAR_INTERRUPT_MASK_FROM_ISR( 0 ); } @@ -190,6 +213,7 @@ void vPortSetupTimerInterrupt( void ) nrf_rtc_int_enable (portNRF_RTC_REG, RTC_INTENSET_TICK_Msk); nrf_rtc_task_trigger (portNRF_RTC_REG, NRF_RTC_TASK_CLEAR); nrf_rtc_task_trigger (portNRF_RTC_REG, NRF_RTC_TASK_START); + nrf_rtc_event_enable(portNRF_RTC_REG, RTC_EVTEN_OVRFLW_Msk); NVIC_SetPriority(portNRF_RTC_IRQn, configKERNEL_INTERRUPT_PRIORITY); NVIC_EnableIRQ(portNRF_RTC_IRQn); @@ -253,27 +277,43 @@ void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime ) configPRE_SLEEP_PROCESSING( xModifiableIdleTime ); if ( xModifiableIdleTime > 0 ) { - do{ - __WFE(); - } while (0 == (NVIC->ISPR[0] | NVIC->ISPR[1])); +#ifdef SOFTDEVICE_PRESENT + + uint32_t err_code = sd_app_evt_wait(); + APP_ERROR_CHECK(err_code); +#else + /* No SD - we would just block interrupts globally. + * BASEPRI cannot be used for that because it would prevent WFE from wake up. + */ + do{ + __WFE(); + } while (0 == (NVIC->ISPR[0] | NVIC->ISPR[1])); +#endif } configPOST_SLEEP_PROCESSING( xExpectedIdleTime ); + nrf_rtc_int_disable(portNRF_RTC_REG, NRF_RTC_INT_COMPARE0_MASK); + nrf_rtc_event_clear(portNRF_RTC_REG, NRF_RTC_EVENT_COMPARE_0); /* Correct the system ticks */ { TickType_t diff; - TickType_t hwTicks = nrf_rtc_counter_get(portNRF_RTC_REG); nrf_rtc_event_clear(portNRF_RTC_REG, NRF_RTC_EVENT_TICK); nrf_rtc_int_enable (portNRF_RTC_REG, NRF_RTC_INT_TICK_MASK); - if(enterTime > hwTicks) + /* check for overflow in TICK counter */ + if(nrf_rtc_event_pending(portNRF_RTC_REG, NRF_RTC_EVENT_OVERFLOW)) { - hwTicks += portNRF_RTC_MAXTICKS + 1U; + nrf_rtc_event_clear(portNRF_RTC_REG, NRF_RTC_EVENT_OVERFLOW); + tick_overflow_count++; } - diff = (hwTicks - enterTime); + diff = ((tick_overflow_count << portNRF_RTC_BITWIDTH) + nrf_rtc_counter_get(portNRF_RTC_REG)) - xTaskGetTickCount(); + + /* It is important that we clear pending here so that our corrections are latest and in sync with tick_interrupt handler */ + NVIC_ClearPendingIRQ(portNRF_RTC_IRQn); + if((configUSE_TICKLESS_IDLE_SIMPLE_DEBUG) && (diff > xExpectedIdleTime)) { diff = xExpectedIdleTime; diff --git a/sdk/nrf5/external/freertos/source/tasks.c b/sdk/nrf5/external/freertos/source/tasks.c index 6156d6b..a557543 100644 --- a/sdk/nrf5/external/freertos/source/tasks.c +++ b/sdk/nrf5/external/freertos/source/tasks.c @@ -1920,8 +1920,6 @@ UBaseType_t uxTaskGetNumberOfTasks( void ) This is to ensure vTaskStepTick() is available when user defined low power mode implementations require configUSE_TICKLESS_IDLE to be set to a value other than 1. */ -#if ( configUSE_TICKLESS_IDLE != 0 ) - void vTaskStepTick( const TickType_t xTicksToJump ) { /* Correct the tick count value after a period during which the tick @@ -1932,7 +1930,7 @@ implementations require configUSE_TICKLESS_IDLE to be set to a value other than traceINCREASE_TICK_COUNT( xTicksToJump ); } -#endif /* configUSE_TICKLESS_IDLE */ + /*----------------------------------------------------------*/ BaseType_t xTaskIncrementTick( void )