使用STM32WL V1.3.0的LoRaWAN_End_Node_FreeRTOS,stm32wle5cc芯片,发现运行几天后大概率出现systick周期由1ms变为4us的问题,导致freertos任务无法正常运行。
从debug信息中发现STK_LOAD寄存器被修改为很小的值,每次出问题的位置都是在lorawan发送一帧数据的过程中,MAC txDone到MAC rxTimeOut之间。
Debug info:
[2023-08-06 22:22:51-023] 01:01:01:01:01:01:01:01
DevAddr: 01:84:17:D3
g_systick_reg_per:6 2b828e 2b7d7f 400003e8
g_systick_reg_post:7 bb80 bb4b 400003e8 (ß The normal register value regs:1.STK_CTRL 2.STK_LOAD 3.STK_VAL 4.STK_CALIB)
-------------test1 TickCount:281704498--------------
-------------free heap:18328 12072--------------
g_systick_test:220752 tim17_test:201719
name state priority stack num
test_task_creat X 11 126 6
IDLE R 0 81 2
Tmr Svc B 2 223 3
monitor_loop B 6 168 5
sensor_loop B 10 790 4
lm_handler_proc B 8 232 7
lorawan_process
[2023-08-06 22:22:51-123] B 7 22 8
[2023-08-06 22:22:52-441] OnMacProcessNotify pre
OnMacProcessNotify:1
282161s607:MAC txDone
----------start lm_handler_process TickCount:281704881-------------- (LmHandlerProcess() Semaphore received)
----------end lm_handler_process TickCount:281704883-------------- (LmHandlerProcess() Wait semaphore enter sleep)
[2023-08-06 22:22:53-493] 282162s601:RX_1 on freq 922600000 Hz at DR 2 (First receive window)
282162s667:IRQ_RX_TX_TIMEOUT
OnMacProcessNotify pre
OnMacProcessNotify:1
282162s667:MAC rxTimeOut
[2023-08-06 22:23:01-934] delay_handle g_lorawan_state:8 (is RTC timer)
(The freertos cannot run)
[2023-08-07 10:06:39-378] EXTI9_5_IRQHandler () (Use an external interrupt to trigger a print reg info)
[2023-08-07 10:06:44-787] HAL_GPIO_EXTI_Callback:256
g_systick_reg_per:6 fee74e fee22c 400003e8
g_systick_reg_post:10007 2c 24 400003e8 (ß The register value of the exception regs:1.STK_CTRL 2.STK_LOAD 3.STK_VAL 4.STK_CALIB)
-------------test1 TickCount:281704899--------------
-------------free heap:18328 12072--------------
休眠唤醒相关代码:
void PreSleepProcessing(uint32_t *ulExpectedIdleTime)
{
/* Called by the kernel before it places the MCU into a sleep mode because
configPRE_SLEEP_PROCESSING() is #defined to PreSleepProcessing().
NOTE: Additional actions can be taken here to get the power consumption
even lower. For example, peripherals can be turned off here, and then back
on again in the post sleep processing function. For maximum power saving
ensure all unused pins are in their lowest power state. */
uint32_t WakeUpTimer_timeOut_ms = app_freertos_tick_to_ms(*ulExpectedIdleTime);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
UTIL_TIMER_SetPeriod(&WakeUpTimer, WakeUpTimer_timeOut_ms);
UTIL_TIMER_Start(&WakeUpTimer);
Time_BeforeSleep = UTIL_TIMER_GetCurrentTime();
/Stop the systick here so that it stops even in sleep mode/
portNVIC_SYSTICK_CTRL_REG &= ~portNVIC_SYSTICK_ENABLE_BIT;
HAL_TIM_Base_Stop_IT(&htim17);
g_systick_reg_pre[0] = portNVIC_SYSTICK_CTRL_REG;
g_systick_reg_pre[1] = portNVIC_SYSTICK_LOAD_REG;
g_systick_reg_pre[2] = portNVIC_SYSTICK_CURRENT_VALUE_REG;
g_systick_reg_pre[3] = portNVIC_SYSTICK_STK_CALIB_REG;
UTIL_LPM_EnterLowPower();
/*
(*ulExpectedIdleTime) is set to 0 to indicate that PreSleepProcessing contains
its own wait for interrupt or wait for event instruction and so the kernel vPortSuppressTicksAndSleep
function does not need to execute the wfi instruction
*/
*ulExpectedIdleTime = 0;
}
void PostSleepProcessing(uint32_t *ulExpectedIdleTime)
{
/* Called by the kernel when the MCU exits a sleep mode because
configPOST_SLEEP_PROCESSING is #defined to PostSleepProcessing(). */
uint32_t SleepDuration = UTIL_TIMER_GetElapsedTime(Time_BeforeSleep);
/ Avoid compiler warnings about the unused parameter. /
UNUSED(ulExpectedIdleTime);
UTIL_TIMER_Stop(&WakeUpTimer);
/ Set the new reload value. /
if (portNVIC_SYSTICK_CURRENT_VALUE_REG > (SleepDuration * CORE_TICK_RATE))
{
/what remains to sleep/
portNVIC_SYSTICK_LOAD_REG = portNVIC_SYSTICK_CURRENT_VALUE_REG - (app_freertos_ms_to_tick(SleepDuration) * CORE_TICK_RATE);
}
else
{
portNVIC_SYSTICK_LOAD_REG = CORE_TICK_RATE;
}
/ Clear the SysTick count flag and set the count value back to zero. /
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
/ Restart SysTick. /
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
HAL_TIM_Base_Start_IT(&htim17);
g_systick_reg_post[0] = portNVIC_SYSTICK_CTRL_REG;
g_systick_reg_post[1] = portNVIC_SYSTICK_LOAD_REG;
g_systick_reg_post[2] = portNVIC_SYSTICK_CURRENT_VALUE_REG;
g_systick_reg_post[3] = portNVIC_SYSTICK_STK_CALIB_REG;
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
}
用户数据发送部分代码:
void tcs_lorawan_send(int max_temp, int min_temp)
{
LmHandlerErrorStatus_t status = LORAMAC_HANDLER_ERROR;
UTIL_TIMER_Time_t nextTxIn = 0;
static uint16_t sn = 0;
float temp;
if (g_is_connect) {
uint8_t len = 0;
static uint16_t battery = 0xFFFF;
static uint16_t batt_tmp;
batt_tmp = SYS_GetBatteryLevel();
if (batt_tmp < battery) {
battery = batt_tmp;
}
max_temp -= 2731;
min_temp -= 2731;
max_temp += MAX_TEMP_OFFSET;
min_temp += MIN_TEMP_OFFSET;
temp = objectTemperatureByDistance((float)max_temp / 10, (float)CONFIG.distance_corr / 100);
max_temp = temp * 100;
min_temp *= 10;
APP_LOG(TS_ON, VLEVEL_M, "VDDA: %dmv\r\n", battery);
APP_LOG(TS_ON, VLEVEL_M, "max_temp:%d min_temp:%d\r\n", max_temp, min_temp);
if (((max_temp > TEMP_MAX_ERR) || (max_temp < TEMP_MIN_ERR)) ||
((min_temp > TEMP_MAX_ERR) || (min_temp < TEMP_MIN_ERR))) {
UTIL_TIMER_StartWithPeriod(&g_delay_timer, SEND_INTERVAL * 1000);
g_lorawan_state = LORAWAN_STATE_SEND_RETRY;
return;
}
AppData.Port = LORAWAN_USER_APP_PORT;
/ head /
AppData.Buffer[len++] = 0xAA;
if 1
/ len (Skip Length) /
len++;
/ serial number /
AppData.Buffer[len++] = (uint8_t)sn & 0xFF;
AppData.Buffer[len++] = (uint8_t)((sn >> 8) & 0xFF);
sn++;
/ dev_t /
AppData.Buffer[len++] = (uint8_t)PROTOCOL_DEV_TYPE & 0xff;
AppData.Buffer[len++] = (uint8_t)((PROTOCOL_DEV_TYPE >> 8) & 0xff);
/ key (ignore)/
AppData.Buffer[len++] = 0x00;
AppData.Buffer[len++] = 0x00;
AppData.Buffer[len++] = 0x00;
/ data /
AppData.Buffer[len++] = (uint8_t)(battery & 0xFF);
AppData.Buffer[len++] = (uint8_t)((battery >> 8) & 0xFF);
AppData.Buffer[len++] = (uint8_t)(max_temp & 0xFF);
AppData.Buffer[len++] = (uint8_t)((max_temp >> 8) & 0xFF);
AppData.Buffer[len++] = (uint8_t)(min_temp & 0xFF);
AppData.Buffer[len++] = (uint8_t)((min_temp >> 8) & 0xFF);
AppData.Buffer[len++] = (uint8_t)(CONFIG.distance_corr & 0xFF);
AppData.Buffer[len++] = (uint8_t)((CONFIG.distance_corr
& 0xFF);
AppData.Buffer[len++] = CONFIG.emissivity;
AppData.Buffer[len++] = CONFIG.max_temp_limit;
AppData.Buffer[len++] = CONFIG.min_temp_limit;
/ set len /
AppData.Buffer[1] = len;
/ set checksum /
AppData.Buffer[len++] = get_checkSum(AppData.Buffer, len);
endif
AppData.BufferSize = len;
status = LmHandlerSend(&AppData, LmHandlerParams.IsTxConfirmed, false);
if (LORAMAC_HANDLER_SUCCESS == status) {
APP_LOG(TS_ON, VLEVEL_L, "SEND REQUEST\r\n");
} else if (LORAMAC_HANDLER_DUTYCYCLE_RESTRICTED == status) {
nextTxIn = LmHandlerGetDutyCycleWaitTime();
if (nextTxIn > 0) {
APP_PRINTF("Next Tx in : ~%d second(s)\n", (nextTxIn / 1000));
}
}
}
UTIL_TIMER_StartWithPeriod(&g_delay_timer, MAX(nextTxIn, SEND_INTERVAL * 1000));
} |