1. Introduction
This article explains how to remove the usage of LSE, 32.768 kHz low-speed external crystal, and replaces its functionality by using LSI2, 32 kHz low-speed low drift internal RC in an RF application. It also describes the modifications in the STM32CubeMX tool to build an RF application without using the external LSE and the use of LSI2 instead.
2. Overview
The low-speed clock is used as the real-time clock peripheral (RTC) for clock/calendar, the 2.4 GHz radio sleep timer, or other timing functions. The 2.4 GHz radio sleep timer kernel clock source can be either LSE, HSE32/1000, or LSI2. By default, LSE clock is used for its accuracy but bill of materials (BOM) can be reduced by removing LSE crystal and using the HSE32/1000 or LSI2 alternative instead. The drawback with the HSE32/1000 alternative is that low-power modes lower than SLEEP mode are not supported because the HSE is turned off when the system enters in deeper low power modes (STOP/STANDBY modes). LSI2 is supported since STM32CubeWBA[1] v1.6.0. This alternative reduces the BOM and performs low power as LSI2 keeps running in Stop and Standby modes like LSE. The only drawback is the increased power consumption compared to LSE.
The LSI2 clock drifts, especially in temperature, and must be calibrated regularly to remain compliant with RF specifications. For example, the low-speed clock frequency tolerance is ±500 ppm for Bluetooth® LE. The requirement for STM32WBA is to have less than 1 degree of variation between two calibrations to ensure compliance with the specifications. To ensure that this requirement is met, the LSI2 clock is calibrated every 1 s by default. The calibration is completely asynchronous to the radio activity.
The link layer must be notified of the low-speed clock source used to determine if RCO calibration is required. By default, in the STM32CubeWBA[1] package, this notification is done automatically with the 2.4 GHz radio sleep timer clock configured during initialization.
The calibration interval can be change using the following API:
ll_intf_cmn_le_set_rco_clbr_evnt_params(uint8_t rco_clbr_event_duration, uint32_t rco_clbr_event_interval);
With:
rco_clbr_event_duration: indicates the number of sleep clock cycles for performing the RCO calibration process. This value must be set to 24.
rco_clbr_event_interval: indicates the periodicity of running the runtime RCO calibration event. The value is expressed in ms.
This API can be called in the ll_sys_reset function for Bluetooth® LE applications and in the ll_sys_config_params function for others RF protocol applications.
The pros and cons for each low-speed clock alternative are the following:
Pros | Cons | |
---|---|---|
LSE |
|
|
LSI2 |
|
|
HSE32/1000 |
|
|
3. How to replace LSE usage by LSI2 in an existing project using STM32CubeMX
As mentioned above LSI2 is supported since STM32CubeWBA[1] v1.6.0, which implies using at least STM32CubeMX v6.14.0.
Note that examples in the STM32CubeWBA[1] firmware package are preconfigured to use the LSE for the 2.4 GHz radio sleep timer, SysTick and RTC. Any example can be used to demonstrate the changes that need to be made for this. In this case, the “BLE_p2pServer” example, found under “Projects\NUCLEO-WBA55CG\Applications\BLE\BLE_p2pServer”, is used to demonstrate how to do this.
3.1. Clock configuration
In the Clock configuration tab:
3.2. RCC configuration
4. Difference in the embedded software between LSE and LSI2 configuration
The following part will show the difference between LSE and LSI2 configuration in the embedded software. The software generated by the STM32CubeMX tool with the modifications described in the previous part corresponds to the software in the right boxes.
4.1. Low-speed clock initialization and SysTick clock source configuration
The low-speed clock initialization is performed in the SystemClock_Config function in the main.c file. The SysTick source clock is also configured in this function. In the LSI configuration, all parts related to the LSE clock have been removed (LSE drive configuration and LSE starts), and LSI has been set as SysTick clock source.
LSE configuration | LSI configuration |
---|---|
void SystemClock_Config(void)
{
# Beginning of the function hide as identical for both configurations
/** Configure LSE Drive Capability
*/
HAL_PWR_EnableBkUpAccess();
__HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_MEDIUMLOW);
/** Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI
|RCC_OSCILLATORTYPE_HSE
|RCC_OSCILLATORTYPE_LSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEDiv = RCC_HSE_DIV1;
RCC_OscInitStruct.LSEState = RCC_LSE_ON;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL1.PLLState = RCC_PLL_NONE;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
# Part of the function hide as identical for both configurations
/* Select SysTick source clock */
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_LSE);
|
void SystemClock_Config(void)
{
# Beginning of the function hide as identical for both configurations
/** Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI
|RCC_OSCILLATORTYPE_LSI
|RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEDiv = RCC_HSE_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.LSIState = RCC_LSI2_ON;
RCC_OscInitStruct.LSIDiv = RCC_LSI_DIV1;
RCC_OscInitStruct.PLL1.PLLState = RCC_PLL_NONE;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
# Part of the function hide as identical for both configurations
/* Select SysTick source clock */
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_LSI);
|
4.2. 2.4 GHz radio sleep timer clock source configuration
The 2.4 GHz radio sleep timer clock source is configured in the PeriphCommonClock_Config function in the main.c file:
LSE configuration | LSI configuration |
---|---|
void PeriphCommonClock_Config(void)
{
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
/** Initializes the peripherals clock
*/
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_RADIOST;
PeriphClkInit.RadioSlpTimClockSelection = RCC_RADIOSTCLKSOURCE_LSE;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
}
|
void PeriphCommonClock_Config(void)
{
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
/** Initializes the peripherals clock
*/
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_RADIOST;
PeriphClkInit.RadioSlpTimClockSelection = RCC_RADIOSTCLKSOURCE_LSI;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
}
|
4.3. RTC clock source configuration
The RTC clock source is configured in the HAL_RTC_MspInit function in the stm32wbaxx_hal_msp.c file:
LSE configuration | LSI configuration |
---|---|
void HAL_RTC_MspInit(RTC_HandleTypeDef* hrtc)
{
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
if(hrtc->Instance==RTC)
{
/* USER CODE BEGIN RTC_MspInit 0 */
/* USER CODE END RTC_MspInit 0 */
/** Initializes the peripherals clock
*/
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_RTC;
PeriphClkInit.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;
|
void HAL_RTC_MspInit(RTC_HandleTypeDef* hrtc)
{
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
if(hrtc->Instance==RTC)
{
/* USER CODE BEGIN RTC_MspInit 0 */
/* USER CODE END RTC_MspInit 0 */
/** Initializes the peripherals clock
*/
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_RTC;
PeriphClkInit.RTCClockSelection = RCC_RTCCLKSOURCE_LSI;
|
4.4. SysTick clock source configuration when exiting standby
The SysTick clock source when exiting standby is configured in the MX_StandbyExit_PeripheralInit function in the peripheral_init.c file:
LSE configuration | LSI configuration |
---|---|
void MX_StandbyExit_PeripheralInit(void)
{
HAL_StatusTypeDef hal_status;
/* USER CODE BEGIN MX_STANDBY_EXIT_PERIPHERAL_INIT_1 */
/* USER CODE END MX_STANDBY_EXIT_PERIPHERAL_INIT_1 */
/* Select SysTick source clock */
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_LSE);
|
void MX_StandbyExit_PeripheralInit(void)
{
HAL_StatusTypeDef hal_status;
/* USER CODE BEGIN MX_STANDBY_EXIT_PERIPHERAL_INIT_1 */
/* USER CODE END MX_STANDBY_EXIT_PERIPHERAL_INIT_1 */
/* Select SysTick source clock */
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_LSI);
|
5. References