2024-12-20 05:17 AM - edited 2024-12-20 05:26 AM
hello every one
I'm working on a STM32WB35 custom board with full ble stack
what could cause C0 rf controler to stops advertising when going in stop2 mode?
to get focused on my bug I've build a simple app that use tiny LPM as ble_heartbeat example
except that I dont have any advertising frequency change I have no custom app
test purpose is to init ble stack start advertising and then go to stop 2 mode and advertise like this for ever
I'm allowing stop2 mode as soon as we finished APP_BLE_Init() function
BleApplicationContext.BleApplicationContext_legacy.advtServUUID[0] = NULL;
BleApplicationContext.BleApplicationContext_legacy.advtServUUIDlen = 0;
/**
* Start to Advertise to be connected by a Client
*/
Adv_Request(APP_BLE_FAST_ADV);
/* USER CODE BEGIN APP_BLE_Init_2 */
UTIL_LPM_SetStopMode(1 << CFG_LPM_APP_BLE, UTIL_LPM_ENABLE);
//DUMMYTSK_Init();
/* USER CODE END APP_BLE_Init_2 */
return;
}
Enter and Exit LowPower functions are sames as BLE_heartbeat exemple
static void EnterLowPower(void)
{
/**
* This function is called from CRITICAL SECTION
*/
while(LL_HSEM_1StepLock(HSEM, CFG_HW_RCC_SEMID));
if (! LL_HSEM_1StepLock(HSEM, CFG_HW_ENTRY_STOP_MODE_SEMID))
{
if(LL_PWR_IsActiveFlag_C2DS() || LL_PWR_IsActiveFlag_C2SB())
{
/* Release ENTRY_STOP_MODE semaphore */
LL_HSEM_ReleaseLock(HSEM, CFG_HW_ENTRY_STOP_MODE_SEMID, 0);
Switch_On_HSI();
__HAL_FLASH_SET_LATENCY(FLASH_LATENCY_0);
}
}
else
{
Switch_On_HSI();
__HAL_FLASH_SET_LATENCY(FLASH_LATENCY_0);
}
/* Release RCC semaphore */
LL_HSEM_ReleaseLock(HSEM, CFG_HW_RCC_SEMID, 0);
return;
}
/**
* @brief Restore the system to exit stop mode
* none
* @retval none
*/
static void ExitLowPower(void)
{
/* Release ENTRY_STOP_MODE semaphore */
LL_HSEM_ReleaseLock(HSEM, CFG_HW_ENTRY_STOP_MODE_SEMID, 0);
while(LL_HSEM_1StepLock(HSEM, CFG_HW_RCC_SEMID));
if(LL_RCC_GetSysClkSource() == LL_RCC_SYS_CLKSOURCE_STATUS_HSI)
{
/* Restore the clock configuration of the application in this user section */
/* USER CODE BEGIN ExitLowPower_1 */
Switch_On_HSE();
/* USER CODE END ExitLowPower_1 */
}
else
{
/* If the application is not running on HSE restore the clock configuration in this user section */
/* USER CODE BEGIN ExitLowPower_2 */
/* USER CODE END ExitLowPower_2 */
}
/* Release RCC semaphore */
LL_HSEM_ReleaseLock(HSEM, CFG_HW_RCC_SEMID, 0);
return;
}
/**
* @brief Switch the system clock on HSI
* none
* @retval none
*/
static void Switch_On_HSI(void)
{
LL_RCC_HSI_Enable();
while(!LL_RCC_HSI_IsReady());
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSI);
LL_RCC_SetSMPSClockSource(LL_RCC_SMPS_CLKSOURCE_HSI);
while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSI);
return;
}
/* USER CODE BEGIN Private_Functions */
void Switch_On_HSE(void)
{
LL_RCC_HSE_Enable();
__HAL_FLASH_SET_LATENCY(FLASH_LATENCY_1);
while(__HAL_FLASH_GET_LATENCY() != FLASH_LATENCY_1);
while(!LL_RCC_HSE_IsReady());
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSE);
while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSE);
return;
}
the only difference is that I have added an LPM ID bit to be able to have trace even if LPM is enable
/******************************************************************************
* LOW POWER
******************************************************************************/
/**
* Supported requester to the MCU Low Power Manager - can be increased up to 32
* It list a bit mapping of all user of the Low Power Manager
*/
typedef enum
{
CFG_LPM_APP,
CFG_LPM_APP_BLE,
/* USER CODE BEGIN CFG_LPM_Id_t */
CFG_LPM_DBG_TRACE,
/* USER CODE END CFG_LPM_Id_t */
} CFG_LPM_Id_t;
I have modified the app_conf.h to get the LPM and TRACE at same time
#ifdef _DEBUG_
#define CFG_LPM_SUPPORTED 1
#define CFG_DEBUGGER_SUPPORTED 1
#else
#define CFG_LPM_SUPPORTED 1
#define CFG_DEBUGGER_SUPPORTED 0
#endif
/**
* When CFG_DEBUG_TRACE_FULL is set to 1, the trace are output with the API name, the file name and the line number
* When CFG_DEBUG_TRACE_LIGHT is set to 1, only the debug message is output
*
* When both are set to 0, no trace are output
* When both are set to 1, CFG_DEBUG_TRACE_FULL is selected
*/
#define CFG_DEBUG_TRACE_LIGHT 0
#define CFG_DEBUG_TRACE_FULL 1
the dbg_trace.c functions have been modified accordingly
static void DbgTrace_TxCpltCallback(void)
{
#if (DBG_TRACE_USE_CIRCULAR_QUEUE != 0)
uint8_t* buf;
uint16_t bufSize;
BACKUP_PRIMASK();
DISABLE_IRQ(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/
/* Remove element just sent to UART */
CircularQueue_Remove(&MsgDbgTraceQueue,&bufSize);
/* Sense if new data to be sent */
buf=CircularQueue_Sense(&MsgDbgTraceQueue,&bufSize);
if ( buf != NULL)
{
RESTORE_PRIMASK();
DbgOutputTraces((uint8_t*)buf, bufSize, DbgTrace_TxCpltCallback);
}
else
{
DbgTracePeripheralReady = SET;
RESTORE_PRIMASK();
}
#else
BACKUP_PRIMASK();
DISABLE_IRQ(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/
DbgTracePeripheralReady = SET;
RESTORE_PRIMASK();
#endif
if(DbgTracePeripheralReady==SET) UTIL_LPM_SetStopMode(1 << CFG_LPM_DBG_TRACE, UTIL_LPM_ENABLE);
}
#endif
size_t DbgTraceWrite(int handle, const unsigned char * buf, size_t bufSize)
{
size_t chars_written = 0;
uint8_t* buffer;
BACKUP_PRIMASK();
/* Ignore flushes */
if ( handle == -1 )
{
chars_written = ( size_t ) 0;
}
/* Only allow stdout/stderr output */
else if ( ( handle != 1 ) && ( handle != 2 ) )
{
chars_written = ( size_t ) - 1;
}
/* Parameters OK, call the low-level character output routine */
else if (bufSize != 0)
{
chars_written = bufSize;
/* If queue emepty and TX free, send directly */
/* CS Start */
#if (DBG_TRACE_USE_CIRCULAR_QUEUE != 0)
DISABLE_IRQ(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/
buffer=CircularQueue_Add(&MsgDbgTraceQueue,(uint8_t*)buf, bufSize,1);
if (buffer && DbgTracePeripheralReady)
{
DbgTracePeripheralReady = RESET;
RESTORE_PRIMASK();
DbgOutputTraces((uint8_t*)buffer, bufSize, DbgTrace_TxCpltCallback);
}
else
{
RESTORE_PRIMASK();
}
#else
DISABLE_IRQ(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/
DbgTracePeripheralReady = RESET;
RESTORE_PRIMASK();
DbgOutputTraces((uint8_t*)buf, bufSize, DbgTrace_TxCpltCallback);
while (!DbgTracePeripheralReady);
#endif
if(DbgTracePeripheralReady==RESET) UTIL_LPM_SetStopMode(1 << CFG_LPM_DBG_TRACE, UTIL_LPM_DISABLE);
/* CS END */
}
return ( chars_written );
}
theses are all the differences from a totally fresh design generated by cube mx
and it works almost flawlessly
after the init and all prints finished main core is going to stop2 mode and is waked @ each adv frames
but some times the C0 stops sending adv and stops awaking main core
I've tested on different board on some of them it appends after 30 mins or 1h on some other about 3 or 4 wake-up from stop2 cycle and most of time it appends direct after first stop2 mode switch
I have test with adding a periodic task that read C0 HW fault registers @SRAM2A
uint32_t* p=SRAM2A_BASE;
printf("C2 HW %08lX\n",*p);
printf("C2 PC %08lX\n",*(p+4));
printf("C2 LR %08lX\n",*(p+8));
printf("C2 SP %08lX\n",*(p+12));
and it shows no issue of hard fault
I have also few HCI_HARDWARE_EVT_CODE that pops from time to time that I don't know how to avoid
[tl_mbox.c][OutputDbgTrace][758] ble evt: 0x10
[tl_mbox.c][OutputDbgTrace][761] payload: 01
[tl_mbox.c][OutputDbgTrace][776]
[app_ble.c][SVCCTL_App_Notification][476] >>== HCI_HARDWARE_ERROR_EVT_CODE
[app_ble.c][SVCCTL_App_Notification][477] Hardware Code = 0x01
I've try on a P-nucleoWB55 board and It didn't falls into any of theses tow bugs
any idea will be greatly appreciated
thanks for reading until here