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