1 /* USER CODE BEGIN Header */
2 /**
3 ******************************************************************************
4 * @file linklayer_plat.c
5 * @author MCD Application Team
6 * @brief Source file for the linklayer plateform adaptation layer
7 ******************************************************************************
8 * @attention
9 *
10 * Copyright (c) 2022 STMicroelectronics.
11 * All rights reserved.
12 *
13 * This software is licensed under terms that can be found in the LICENSE file
14 * in the root directory of this software component.
15 * If no LICENSE file comes with this software, it is provided AS-IS.
16 *
17 ******************************************************************************
18 */
19 /* USER CODE END Header */
20
21 #ifndef __ZEPHYR__
22 #include "stm32wbaxx_hal.h"
23 #include "stm32wbaxx_hal_conf.h"
24 #include "stm32wbaxx_ll_rcc.h"
25
26 #include "app_common.h"
27 #include "app_conf.h"
28 #include "linklayer_plat.h"
29 #include "scm.h"
30 #include "log_module.h"
31 #if (USE_TEMPERATURE_BASED_RADIO_CALIBRATION == 1)
32 #include "adc_ctrl.h"
33 #endif /* (USE_TEMPERATURE_BASED_RADIO_CALIBRATION == 1) */
34
35 #if (CFG_LPM_LEVEL != 0)
36 #include "stm32_lpm.h"
37 #endif /* (CFG_LPM_LEVEL != 0) */
38 /* USER CODE BEGIN Includes */
39
40 /* USER CODE END Includes */
41
42 #else
43 #include "scm.h"
44 #endif
45 #define max(a,b) ((a) > (b) ? a : b)
46
47 /* 2.4GHz RADIO ISR callbacks */
48 typedef void (*radio_isr_cb_t) (void);
49
50
51
52 /* Radio critical sections */
53 static uint32_t primask_bit = 0;
54 volatile int32_t irq_counter;
55
56 /* Radio bus clock control variables */
57 uint8_t AHB5_SwitchedOff;
58 uint32_t radio_sleep_timer_val;
59
60 /**
61 * @brief Configure the necessary clock sources for the radio.
62 * @param None
63 * @retval None
64 */
LINKLAYER_PLAT_ClockInit(void)65 void LINKLAYER_PLAT_ClockInit(void)
66 {
67 AHB5_SwitchedOff = 0;
68 radio_sleep_timer_val = 0;
69
70 LL_PWR_EnableBkUpAccess();
71
72 /* Select LSE as Sleep CLK */
73 __HAL_RCC_RADIOSLPTIM_CONFIG(RCC_RADIOSTCLKSOURCE_LSE);
74
75 LL_PWR_DisableBkUpAccess();
76
77 /* Enable AHB5ENR peripheral clock (bus CLK) */
78 __HAL_RCC_RADIO_CLK_ENABLE();
79 }
80
81 #ifndef __ZEPHYR__
82 /**
83 * @brief Link Layer active waiting loop.
84 * @param delay: delay in us
85 * @retval None
86 */
LINKLAYER_PLAT_DelayUs(uint32_t delay)87 void LINKLAYER_PLAT_DelayUs(uint32_t delay)
88 {
89 __IO register uint32_t Delay = delay * (SystemCoreClock / 1000000U);
90 do
91 {
92 __NOP();
93 }
94 while (Delay --);
95 }
96
97 /**
98 * @brief Link Layer assertion API
99 * @param condition: conditional statement to be checked.
100 * @retval None
101 */
LINKLAYER_PLAT_Assert(uint8_t condition)102 void LINKLAYER_PLAT_Assert(uint8_t condition)
103 {
104 assert_param(condition);
105 }
106 #endif
107
108 /**
109 * @brief Enable/disable the Link Layer active clock (baseband clock).
110 * @param enable: boolean value to enable (1) or disable (0) the clock.
111 * @retval None
112 */
LINKLAYER_PLAT_WaitHclkRdy(void)113 void LINKLAYER_PLAT_WaitHclkRdy(void)
114 {
115 /* Wait on radio bus clock readiness */
116 while(HAL_RCCEx_GetRadioBusClockReadiness() != RCC_RADIO_BUS_CLOCK_READY);
117 }
118
119 /**
120 * @brief Notify the Link Layer platform layer the system will enter in WFI
121 * and AHB5 clock may be turned of regarding the 2.4Ghz radio state.
122 * @param None
123 * @retval None
124 */
LINKLAYER_PLAT_NotifyWFIEnter(void)125 void LINKLAYER_PLAT_NotifyWFIEnter(void)
126 {
127 /* Check if Radio state will allow the AHB5 clock to be cut */
128
129 /* AHB5 clock will be cut in the following cases:
130 * - 2.4GHz radio is not in ACTIVE mode (in SLEEP or DEEPSLEEP mode).
131 * - RADIOSMEN and STRADIOCLKON bits are at 0.
132 */
133 if((LL_PWR_GetRadioMode() != LL_PWR_RADIO_ACTIVE_MODE) ||
134 ((__HAL_RCC_RADIO_IS_CLK_SLEEP_ENABLED() == 0) && (LL_RCC_RADIO_IsEnabledSleepTimerClock() == 0)))
135 {
136 AHB5_SwitchedOff = 1;
137 }
138 }
139
140 /**
141 * @brief Notify the Link Layer platform layer the system exited WFI and AHB5
142 * clock may be resynchronized as is may have been turned of during
143 * low power mode entry.
144 * @param None
145 * @retval None
146 */
LINKLAYER_PLAT_NotifyWFIExit(void)147 void LINKLAYER_PLAT_NotifyWFIExit(void)
148 {
149 /* Check if AHB5 clock has been turned of and needs resynchronisation */
150 if (AHB5_SwitchedOff)
151 {
152 /* Read sleep register as earlier as possible */
153 radio_sleep_timer_val = ll_intf_cmn_get_slptmr_value();
154 }
155 }
156
157 /**
158 * @brief Active wait on bus clock readiness.
159 * @param None
160 * @retval None
161 */
LINKLAYER_PLAT_AclkCtrl(uint8_t enable)162 void LINKLAYER_PLAT_AclkCtrl(uint8_t enable)
163 {
164 if(enable){
165 /* Enable RADIO baseband clock (active CLK) */
166 HAL_RCCEx_EnableRadioBBClock();
167
168 /* Polling on HSE32 activation */
169 while ( LL_RCC_HSE_IsReady() == 0);
170 }
171 else
172 {
173 /* Disable RADIO baseband clock (active CLK) */
174 HAL_RCCEx_DisableRadioBBClock();
175 }
176 }
177
178 #ifndef __ZEPHYR__
179 /**
180 * @brief Link Layer RNG request.
181 * @param ptr_rnd: pointer to the variable that hosts the number.
182 * @param len: number of byte of anthropy to get.
183 * @retval None
184 */
LINKLAYER_PLAT_GetRNG(uint8_t * ptr_rnd,uint32_t len)185 void LINKLAYER_PLAT_GetRNG(uint8_t *ptr_rnd, uint32_t len)
186 {
187 uint32_t nb_remaining_rng = len;
188 uint32_t generated_rng;
189
190 /* Get the requested RNGs (4 bytes by 4bytes) */
191 while(nb_remaining_rng >= 4)
192 {
193 generated_rng = 0;
194 HW_RNG_Get(1, &generated_rng);
195 memcpy((ptr_rnd+(len-nb_remaining_rng)), &generated_rng, 4);
196 nb_remaining_rng -=4;
197 }
198
199 /* Get the remaining number of RNGs */
200 if(nb_remaining_rng>0){
201 generated_rng = 0;
202 HW_RNG_Get(1, &generated_rng);
203 memcpy((ptr_rnd+(len-nb_remaining_rng)), &generated_rng, nb_remaining_rng);
204 }
205 }
206
207 /**
208 * @brief Initialize Link Layer radio high priority interrupt.
209 * @param intr_cb: function pointer to assign for the radio high priority ISR routine.
210 * @retval None
211 */
LINKLAYER_PLAT_SetupRadioIT(void (* intr_cb)())212 void LINKLAYER_PLAT_SetupRadioIT(void (*intr_cb)())
213 {
214 radio_callback = intr_cb;
215 HAL_NVIC_SetPriority((IRQn_Type) RADIO_INTR_NUM, RADIO_INTR_PRIO_HIGH, 0);
216 HAL_NVIC_EnableIRQ((IRQn_Type) RADIO_INTR_NUM);
217 }
218
219 /**
220 * @brief Initialize Link Layer SW low priority interrupt.
221 * @param intr_cb: function pointer to assign for the SW low priority ISR routine.
222 * @retval None
223 */
LINKLAYER_PLAT_SetupSwLowIT(void (* intr_cb)())224 void LINKLAYER_PLAT_SetupSwLowIT(void (*intr_cb)())
225 {
226 low_isr_callback = intr_cb;
227
228 HAL_NVIC_SetPriority((IRQn_Type) RADIO_SW_LOW_INTR_NUM, RADIO_SW_LOW_INTR_PRIO, 0);
229 HAL_NVIC_EnableIRQ((IRQn_Type) RADIO_SW_LOW_INTR_NUM);
230 }
231
232 /**
233 * @brief Trigger the link layer SW low interrupt.
234 * @param None
235 * @retval None
236 */
LINKLAYER_PLAT_TriggerSwLowIT(uint8_t priority)237 void LINKLAYER_PLAT_TriggerSwLowIT(uint8_t priority)
238 {
239 uint8_t low_isr_priority = RADIO_INTR_PRIO_LOW;
240
241 /* Check if a SW low interrupt as already been raised.
242 * Nested call far radio low isr are not supported
243 **/
244
245 if(NVIC_GetActive(RADIO_SW_LOW_INTR_NUM) == 0)
246 {
247 /* No nested SW low ISR, default behavior */
248
249 if(priority == 0)
250 {
251 low_isr_priority = RADIO_SW_LOW_INTR_PRIO;
252 }
253
254 HAL_NVIC_SetPriority((IRQn_Type) RADIO_SW_LOW_INTR_NUM, low_isr_priority, 0);
255 }
256 else
257 {
258 /* Nested call detected */
259 /* No change for SW radio low interrupt priority for the moment */
260
261 if(priority != 0)
262 {
263 /* At the end of current SW radio low ISR, this pending SW low interrupt
264 * will run with RADIO_INTR_PRIO_LOW priority
265 **/
266 radio_sw_low_isr_is_running_high_prio = 1;
267 }
268 }
269
270 HAL_NVIC_SetPendingIRQ((IRQn_Type) RADIO_SW_LOW_INTR_NUM);
271 }
272 #endif
273
274 /**
275 * @brief Enable interrupts.
276 * @param None
277 * @retval None
278 */
LINKLAYER_PLAT_EnableIRQ(void)279 void LINKLAYER_PLAT_EnableIRQ(void)
280 {
281 irq_counter = max(0,irq_counter-1);
282
283 if(irq_counter == 0)
284 {
285 /* When irq_counter reaches 0, restore primask bit */
286 __set_PRIMASK(primask_bit);
287 }
288 }
289
290 /**
291 * @brief Disable interrupts.
292 * @param None
293 * @retval None
294 */
LINKLAYER_PLAT_DisableIRQ(void)295 void LINKLAYER_PLAT_DisableIRQ(void)
296 {
297 if(irq_counter == 0)
298 {
299 /* Save primask bit at first interrupt disablement */
300 primask_bit= __get_PRIMASK();
301 }
302 __disable_irq();
303 irq_counter ++;
304 }
305
306 #ifndef __ZEPHYR__
307 /**
308 * @brief Enable specific interrupt group.
309 * @param isr_type: mask for interrupt group to enable.
310 * This parameter can be one of the following:
311 * @arg LL_HIGH_ISR_ONLY: enable link layer high priority ISR.
312 * @arg LL_LOW_ISR_ONLY: enable link layer SW low priority ISR.
313 * @arg SYS_LOW_ISR: mask interrupts for all the other system ISR with
314 * lower priority that link layer SW low interrupt.
315 * @retval None
316 */
LINKLAYER_PLAT_EnableSpecificIRQ(uint8_t isr_type)317 void LINKLAYER_PLAT_EnableSpecificIRQ(uint8_t isr_type)
318 {
319 if( (isr_type & LL_HIGH_ISR_ONLY) != 0 )
320 {
321 prio_high_isr_counter--;
322 if(prio_high_isr_counter == 0)
323 {
324 /* When specific counter for link layer high ISR reaches 0, interrupt is enabled */
325 HAL_NVIC_EnableIRQ(RADIO_INTR_NUM);
326 /* USER CODE BEGIN LINKLAYER_PLAT_EnableSpecificIRQ_1 */
327
328 /* USER CODE END LINKLAYER_PLAT_EnableSpecificIRQ_1 */
329 }
330 }
331
332 if( (isr_type & LL_LOW_ISR_ONLY) != 0 )
333 {
334 prio_low_isr_counter--;
335 if(prio_low_isr_counter == 0)
336 {
337 /* When specific counter for link layer SW low ISR reaches 0, interrupt is enabled */
338 HAL_NVIC_EnableIRQ(RADIO_SW_LOW_INTR_NUM);
339 }
340
341 }
342
343 if( (isr_type & SYS_LOW_ISR) != 0 )
344 {
345 prio_sys_isr_counter--;
346 if(prio_sys_isr_counter == 0)
347 {
348 /* Restore basepri value */
349 __set_BASEPRI(local_basepri_value);
350 }
351 }
352 }
353
354 /**
355 * @brief Disable specific interrupt group.
356 * @param isr_type: mask for interrupt group to disable.
357 * This parameter can be one of the following:
358 * @arg LL_HIGH_ISR_ONLY: disable link layer high priority ISR.
359 * @arg LL_LOW_ISR_ONLY: disable link layer SW low priority ISR.
360 * @arg SYS_LOW_ISR: unmask interrupts for all the other system ISR with
361 * lower priority that link layer SW low interrupt.
362 * @retval None
363 */
LINKLAYER_PLAT_DisableSpecificIRQ(uint8_t isr_type)364 void LINKLAYER_PLAT_DisableSpecificIRQ(uint8_t isr_type)
365 {
366 if( (isr_type & LL_HIGH_ISR_ONLY) != 0 )
367 {
368 prio_high_isr_counter++;
369 if(prio_high_isr_counter == 1)
370 {
371 /* USER CODE BEGIN LINKLAYER_PLAT_DisableSpecificIRQ_1 */
372
373 /* USER CODE END LINKLAYER_PLAT_DisableSpecificIRQ_1 */
374 /* When specific counter for link layer high ISR value is 1, interrupt is disabled */
375 HAL_NVIC_DisableIRQ(RADIO_INTR_NUM);
376 }
377 }
378
379 if( (isr_type & LL_LOW_ISR_ONLY) != 0 )
380 {
381 prio_low_isr_counter++;
382 if(prio_low_isr_counter == 1)
383 {
384 /* When specific counter for link layer SW low ISR value is 1, interrupt is disabled */
385 HAL_NVIC_DisableIRQ(RADIO_SW_LOW_INTR_NUM);
386 }
387 }
388
389 if( (isr_type & SYS_LOW_ISR) != 0 )
390 {
391 prio_sys_isr_counter++;
392 if(prio_sys_isr_counter == 1)
393 {
394 /* Save basepri register value */
395 local_basepri_value = __get_BASEPRI();
396
397 /* Mask all other interrupts with lower priority that link layer SW low ISR */
398 __set_BASEPRI_MAX(RADIO_INTR_PRIO_LOW<<4);
399 }
400 }
401 }
402 #endif
403
404 /**
405 * @brief Enable link layer high priority ISR only.
406 * @param None
407 * @retval None
408 */
LINKLAYER_PLAT_EnableRadioIT(void)409 void LINKLAYER_PLAT_EnableRadioIT(void)
410 {
411 /* USER CODE BEGIN LINKLAYER_PLAT_EnableRadioIT_1 */
412
413 /* USER CODE END LINKLAYER_PLAT_EnableRadioIT_1 */
414
415 HAL_NVIC_EnableIRQ((IRQn_Type) RADIO_INTR_NUM);
416
417 /* USER CODE BEGIN LINKLAYER_PLAT_EnableRadioIT_2 */
418
419 /* USER CODE END LINKLAYER_PLAT_EnableRadioIT_2 */
420 }
421
422 /**
423 * @brief Disable link layer high priority ISR only.
424 * @param None
425 * @retval None
426 */
LINKLAYER_PLAT_DisableRadioIT(void)427 void LINKLAYER_PLAT_DisableRadioIT(void)
428 {
429 /* USER CODE BEGIN LINKLAYER_PLAT_DisableRadioIT_1 */
430
431 /* USER CODE END LINKLAYER_PLAT_DisableRadioIT_1 */
432
433 HAL_NVIC_DisableIRQ((IRQn_Type) RADIO_INTR_NUM);
434
435 /* USER CODE BEGIN LINKLAYER_PLAT_DisableRadioIT_2 */
436
437 /* USER CODE END LINKLAYER_PLAT_DisableRadioIT_2 */
438 }
439
440 #ifndef __ZEPHYR__
441 /**
442 * @brief Link Layer notification for radio activity start.
443 * @param None
444 * @retval None
445 */
LINKLAYER_PLAT_StartRadioEvt(void)446 void LINKLAYER_PLAT_StartRadioEvt(void)
447 {
448 __HAL_RCC_RADIO_CLK_SLEEP_ENABLE();
449 NVIC_SetPriority(RADIO_INTR_NUM, RADIO_INTR_PRIO_HIGH);
450 #if (CFG_SCM_SUPPORTED == 1)
451 scm_notifyradiostate(SCM_RADIO_ACTIVE);
452 #endif /* CFG_SCM_SUPPORTED */
453 }
454
455 /**
456 * @brief Link Layer notification for radio activity end.
457 * @param None
458 * @retval None
459 */
LINKLAYER_PLAT_StopRadioEvt(void)460 void LINKLAYER_PLAT_StopRadioEvt(void)
461 {
462 __HAL_RCC_RADIO_CLK_SLEEP_DISABLE();
463 NVIC_SetPriority(RADIO_INTR_NUM, RADIO_INTR_PRIO_LOW);
464 #if (CFG_SCM_SUPPORTED == 1)
465 scm_notifyradiostate(SCM_RADIO_NOT_ACTIVE);
466 #endif /* CFG_SCM_SUPPORTED */
467 }
468
469 /**
470 * @brief Link Layer notification for RCO calibration start.
471 * @param None
472 * @retval None
473 */
LINKLAYER_PLAT_RCOStartClbr(void)474 void LINKLAYER_PLAT_RCOStartClbr(void)
475 {
476 #if (CFG_SCM_SUPPORTED == 1)
477 #if (CFG_LPM_LEVEL != 0)
478 #if (CFG_LPM_STDBY_SUPPORTED == 1)
479 UTIL_LPM_SetOffMode(1U << CFG_LPM_LL_HW_RCO_CLBR, UTIL_LPM_DISABLE);
480 #endif /* (CFG_LPM_STDBY_SUPPORTED == 1) */
481 UTIL_LPM_SetStopMode(1U << CFG_LPM_LL_HW_RCO_CLBR, UTIL_LPM_DISABLE);
482 #endif /* (CFG_LPM_LEVEL != 0) */
483 scm_setsystemclock(SCM_USER_LL_HW_RCO_CLBR, HSE_32MHZ);
484 while (LL_PWR_IsActiveFlag_VOS() == 0);
485 #endif /* CFG_SCM_SUPPORTED */
486 }
487
488 /**
489 * @brief Link Layer notification for RCO calibration end.
490 * @param None
491 * @retval None
492 */
LINKLAYER_PLAT_RCOStopClbr(void)493 void LINKLAYER_PLAT_RCOStopClbr(void)
494 {
495 #if (CFG_SCM_SUPPORTED == 1)
496 #if (CFG_LPM_LEVEL != 0)
497 #if (CFG_LPM_STDBY_SUPPORTED == 1)
498 UTIL_LPM_SetOffMode(1U << CFG_LPM_LL_HW_RCO_CLBR, UTIL_LPM_ENABLE);
499 #endif /* (CFG_LPM_STDBY_SUPPORTED == 1) */
500 UTIL_LPM_SetStopMode(1U << CFG_LPM_LL_HW_RCO_CLBR, UTIL_LPM_ENABLE);
501 #endif /* (CFG_LPM_LEVEL != 0) */
502 scm_setsystemclock(SCM_USER_LL_HW_RCO_CLBR, HSE_16MHZ);
503 while (LL_PWR_IsActiveFlag_VOS() == 0);
504 #endif /* CFG_SCM_SUPPORTED */
505 }
506
507 /**
508 * @brief Link Layer requests temperature.
509 * @param None
510 * @retval None
511 */
LINKLAYER_PLAT_RequestTemperature(void)512 void LINKLAYER_PLAT_RequestTemperature(void)
513 {
514 #if (USE_TEMPERATURE_BASED_RADIO_CALIBRATION == 1)
515 ll_sys_bg_temperature_measurement();
516 #endif /* USE_TEMPERATURE_BASED_RADIO_CALIBRATION */
517 }
518
519 /**
520 * @brief Enable RTOS context switch.
521 * @param None
522 * @retval None
523 */
LINKLAYER_PLAT_EnableOSContextSwitch(void)524 void LINKLAYER_PLAT_EnableOSContextSwitch(void)
525 {
526 /* USER CODE BEGIN LINKLAYER_PLAT_EnableOSContextSwitch_0 */
527
528 /* USER CODE END LINKLAYER_PLAT_EnableOSContextSwitch_0 */
529 /* USER CODE BEGIN LINKLAYER_PLAT_EnableOSContextSwitch_1 */
530
531 /* USER CODE END LINKLAYER_PLAT_EnableOSContextSwitch_1 */
532 }
533
534 /**
535 * @brief Disable RTOS context switch.
536 * @param None
537 * @retval None
538 */
LINKLAYER_PLAT_DisableOSContextSwitch(void)539 void LINKLAYER_PLAT_DisableOSContextSwitch(void)
540 {
541 /* USER CODE BEGIN LINKLAYER_PLAT_DisableOSContextSwitch_0 */
542
543 /* USER CODE END LINKLAYER_PLAT_DisableOSContextSwitch_0 */
544 /* USER CODE BEGIN LINKLAYER_PLAT_DisableOSContextSwitch_1 */
545
546 /* USER CODE END LINKLAYER_PLAT_DisableOSContextSwitch_1 */
547 }
548
549 /**
550 * @brief Notify the upper layer that new Link Layer timings have been applied.
551 * @param evnt_timing[in]: Evnt_timing_t pointer to structure contains drift time , execution time and scheduling time
552 * @retval None.
553 */
LINKLAYER_PLAT_SCHLDR_TIMING_UPDATE_NOT(Evnt_timing_t * p_evnt_timing)554 void LINKLAYER_PLAT_SCHLDR_TIMING_UPDATE_NOT(Evnt_timing_t * p_evnt_timing)
555 {
556 /* USER CODE BEGIN LINKLAYER_PLAT_SCHLDR_TIMING_UPDATE_NOT_0 */
557
558 /* USER CODE END LINKLAYER_PLAT_SCHLDR_TIMING_UPDATE_NOT_0 */
559 }
560
561 /**
562 * @brief Get the ST company ID.
563 * @param None
564 * @retval Company ID
565 */
LINKLAYER_PLAT_GetSTCompanyID(void)566 uint32_t LINKLAYER_PLAT_GetSTCompanyID(void)
567 {
568 return LL_FLASH_GetSTCompanyID();
569 }
570
571 /**
572 * @brief Get the Unique Device Number (UDN).
573 * @param None
574 * @retval UDN
575 */
LINKLAYER_PLAT_GetUDN(void)576 uint32_t LINKLAYER_PLAT_GetUDN(void)
577 {
578 return LL_FLASH_GetUDN();
579 }
580 #endif
581 /* USER CODE BEGIN LINKLAYER_PLAT 0 */
582
583 /* USER CODE END LINKLAYER_PLAT 0 */
584