Skip to content

Commit dc75210

Browse files
committed
drivers: timer: Provide radio timer driver for STM32WB0x SoCs
Provide radio timer driver for STM32WB0x SoCs. Signed-off-by: Ali Hozhabri <[email protected]>
1 parent 0148d5a commit dc75210

File tree

1 file changed

+199
-0
lines changed

1 file changed

+199
-0
lines changed

drivers/timer/stm32_radio_timer.c

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
/* stm32_radio_timer.c - STM32WB0x Radio Timer */
2+
3+
/*
4+
* Copyright (c) 2025 STMicroelectronics
5+
*
6+
* SPDX-License-Identifier: Apache-2.0
7+
*/
8+
#include <zephyr/kernel.h>
9+
#include <zephyr/init.h>
10+
#include <zephyr/drivers/timer/system_timer.h>
11+
#include <zephyr/sys_clock.h>
12+
#include <zephyr/spinlock.h>
13+
#include <cmsis_core.h>
14+
#include <zephyr/irq.h>
15+
#include <zephyr/sys/util.h>
16+
#include <zephyr/drivers/counter.h>
17+
#include "stm32wb0x_hal_radio_timer.h"
18+
19+
#include <zephyr/logging/log.h>
20+
LOG_MODULE_REGISTER(radio_timer_driver);
21+
22+
/* Max HS startup time expressed in system time (1953 us / 2.4414 us) */
23+
#define MAX_HS_STARTUP_TIME 320
24+
#define BLE_WKUP_PRIO 0
25+
#define BLE_WKUP_FLAGS 0
26+
#define CPU_WKUP_PRIO 1
27+
#define CPU_WKUP_FLAGS 0
28+
#define RADIO_TIMER_ERROR_PRIO 3
29+
#define RADIO_TIMER_ERROR_FLAGS 0
30+
31+
#define MULT64_THR_FREQ (806)
32+
#define TIMER_MAX_VALUE (0xFFFFFFFFU)
33+
#define TIMER_WRAPPING_MARGIN (4096)
34+
#define MAX_ALLOWED_DELAY (TIMER_MAX_VALUE - TIMER_WRAPPING_MARGIN)
35+
36+
37+
BUILD_ASSERT(DT_NODE_HAS_STATUS(DT_NODELABEL(clk_lsi), disabled),
38+
"At the moment, LSI is not supported");
39+
40+
/* Translate STU to MTU and vice versa. It is implemented by using integer operations. */
41+
uint32_t blue_unit_conversion(uint32_t time, uint32_t period_freq, uint32_t thr);
42+
static uint64_t announced_cycles;
43+
44+
static void radio_timer_error_isr(void *args)
45+
{
46+
volatile uint32_t debug_cmd;
47+
48+
ARG_UNUSED(args);
49+
50+
BLUE->DEBUGCMDREG |= 1;
51+
/* If the device is configured with CLK_SYS = 64MHz
52+
* and BLE clock = 16MHz, a register read is necessary
53+
* to ensure interrupt register is properly cleared
54+
* due to AHB down converter latency
55+
*/
56+
debug_cmd = BLUE->DEBUGCMDREG;
57+
LOG_ERR("Timer error");
58+
}
59+
60+
static void radio_timer_cpu_wkup_isr(void *args)
61+
{
62+
int32_t dticks;
63+
uint64_t diff_cycles;
64+
65+
ARG_UNUSED(args);
66+
67+
HAL_RADIO_TIMER_TimeoutCallback();
68+
if (IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
69+
diff_cycles = HAL_RADIO_TIMER_GetCurrentSysTime() - announced_cycles;
70+
dticks = (int32_t)k_cyc_to_ticks_near64(diff_cycles);
71+
announced_cycles += k_ticks_to_cyc_near32(dticks);
72+
sys_clock_announce(dticks);
73+
} else {
74+
sys_clock_announce(1);
75+
}
76+
}
77+
78+
volatile uint32_t ciccio_k = 0;
79+
#if defined(CONFIG_SOC_STM32WB06) || defined(CONFIG_SOC_STM32WB07)
80+
static void radio_timer_txrx_wkup_isr(void *args)
81+
{
82+
ARG_UNUSED(args);
83+
84+
HAL_RADIO_TIMER_WakeUpCallback();
85+
}
86+
#endif /* CONFIG_SOC_STM32WB06 || CONFIG_SOC_STM32WB07 */
87+
88+
void sys_clock_set_timeout(int32_t ticks, bool idle)
89+
{
90+
ARG_UNUSED(idle);
91+
92+
if (ticks == K_TICKS_FOREVER) {
93+
return;
94+
}
95+
96+
#if defined(CONFIG_TICKLESS_KERNEL)
97+
uint32_t current_time, delay;
98+
99+
/* This value is only valid for the LSE with a frequency of 32768 Hz.
100+
* The implementation for the LSI will be done in the future.
101+
*/
102+
uint32_t calibrationData_freq1 = 0x0028F5C2;
103+
104+
if (ticks < 1) {
105+
ticks = 1;
106+
}
107+
//CLAMP(ticks, 1, (int32_t)MAX_TICKS);
108+
delay = blue_unit_conversion(k_ticks_to_cyc_near32(ticks), calibrationData_freq1, MULT64_THR_FREQ) ;
109+
if (delay > MAX_ALLOWED_DELAY) {
110+
delay = MAX_ALLOWED_DELAY;
111+
} else {
112+
/* If the delay is too small round to minimum 2 ticks */
113+
delay = MAX(32, delay);
114+
}
115+
current_time = LL_RADIO_TIMER_GetAbsoluteTime(WAKEUP);
116+
/* 4 least significant bits are not taken into account. Then let's round the value */
117+
LL_RADIO_TIMER_SetCPUWakeupTime(WAKEUP, ((current_time + (delay + 8)) & TIMER_MAX_VALUE));
118+
LL_RADIO_TIMER_EnableWakeupTimerLowPowerMode(WAKEUP);
119+
LL_RADIO_TIMER_EnableCPUWakeupTimer(WAKEUP);
120+
121+
#endif /* CONFIG_TICKLESS_KERNEL */
122+
}
123+
124+
uint32_t sys_clock_elapsed(void)
125+
{
126+
if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
127+
return 0;
128+
}
129+
130+
return k_cyc_to_ticks_near32(HAL_RADIO_TIMER_GetCurrentSysTime() - announced_cycles);
131+
}
132+
133+
uint32_t sys_clock_cycle_get_32(void)
134+
{
135+
uint64_t val64;
136+
137+
val64 = sys_clock_cycle_get_64();
138+
return val64 & 0xFFFFFFFF;
139+
}
140+
141+
uint64_t sys_clock_cycle_get_64(void)
142+
{
143+
uint64_t cycles;
144+
145+
cycles = HAL_RADIO_TIMER_GetCurrentSysTime();
146+
return cycles;
147+
}
148+
149+
void sys_clock_disable(void)
150+
{
151+
#if defined(CONFIG_SOC_STM32WB06) || defined(CONFIG_SOC_STM32WB07)
152+
irq_disable(RADIO_TIMER_TXRX_WKUP_IRQn);
153+
#endif /* CONFIG_SOC_STM32WB06 || CONFIG_SOC_STM32WB07 */
154+
irq_disable(RADIO_TIMER_CPU_WKUP_IRQn);
155+
irq_disable(RADIO_TIMER_ERROR_IRQn);
156+
__HAL_RCC_RADIO_CLK_DISABLE();
157+
}
158+
159+
static int sys_clock_driver_init(void)
160+
{
161+
RADIO_TIMER_InitTypeDef VTIMER_InitStruct = {MAX_HS_STARTUP_TIME, 0, 0};
162+
163+
#if defined(CONFIG_SOC_STM32WB06) || defined(CONFIG_SOC_STM32WB07)
164+
IRQ_CONNECT(RADIO_TIMER_TXRX_WKUP_IRQn,
165+
BLE_WKUP_PRIO,
166+
radio_timer_txrx_wkup_isr,
167+
NULL,
168+
BLE_WKUP_FLAGS);
169+
#endif /* CONFIG_SOC_STM32WB06 || CONFIG_SOC_STM32WB07 */
170+
171+
IRQ_CONNECT(RADIO_TIMER_CPU_WKUP_IRQn,
172+
CPU_WKUP_PRIO,
173+
radio_timer_cpu_wkup_isr,
174+
NULL,
175+
CPU_WKUP_FLAGS);
176+
IRQ_CONNECT(RADIO_TIMER_ERROR_IRQn,
177+
RADIO_TIMER_ERROR_PRIO,
178+
radio_timer_error_isr,
179+
NULL,
180+
RADIO_TIMER_ERROR_FLAGS);
181+
182+
/* Peripheral clock enable */
183+
if (__HAL_RCC_RADIO_IS_CLK_DISABLED()) {
184+
/* Radio reset */
185+
__HAL_RCC_RADIO_FORCE_RESET();
186+
__HAL_RCC_RADIO_RELEASE_RESET();
187+
188+
/* Enable Radio peripheral clock */
189+
__HAL_RCC_RADIO_CLK_ENABLE();
190+
}
191+
192+
/* Wait to be sure that the Radio Timer is active */
193+
while (LL_RADIO_TIMER_GetAbsoluteTime(WAKEUP) < 0x10) {
194+
}
195+
HAL_RADIO_TIMER_Init(&VTIMER_InitStruct);
196+
return 0;
197+
}
198+
199+
SYS_INIT(sys_clock_driver_init, PRE_KERNEL_2, CONFIG_SYSTEM_CLOCK_INIT_PRIORITY);

0 commit comments

Comments
 (0)