Skip to content
Snippets Groups Projects
Commit 4b22f2a7 authored by schneider's avatar schneider
Browse files

Merge branch 'schneider/ble-sleep' into 'master'

epicardium: Query BLE hardware for idle periods

See merge request card10/firmware!500
parents 4d0045ff 545d6473
Branches
Tags
No related merge requests found
...@@ -9,13 +9,45 @@ ...@@ -9,13 +9,45 @@
#include "user_core/user_core.h" #include "user_core/user_core.h"
#include "os/core.h" #include "os/core.h"
#include "drivers/drivers.h" #include "drivers/drivers.h"
#include "modules/modules.h"
#define BB_CLK_RATE_HZ 1600000
#include "usb.h" #include "usb.h"
#include "mxc_sys.h" #include "mxc_sys.h"
#include "wut.h" #include "wut.h"
#include "wsf_types.h"
#include "wsf_os.h"
#include "sch_api_ble.h"
#include "bb_drv.h"
#include "card10.h" #include "card10.h"
#define US_TO_BBTICKS(x) (((x) * (BB_CLK_RATE_HZ / 100000) + 9) / 10)
#define MIN(a, b) (a < b) ? a : b
#define MIN_SLEEP_TIME_MS 1
static int32_t ble_sleep_ticks(void)
{
uint32_t nextDbbEventDue;
bool_t dueValid = SchBleGetNextDueTime(&nextDbbEventDue);
int sleep_ticks = nextDbbEventDue - BbDrvGetCurrentTime();
if (dueValid) {
if (sleep_ticks > 0) {
uint32_t bb_idle = BB_TICKS_TO_US(sleep_ticks) / 1000;
return bb_idle;
} else {
return 0;
}
} else {
return -1;
}
}
/* /*
* This hook is called before FreeRTOS enters tickless idle. * This hook is called before FreeRTOS enters tickless idle.
*/ */
...@@ -28,16 +60,23 @@ void pre_idle_sleep(TickType_t xExpectedIdleTime) ...@@ -28,16 +60,23 @@ void pre_idle_sleep(TickType_t xExpectedIdleTime)
* epicardium if it wants to issue an API call. * epicardium if it wants to issue an API call.
*/ */
/*
* TODO: Ensure this is actually correct and does not have any
* race conditions.
*/
/* If the other core is waiting for a call to return and we are able /* If the other core is waiting for a call to return and we are able
* to sleep, reduce the system clock to save energy. */ * to sleep, reduce the system clock to save energy. */
if (xExpectedIdleTime >= pdMS_TO_TICKS(10) && if (xExpectedIdleTime >= pdMS_TO_TICKS(MIN_SLEEP_TIME_MS) &&
api_dispatcher_call_pending()) { api_dispatcher_call_pending() && wsfOsReadyToSleep()) {
uint32_t ms = xExpectedIdleTime - 1; uint32_t ms = xExpectedIdleTime;
if (ble_is_enabled()) {
int32_t ble_idle = ble_sleep_ticks();
if (ble_idle >= 0) {
ms =
MIN(xExpectedIdleTime,
(uint32_t)ble_idle);
}
}
// Us the WUT only if we can sleep a significant amount of time
if (ms >= MIN_SLEEP_TIME_MS) {
/* Initialize Wakeup timer */ /* Initialize Wakeup timer */
WUT_Init(WUT_PRES_1); WUT_Init(WUT_PRES_1);
wut_cfg_t wut_cfg; wut_cfg_t wut_cfg;
...@@ -51,7 +90,9 @@ void pre_idle_sleep(TickType_t xExpectedIdleTime) ...@@ -51,7 +90,9 @@ void pre_idle_sleep(TickType_t xExpectedIdleTime)
uint32_t targetTick; uint32_t targetTick;
targetTick = WUT_GetCount(); targetTick = WUT_GetCount();
targetTick += ((uint64_t)(ms)*SYS_WUT_GetFreq() / 1000); targetTick +=
((uint64_t)(ms)*SYS_WUT_GetFreq() /
1000);
WUT_SetCompare(targetTick); WUT_SetCompare(targetTick);
/* Stop SysTick */ /* Stop SysTick */
...@@ -59,34 +100,53 @@ void pre_idle_sleep(TickType_t xExpectedIdleTime) ...@@ -59,34 +100,53 @@ void pre_idle_sleep(TickType_t xExpectedIdleTime)
SysTick->CTRL &= ~(SysTick_CTRL_ENABLE_Msk); SysTick->CTRL &= ~(SysTick_CTRL_ENABLE_Msk);
if (usb_get_status() & MAXUSB_STATUS_VBUS_ON) { if (usb_get_status() & MAXUSB_STATUS_VBUS_ON) {
SYS_Clock_Select(SYS_CLOCK_HIRC, NULL); /* Need to stay on 96 MHz. USB serial becomes
* unstable otherwise. Don't know why. */
//SYS_Clock_Select(SYS_CLOCK_HIRC, NULL);
} else { } else {
MXC_GCR->clkcn |=
MXC_S_GCR_CLKCN_PSC_DIV4;
SYS_Clock_Select(SYS_CLOCK_HIRC, NULL); SYS_Clock_Select(SYS_CLOCK_HIRC, NULL);
SYS_ClockSourceDisable(SYS_CLOCK_HIRC96); SYS_ClockSourceDisable(
SYS_CLOCK_HIRC96
);
} }
disp_update_backlight_clock(); disp_update_backlight_clock();
__asm volatile("dsb" ::: "memory"); __asm volatile("dsb" ::: "memory");
__asm volatile("wfe"); __asm volatile("wfe");
__asm volatile("isb"); __asm volatile("isb");
MXC_GCR->clkcn &= ~(MXC_S_GCR_CLKCN_PSC_DIV4);
SYS_Clock_Select(SYS_CLOCK_HIRC96, NULL); SYS_Clock_Select(SYS_CLOCK_HIRC96, NULL);
#if 0
/* Allow to serve high priority interrupts before
* doing the lengthy xTaskIncrementTick loop. */
portDISABLE_INTERRUPTS();
__set_PRIMASK(0);
__set_PRIMASK(1);
portENABLE_INTERRUPTS();
#endif
disp_update_backlight_clock(); disp_update_backlight_clock();
SYS_ClockSourceDisable(SYS_CLOCK_HIRC); SYS_ClockSourceDisable(SYS_CLOCK_HIRC);
SysTick->LOAD = val; SysTick->LOAD = val;
SysTick->VAL = 0; SysTick->VAL = 0;
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;
ms = (WUT_GetCount() * 1000) / SYS_WUT_GetFreq(); ms = (WUT_GetCount() * 1000) /
SYS_WUT_GetFreq();
for (uint32_t t = 0; t < ms; t++) { for (uint32_t t = 0; t < ms; t++) {
xTaskIncrementTick(); xTaskIncrementTick();
} }
return;
}
}
} else { /* Fall back to light sleep with clocks on if we can't
* sleep long enough for the WUT */
__asm volatile("dsb" ::: "memory"); __asm volatile("dsb" ::: "memory");
__asm volatile("wfe"); __asm volatile("wfe");
__asm volatile("isb"); __asm volatile("isb");
} }
} }
}
/* /*
* This hook is called after FreeRTOS exits tickless idle. * This hook is called after FreeRTOS exits tickless idle.
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment