Skip to content

Commit 1c2f1e5

Browse files
hw/mcu/dialog: Rework CMAC sleep calculations
Sleep time calculation on CMAC assumed incorrectly that wakeup fsm uses lpclk but in fact RC32K is used so we need to take it into account. To make things easier to handle on CMAC side we will calculate wakeup time on M33 side and pass it to CMAC instead of XTAL32M settle time. This way we don't really need to care about how wakeup fsm is configured. It's now expected that M33 will take care of RC32K calibration and will calculate proper wakeup time based on wakeup fsm settings and XTAL32M settle time, and then notify CMAC on any change so we can recalculate our min sleep time.
1 parent c8596c3 commit 1c2f1e5

File tree

10 files changed

+99
-87
lines changed

10 files changed

+99
-87
lines changed

hw/drivers/ipc_cmac/include/ipc_cmac/shm.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ extern "C" {
3838

3939
#define CMAC_SHM_CB_MAGIC 0xc3ac
4040

41-
#define CMAC_SHM_CB_PENDING_OP_LP_CLK 0x0001
41+
#define CMAC_SHM_CB_PENDING_OP_SLEEP_UPDATE 0x0001
4242
#define CMAC_SHM_CB_PENDING_OP_RF_CAL 0x0002
4343

4444
#define CMAC_SHM_VECT_MAGIC 0xc3ac0001
@@ -59,7 +59,7 @@ struct cmac_shm_ctrl {
5959
uint16_t magic;
6060
uint16_t pending_ops;
6161
uint16_t lp_clock_freq;
62-
uint16_t xtal32m_settle_us;
62+
uint16_t wakeup_lpclk_ticks;
6363
};
6464

6565
struct cmac_shm_mbox {

hw/drivers/ipc_cmac/include/ipc_cmac/shm_hs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ extern volatile struct cmac_shm_debugdata *g_cmac_shm_debugdata;
3838

3939
void cmac_host_init(void);
4040
void cmac_host_signal2cmac(void);
41+
42+
void cmac_host_req_sleep_update(void);
4143
void cmac_host_rf_calibrate(void);
4244

4345
#ifdef __cplusplus

hw/drivers/ipc_cmac/src/shm_hs.c

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include <ipc_cmac/rand.h>
3737
#include "trng/trng.h"
3838
#include "console/console.h"
39+
#include "mcu/da1469x_sleep.h"
3940

4041
extern char _binary_cmac_img_bin_start[];
4142
extern char _binary_cmac_img_bin_end;
@@ -196,20 +197,10 @@ cmac_host_rand_chk_fill(void)
196197
}
197198
}
198199

199-
static void
200-
cmac_host_lpclk_cb(uint32_t freq)
200+
static bool
201+
shm_synced(void)
201202
{
202-
/* No need to wakeup CMAC if LP clock frequency did not change */
203-
if (g_cmac_shm_ctrl->lp_clock_freq == freq) {
204-
return;
205-
}
206-
207-
cmac_shm_lock();
208-
g_cmac_shm_ctrl->lp_clock_freq = freq;
209-
g_cmac_shm_ctrl->pending_ops |= CMAC_SHM_CB_PENDING_OP_LP_CLK;
210-
cmac_shm_unlock();
211-
212-
cmac_host_signal2cmac();
203+
return g_cmac_shm_ctrl && (g_cmac_shm_ctrl->magic == CMAC_SHM_CB_MAGIC);
213204
}
214205

215206
static void
@@ -234,8 +225,8 @@ shm_configure(void)
234225
struct cmac_shm_trim *trim;
235226
uint32_t *trim_data;
236227

237-
g_cmac_shm_ctrl->xtal32m_settle_us =
238-
MYNEWT_VAL(MCU_CLOCK_XTAL32M_SETTLE_TIME_US);
228+
g_cmac_shm_ctrl->lp_clock_freq = 0;
229+
g_cmac_shm_ctrl->wakeup_lpclk_ticks = 0;
239230

240231
trim = (struct cmac_shm_trim *)g_cmac_shm_trim;
241232
trim_data = trim->data;
@@ -415,7 +406,7 @@ cmac_start(void)
415406
/* Release CMAC from reset and sync */
416407
CRG_TOP->CLK_RADIO_REG &= ~CRG_TOP_CLK_RADIO_REG_CMAC_SYNCH_RESET_Msk;
417408

418-
while (g_cmac_shm_ctrl->magic != CMAC_SHM_CB_MAGIC) {
409+
while (!shm_synced()) {
419410
/* Wait for CMAC to initialize */
420411
}
421412
NVIC_EnableIRQ(CMAC2SYS_IRQn);
@@ -443,7 +434,7 @@ cmac_host_init(void)
443434

444435
cmac_start();
445436

446-
da1469x_lpclk_register_cmac_cb(cmac_host_lpclk_cb);
437+
cmac_host_req_sleep_update();
447438

448439
#if MYNEWT_VAL(CMAC_DEBUG_HOST_PRINT_ENABLE) && MYNEWT_VAL(CMAC_DEBUG_DATA_ENABLE)
449440
/* Trim values are calculated on RF init, so are valid after synced with CMAC */
@@ -462,9 +453,40 @@ cmac_host_signal2cmac(void)
462453
da1469x_pdc_set(g_cmac_host_pdc_sys2cmac);
463454
}
464455

456+
void
457+
cmac_host_req_sleep_update(void)
458+
{
459+
uint16_t lpclk_freq;
460+
uint32_t wakeup_lpclk_ticks;
461+
462+
if (!shm_synced()) {
463+
return;
464+
}
465+
466+
lpclk_freq = da1469x_lpclk_freq_get();
467+
wakeup_lpclk_ticks = da1469x_sleep_wakeup_ticks_get();
468+
469+
if ((g_cmac_shm_ctrl->lp_clock_freq == lpclk_freq) &&
470+
(g_cmac_shm_ctrl->wakeup_lpclk_ticks == wakeup_lpclk_ticks)) {
471+
return;
472+
}
473+
474+
cmac_shm_lock();
475+
g_cmac_shm_ctrl->lp_clock_freq = lpclk_freq;
476+
g_cmac_shm_ctrl->wakeup_lpclk_ticks = wakeup_lpclk_ticks;
477+
g_cmac_shm_ctrl->pending_ops |= CMAC_SHM_CB_PENDING_OP_SLEEP_UPDATE;
478+
cmac_shm_unlock();
479+
480+
cmac_host_signal2cmac();
481+
}
482+
465483
void
466484
cmac_host_rf_calibrate(void)
467485
{
486+
if (!shm_synced()) {
487+
return;
488+
}
489+
468490
cmac_shm_lock();
469491
g_cmac_shm_ctrl->pending_ops |= CMAC_SHM_CB_PENDING_OP_RF_CAL;
470492
cmac_shm_unlock();

hw/mcu/dialog/cmac/include/mcu/cmac_timer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ extern struct cmac_timer_ctrl g_cmac_timer_ctrl;
3535
void cmac_timer_init(void);
3636
void cmac_timer_slp_enable(uint32_t ticks);
3737
void cmac_timer_slp_disable(uint32_t exp_ticks);
38-
bool cmac_timer_slp_update(void);
38+
void cmac_timer_slp_update(uint16_t lp_clock_freq);
3939
bool cmac_timer_slp_is_ready(void);
4040
#if MYNEWT_VAL(MCU_SLP_TIMER_32K_ONLY)
4141
static inline uint32_t

hw/mcu/dialog/cmac/src/cmac_isr.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@
1717
* under the License.
1818
*/
1919

20+
#include <syscfg/syscfg.h>
2021
#include <CMAC.h>
2122
#include <mcu/cmac_pdc.h>
23+
#include <mcu/cmac_timer.h>
2224
#include <ipc_cmac/shm.h>
2325
#include <ipc_cmac/mbox.h>
2426
#include <ipc_cmac/rand.h>
@@ -40,8 +42,9 @@ SYS2CMAC_IRQHandler(void)
4042
cmac_mbox_read();
4143
cmac_rand_read();
4244

43-
if (pending_ops & CMAC_SHM_CB_PENDING_OP_LP_CLK) {
44-
cmac_sleep_recalculate();
45+
if (pending_ops & CMAC_SHM_CB_PENDING_OP_SLEEP_UPDATE) {
46+
cmac_timer_slp_update(g_cmac_shm_ctrl.lp_clock_freq);
47+
cmac_sleep_wakeup_time_update(g_cmac_shm_ctrl.wakeup_lpclk_ticks);
4548
}
4649

4750
if (pending_ops & CMAC_SHM_CB_PENDING_OP_RF_CAL) {

hw/mcu/dialog/cmac/src/cmac_priv.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ extern "C" {
3030
extern int8_t g_cmac_pdc_cmac2sys;
3131

3232
void cmac_sleep(void);
33-
void cmac_sleep_recalculate(void);
33+
void cmac_sleep_wakeup_time_update(uint16_t wakeup_lpclk_ticks);
3434

3535
#ifdef __cplusplus
3636
}

hw/mcu/dialog/cmac/src/cmac_sleep.c

Lines changed: 27 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,9 @@ static uint32_t g_retained_regs_val[ ARRAY_SIZE(retained_regs) ];
7272
static uint32_t g_mcu_wait_for_swd_start;
7373

7474
/* Minimum time required to go to sleep (until switch to SLP) and then wake up */
75-
static uint32_t g_mcu_wakeup_usecs_min;
75+
static uint32_t g_mcu_sleep_lp_ticks_min;
7676

77-
static bool
77+
static inline bool
7878
cmac_sleep_is_switch_allowed(void)
7979
{
8080
return (ble_phy_xcvr_state_get() == 0) &&
@@ -168,44 +168,34 @@ cmac_sleep_wait4xtal(void)
168168
*(volatile uint32_t *)0x5000001c = 1;
169169
}
170170

171-
#define T_USEC(_t) (_t)
172-
#define T_LPTICK(_t) ((_t) * cmac_timer_slp_tick_us())
173-
#define T_LPTICK_U(_t) (T_LPTICK(_t) * 15 / 10)
171+
#define T_USEC(_t) (((_t) + cmac_timer_slp_tick_us() - 1) / \
172+
cmac_timer_slp_tick_us())
173+
#define T_LPTICK(_t) (_t)
174174

175-
static void
176-
cmac_sleep_calculate_wakeup_time(void)
175+
void
176+
cmac_sleep_wakeup_time_update(uint16_t wakeup_lpclk_ticks)
177177
{
178-
assert(g_cmac_shm_ctrl.xtal32m_settle_us);
178+
if (wakeup_lpclk_ticks == 0) {
179+
g_mcu_sleep_lp_ticks_min = 0;
180+
return;
181+
}
179182

180-
g_mcu_wakeup_usecs_min =
183+
g_mcu_sleep_lp_ticks_min =
181184
/*
182-
* We need ~12us to prepare for sleep before starting switch to SLP.
185+
* We need ~15us to prepare for sleep before starting switch to SLP.
183186
* Switch to SLP is done by switching SLP clock to LPCLK first and then
184187
* enabling SLP. The former has to be synchronized with negative edge of
185188
* LPCLK and the latter happens on positive edge of LPCLK so we just
186189
* assume 2 LPCLK ticks in worst case.
187190
*/
188-
T_USEC(12) + T_LPTICK(2) +
191+
T_USEC(15) + T_LPTICK(2) +
189192
/*
190-
* On wake up we assume fast wake up mode which has 3 phases that take
191-
* up to 2, 2 and 3 LPCLK ticks respectively (need to add some margin
192-
* here for worst-worst case). XTAL32M is started at 3rd phase and we
193-
* need to wait for it to settle before switch back to LLT. This is done
194-
* by disabling SLP and then switching SLP clock to PCLK. Both actions
195-
* are synchronized with LPCLK negative edge so take 2 LPCLK ticks in
196-
* worst case. Finally, LLP compensation takes around 50us.
193+
* After wakeup (this includes XTAL32M settling) we need to switch back
194+
* to LLT. This is done by disabling SLP and then switching SLP clock to
195+
* PCLK. Both actions are synchronized with LPCLK negative edge so take
196+
* 2 LPCLK ticks in worst case. Finally, LLT compensation takes ~50us.
197197
*/
198-
T_LPTICK_U(2) + T_LPTICK_U(2) +
199-
max(T_LPTICK_U(3), T_USEC(g_cmac_shm_ctrl.xtal32m_settle_us)) +
200-
T_LPTICK(2) + T_USEC(50);
201-
}
202-
203-
void
204-
cmac_sleep_recalculate(void)
205-
{
206-
if (cmac_timer_slp_update()) {
207-
cmac_sleep_calculate_wakeup_time();
208-
}
198+
T_LPTICK(wakeup_lpclk_ticks) + T_LPTICK(2) + T_USEC(50);
209199
}
210200

211201
extern bool ble_rf_try_recalibrate(uint32_t idle_time_us);
@@ -228,25 +218,21 @@ cmac_sleep(void)
228218
cmac_pdc_ack_all();
229219

230220
wakeup_at = cmac_timer_next_at();
221+
sleep_usecs = wakeup_at - cmac_timer_read32();
231222

232-
/*
233-
* At this point in time we know exactly when next LLT interrupt should
234-
* happen so need to make sure we can be up and running on time.
235-
*/
223+
if (ble_rf_try_recalibrate(sleep_usecs)) {
224+
goto skip_sleep;
225+
}
236226

237-
sleep_usecs = wakeup_at - cmac_timer_read32() - g_mcu_wakeup_usecs_min;
238-
if ((int32_t)sleep_usecs <= 0) {
227+
if (g_mcu_sleep_lp_ticks_min == 0) {
239228
switch_to_slp = false;
240229
deep_sleep = false;
241230
goto do_sleep;
242231
}
243232

244-
if (ble_rf_try_recalibrate(sleep_usecs)) {
245-
goto skip_sleep;
246-
}
247-
248-
sleep_lp_ticks = cmac_timer_usecs_to_lp_ticks(sleep_usecs);
249-
if (sleep_lp_ticks <= 1) {
233+
sleep_lp_ticks = cmac_timer_usecs_to_lp_ticks(sleep_usecs) -
234+
g_mcu_sleep_lp_ticks_min;
235+
if ((int32_t)sleep_lp_ticks <= 1) {
250236
switch_to_slp = false;
251237
deep_sleep = false;
252238
goto do_sleep;

hw/mcu/dialog/cmac/src/cmac_timer.c

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -334,15 +334,11 @@ cmac_timer_slp_disable(uint32_t exp_ticks)
334334
assert(CMAC->CM_LL_INT_STAT_REG == 0);
335335
}
336336

337-
bool
338-
cmac_timer_slp_update(void)
337+
void
338+
cmac_timer_slp_update(uint16_t lp_clock_freq)
339339
{
340-
uint32_t lp_clock_freq;
341-
342-
lp_clock_freq = g_cmac_shm_ctrl.lp_clock_freq;
343-
344340
if (lp_clock_freq == g_cmac_timer_slp.freq) {
345-
return false;
341+
return;
346342
}
347343

348344
g_cmac_timer_slp.freq = lp_clock_freq;
@@ -353,8 +349,6 @@ cmac_timer_slp_update(void)
353349
g_cmac_timer_slp.tick_ns = 1000000000 / g_cmac_timer_slp.freq;
354350
}
355351
#endif
356-
357-
return true;
358352
}
359353

360354
bool
@@ -363,7 +357,7 @@ cmac_timer_slp_is_ready(void)
363357
#if MYNEWT_VAL(MCU_SLP_TIMER_32K_ONLY)
364358
return g_cmac_timer_slp.freq == 32768;
365359
#else
366-
return g_cmac_timer_slp.freq;
360+
return g_cmac_timer_slp.freq != 0;
367361
#endif
368362
}
369363

hw/mcu/dialog/da1469x/include/mcu/da1469x_lpclk.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,8 @@
2626
extern "C" {
2727
#endif
2828

29-
typedef void (da1469x_lpclk_cb)(uint32_t freq);
29+
uint16_t da1469x_lpclk_freq_get(void);
3030

31-
void da1469x_lpclk_register_cmac_cb(da1469x_lpclk_cb *cb);
3231
/* Stable lp clock enabled (e.g. switched to XTAL after settling) */
3332
void da1469x_lpclk_enabled(void);
3433
/* Frequency of lp clock changed (e.g. after RCX recalibration) */

hw/mcu/dialog/da1469x/src/da1469x_lpclk.c

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,10 @@
2828
#include "hal/hal_timer.h"
2929
#include "os/os_cputime.h"
3030
#include "da1469x_priv.h"
31+
#include "ipc_cmac/shm.h"
3132

3233
bool g_mcu_lpclk_available;
3334

34-
static da1469x_lpclk_cb *g_da1469x_lpclk_cmac_cb;
35-
3635
#if MYNEWT_VAL_CHOICE(MCU_LPCLK_SOURCE, XTAL32K)
3736
static void
3837
da1469x_lpclk_settle_tmr_cb(void *arg)
@@ -45,22 +44,29 @@ da1469x_lpclk_settle_tmr_cb(void *arg)
4544
static void
4645
da1469x_lpclk_notify(void)
4746
{
48-
if (!g_da1469x_lpclk_cmac_cb || !g_mcu_lpclk_available) {
47+
if (!g_mcu_lpclk_available) {
4948
return;
5049
}
5150

52-
#if MYNEWT_VAL_CHOICE(MCU_LPCLK_SOURCE, XTAL32K)
53-
g_da1469x_lpclk_cmac_cb(32768);
54-
#elif MYNEWT_VAL_CHOICE(MCU_LPCLK_SOURCE, RCX)
55-
g_da1469x_lpclk_cmac_cb(da1469x_clock_lp_rcx_freq_get());
51+
#if MYNEWT_PKG_apache_mynewt_core__hw_drivers_ipc_cmac
52+
cmac_host_req_sleep_update();
5653
#endif
5754
}
5855

59-
void
60-
da1469x_lpclk_register_cmac_cb(da1469x_lpclk_cb *cb)
56+
uint16_t
57+
da1469x_lpclk_freq_get(void)
6158
{
62-
g_da1469x_lpclk_cmac_cb = cb;
63-
da1469x_lpclk_notify();
59+
if (!g_mcu_lpclk_available) {
60+
return 0;
61+
}
62+
63+
#if MYNEWT_VAL_CHOICE(MCU_LPCLK_SOURCE, XTAL32K)
64+
return 32768;
65+
#elif MYNEWT_VAL_CHOICE(MCU_LPCLK_SOURCE, RCX)
66+
return da1469x_clock_lp_rcx_freq_get();
67+
#else
68+
return 0;
69+
#endif
6470
}
6571

6672
void

0 commit comments

Comments
 (0)