本以为上次调试就是终点,实在没想到。在做最终测试时发现节点无法进入低功耗模式,因为Debug模式与低功耗模式是互锁的,所以没有发现这个问题。
先说说现象,强制打开串口打印观察节点,发现原来是节点进入STM32自带的停止模式后无法唤醒。
void RtcEnterLowPowerStopMode( void ) { if( ( LowPowerDisableDuringTask == false ) && ( RtcTimerEventAllowsLowPower == true ) ) { BoardDeInitMcu( ); // Disable the Power Voltage Detector HAL_PWR_DisablePVD( ); //#warning "Commented for debug!" SET_BIT( PWR->CR, PWR_CR_CWUF ); // Enable Ultra low power mode HAL_PWREx_EnableUltraLowPower( ); // Enable the fast wake up from Ultra low power mode HAL_PWREx_EnableFastWakeUp( ); // Enter Stop Mode HAL_PWR_EnterSTOPMode( PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI ); } }
开始设想是晶振问题,检查低功耗唤醒的重复初始化函数,发现源代码只有HSI晶振复位等待,于是添加了HSE部分复位等待。发现节点开始唤醒了。
void SystemClockReConfig( void ) { __HAL_RCC_PWR_CLK_ENABLE( ); __HAL_PWR_VOLTAGESCALING_CONFIG( PWR_REGULATOR_VOLTAGE_SCALE1 ); /* Enable HSI */ __HAL_RCC_HSI_ENABLE(); __HAL_RCC_HSI_CALIBRATIONVALUE_ADJUST(RCC_HSICALIBRATION_DEFAULT); //__HAL_RCC_HSI_CALIBRATIONVALUE_ADJUST((uint32_t)((RCC->ICSCR & RCC_ICSCR_HSITRIM) >> POSITION_VAL(RCC_ICSCR_HSITRIM))); /* Wait till HSI is ready */ while( __HAL_RCC_GET_FLAG( RCC_FLAG_HSIRDY ) == RESET ) { } #if !defined( USE_DEBUGGER ) || defined( USB_VCP ) __HAL_RCC_HSE_CONFIG(RCC_HSE_ON); /* Enable PLL */ __HAL_RCC_PLL_ENABLE( ); /* Wait till HSE is ready */ while( __HAL_RCC_GET_FLAG( RCC_FLAG_HSERDY ) == RESET ) { } /* Wait till PLL is ready */ while( __HAL_RCC_GET_FLAG( RCC_FLAG_PLLRDY ) == RESET ) { } /* Select PLL as system clock source */ __HAL_RCC_SYSCLK_CONFIG ( RCC_SYSCLKSOURCE_HSI ); /* Wait till PLL is used as system clock source */ while( __HAL_RCC_GET_SYSCLK_SOURCE( ) != RCC_SYSCLKSOURCE_STATUS_HSI ) { } /*HSI->SYS*/ #elif defined( USE_DEBUGGER ) && !defined( USB_VCP ) __HAL_RCC_PLL_ENABLE( ); /* Wait till PLL is ready */ while( __HAL_RCC_GET_FLAG( RCC_FLAG_PLLRDY ) == RESET ) { } /* Select PLL as system clock source */ __HAL_RCC_SYSCLK_CONFIG ( RCC_SYSCLKSOURCE_PLLCLK ); /* Wait till PLL is used as system clock source */ while( __HAL_RCC_GET_SYSCLK_SOURCE( ) != RCC_SYSCLKSOURCE_STATUS_PLLCLK ) { } /*PLL->SYS*/ #endif }
但是却发生了节点的接收窗口与网关的下发窗口对不上的问题。
大家分析认为可能是VCP需要用到的外部高速晶振HSE的启动需要一定的时间,导致在错过了接收窗口时间,所以我们改用了HSI提供给SYS时钟源,HSE只单独提供给PLL来作为USB的时钟源。
#elif !defined( USE_DEBUGGER ) RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; RCC_PeriphCLKInitTypeDef PeriphClkInit = {0}; /** Configure the main internal regulator output voltage */ __HAL_RCC_PWR_CLK_ENABLE( ); __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); /** 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.LSEState = RCC_LSE_ON; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL12; RCC_OscInitStruct.PLL.PLLDIV = RCC_PLL_DIV3; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB busses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK) { Error_Handler(); } PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_RTC; PeriphClkInit.RTCClockSelection = RCC_RTCCLKSOURCE_LSE; if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) { Error_Handler(); }
但是问题并没有被解决,后来在张老师的帮助下在系统初始化函数中的用于验证链表的时间校准函数中添加了一个低功耗处理函数,收发窗口就对上了。
后来实测HSE->PLL->SYS 也可以用于低功耗模式,只是在系统时间上我们更倾向于复位更快速的STM32内部时钟,所以依然保留HSI->SYS的设置。
但是问题又来了,节点不时会出现入网成功后卡死的问题(可能是哪里又进入了低功耗,但不好发现),依旧是在张老师的帮助下,发现是收发过程中的系统校准函数没有按想像的运行。不知道是否是晶振配置影响了它。
// Trig OnMacCheckTimerEvent call as soon as possible OnMacStateCheckTimerEvent(); // TimerSetValue( &MacStateCheckTimer, 1 ); // TimerStart( &MacStateCheckTimer );
于是注释了以链表的形式,改用直接执行的方式来运行这个函数。卡死的问题也得到了解决。
实测低功耗模式下节点睡眠电流仅2uA,
至此关于VCP调试的所有阶段才正式结束。