STM32F429(ucosIII)-低功耗停止模式下系列问题记录
1. 需解决的目标:
a. 将手持设备在不使用的情况下从200ma降低到40ma左右,从而提高手持设备的使用时长,超过24小时
2. 实现方式
a.查看stm32的电气手册,看在最大的168M主频下能达到多小的理论电流(详细见文章最底下),并进行实验。
b.通过ucosiii起一个任务进行设备状态的监测,当监测到设备出现熄屏的状态,进入低功耗模式-停止模式,降低使用功耗。
c.进入低功耗前关闭ADC(用的AD1),唤醒后初始化ADC,大概节省了3MA左右.
d.其他的GPIO优化,这个优化之后发现,基本没什么变化。存疑:这个可能对于MA级别的。
3. 调试验证的方式
a.如何知道进入了停止模式:
进入debug模式下
查看PWR的标志位状态,如下两图已进入停止模式
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200717162850924.png#pic_center)
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200717162916801.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xzaDEzNzI2Mjk2NTg3,size_16,color_FFFFFF,t_70#pic_center)
查看调试断点如下跑到函数
PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI);
的下面,如果跑到下面说明被唤醒了。如果没有基本说明MCU处于停止模式。需要注意的是需要添加以下函数进行调试,否则有时会出现调试过程断开的现象。DBGMCU_Config(DBGMCU_STOP,ENABLE);
b.低功耗模式-停止模式-TFT(ILI9341)唤醒
可以通过23个EXTI的外部中断进行唤醒,我使用4个外部的按键GPIO,并配置成外部中断进行处理
***注意: 要进入停止模式,所有 EXTI 线挂起位(在挂起寄存器 (EXTI_PR)
中)、 RTC 闹钟(闹钟 A 和闹钟 B)、 RTC 唤醒、 RTC 入侵和 RTC 时间
戳标志必须复位。否则将忽略进入停止模式这一过程,继续执行程序。(来自于手册)***
4. 代码
(1)ucosIII起一个任务进行守护,未标明的均用的STM库的函数
/*
********************************************************************************
* @function : static void AppTaskLowPower(void *p_arg)
* @brief : 低功耗模式
* @param : p_arg 是在创建该任务时传递的形参
* @return : 0
********************************************************************************
*/
static void AppTaskUserLowPower(void *p_arg){
(void)p_arg;
OS_ERR p_err;
OS_ERR err;
while(1){
//KEY_DEBUG(getDebugLever(), DBG_WARN, "AppTaskUserLowPower线程");
if(LcdOffFlag == 1 && getComStatus() == FALSE ){
OSSchedLock(&p_err);//禁止任务调度
//关闭滴答计数器
SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;
RTC_AlarmCmd(RTC_Alarm_A,DISABLE);
RTC_AlarmCmd(RTC_Alarm_B,DISABLE);
RTC_WakeUpCmd(DISABLE);
RTC_TimeStampCmd(RTC_TimeStampEdge_Rising,DISABLE);
RTC_TimeStampCmd(RTC_TimeStampEdge_Falling,DISABLE);
RTC_TamperCmd(RTC_Tamper_1,DISABLE);
//关闭ADC,和DAC
ADC_Cmd(ELE_QUANTITY_ADC, DISABLE);
//控制FLASH是进入掉电状态还是正常供电状态
PWR_FlashPowerDownCmd(ENABLE);
LCD_SLEEP_Mode(TRUE);//ILI9341进入睡眠模式
//进入低功耗停止模式
PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI);
//重新初始化系统时钟及GPIO
SystemInit();
SystemCoreClockUpdate(); //根据PLL配置更新系统时钟频率变量 SystemCoreClock
LcdOffFlag = 0;
TFTLCD_Init_after_stop(); //初始化LCD
TIM_SetTIM3Compare4(systemParam[backlightLevel].value); //背光占空比调节
ADC_Cmd(ELE_QUANTITY_ADC, ENABLE);
BSP_Tick_Init(); //初始化系统滴答时钟做为uCOS-II的系统时钟节拍,1ms一次
bsp_DelayUS(200000); //Delay 200ms
OSSchedUnlock(&p_err);//允许任务调度
}
OSTimeDly(500, OS_OPT_TIME_DLY, &err);
}
}
(2)外设TFT屏驱动芯片ILI9341进入睡眠模式。
void LCD_SLEEP_Mode(BOOLEAN state){
if(state){
LCD_WriteCommand(LCD_SLEEP_IN);
delay_ms(20);
LCD_WriteCommand(LCD_DISPLAY_OFF);
}
else{
LCD_WriteCommand(LCD_SLEEP_OUT);
delay_ms(120);
LCD_WriteCommand(LCD_DISPLAY_ON);
}
}
(3)外设TFT屏驱动芯片ILI9341退出睡眠模式
/**
* @brief Initializes the LCD after stop.
* @param None
* @retval None
*/
void TFTLCD_Init_after_stop(void)
{
LTDC_InitTypeDef LTDC_InitStruct;
LCD_SLEEP_Mode(FALSE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_LTDC, ENABLE); /* Enable the LTDC Clock */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2D, ENABLE); /* Enable the DMA2D Clock */
LCD_GPIO_Config(); /* Configure the LCD Control pins */
g_LcdHeight = LCD_PIXEL_HEIGHT;
g_LcdWidth = LCD_PIXEL_WIDTH;
HSYNC_W = LCD_HSW;
VSYNC_W = LCD_VSW;
HBP = LCD_HBP;
HFP = LCD_HFP;
VBP = LCD_VBP;
VFP = LCD_VFP;
//LTDC配置
LTDC_InitStruct.LTDC_HSPolarity = LTDC_HSPolarity_AL; //水平同步极性
LTDC_InitStruct.LTDC_VSPolarity = LTDC_VSPolarity_AL; //垂直同步极性
LTDC_InitStruct.LTDC_DEPolarity = LTDC_DEPolarity_AL; //数据使能极性
LTDC_InitStruct.LTDC_PCPolarity = LTDC_PCPolarity_IPC; //像素时钟极性
#if 0
LTDC_InitStruct.LTDC_HorizontalSync = HSYNC_W - 1; //水平同步宽度
LTDC_InitStruct.LTDC_VerticalSync = VSYNC_W - 1; //垂直同步宽度
LTDC_InitStruct.LTDC_AccumulatedHBP = HSYNC_W + HBP - 1; //水平同步后沿宽度
LTDC_InitStruct.LTDC_AccumulatedVBP = VSYNC_W + VBP - 1; //垂直同步后沿高度
LTDC_InitStruct.LTDC_AccumulatedActiveW = HSYNC_W + HBP + g_LcdWidth - 1; //有效宽度
LTDC_InitStruct.LTDC_AccumulatedActiveH = VSYNC_W + VBP + g_LcdHeight - 1; //有效高度
LTDC_InitStruct.LTDC_TotalWidth = HSYNC_W + HBP + LCD_PIXEL_WIDTH + HFP - 1; //总宽度
LTDC_InitStruct.LTDC_TotalHeigh = VSYNC_W + VBP + LCD_PIXEL_HEIGHT + VFP - 1; //总高度
LTDC_InitStruct.LTDC_BackgroundRedValue = 0; //屏幕背景层红色部分
LTDC_InitStruct.LTDC_BackgroundGreenValue = 0; //屏幕背景层绿色部分
LTDC_InitStruct.LTDC_BackgroundBlueValue = 0; //屏幕背景色蓝色部分
#else
LTDC_InitStruct.LTDC_HorizontalSync = HSYNC_W;
LTDC_InitStruct.LTDC_VerticalSync = VSYNC_W;
LTDC_InitStruct.LTDC_AccumulatedHBP = LTDC_InitStruct.LTDC_HorizontalSync + HBP;
LTDC_InitStruct.LTDC_AccumulatedVBP = LTDC_InitStruct.LTDC_VerticalSync + VBP;
LTDC_InitStruct.LTDC_AccumulatedActiveW = g_LcdWidth + LTDC_InitStruct.LTDC_AccumulatedHBP;
LTDC_InitStruct.LTDC_AccumulatedActiveH = g_LcdHeight + LTDC_InitStruct.LTDC_AccumulatedVBP;
LTDC_InitStruct.LTDC_TotalWidth = LTDC_InitStruct.LTDC_AccumulatedActiveW + HFP;
LTDC_InitStruct.LTDC_TotalHeigh = LTDC_InitStruct.LTDC_AccumulatedActiveH + VFP;
/* 背景色 */
LTDC_InitStruct.LTDC_BackgroundRedValue = 0xff;
LTDC_InitStruct.LTDC_BackgroundGreenValue = 0;
LTDC_InitStruct.LTDC_BackgroundBlueValue = 0;
#endif
/* 配置 PLLSAI 分频器,它的输出作为像素同步时钟CLK*/
/* PLLSAI_VCO 输入时钟 = HSE_VALUE/PLL_M = 1 Mhz */
/* PLLSAI_VCO 输出时钟 = PLLSAI_VCO输入 * PLLSAI_N = 384 Mhz */
/* PLLLCDCLK = PLLSAI_VCO 输出/PLLSAI_R = 384/4 Mhz */
/* LTDC 时钟频率 = PLLLCDCLK / DIV = 384/4/4 = 24 Mhz */
/* LTDC时钟太高会导花屏,若对刷屏速度要求不高,降低时钟频率可减少花屏现象*/
/* 以下函数三个参数分别为:PLLSAIN,PLLSAIQ,PLLSAIR,其中PLLSAIQ与LTDC无关*/
//设置像素时钟 6.35Mhz
//CLK=1M*288/4/2/4
RCC_PLLSAIConfig(192, 7, 4);
/*以下函数的参数为DIV值*/
RCC_LTDCCLKDivConfig(RCC_PLLSAIDivR_Div8);
/* Enable PLLSAI Clock */
RCC_PLLSAICmd(ENABLE);
/* Wait for PLLSAI activation */
while(RCC_GetFlagStatus(RCC_FLAG_PLLSAIRDY) == RESET)
{
}
LTDC_Init(<DC_InitStruct);
LTDC_ReloadConfig(LTDC_SRCR_IMR);
}
(4)4个按键外部中断配置(PF6,PF7,PF8,PF9)
void EXTI9_5_IRQHandler(void)
{
OSIntEnter();
if (EXTI_GetITStatus(EXTI_Line6) != RESET)
{
EXTI_ClearITPendingBit(EXTI_Line6);//清除标志
}
if (EXTI_GetITStatus(EXTI_Line7) != RESET)
{
EXTI_ClearITPendingBit(EXTI_Line7);//清除标志
}
if (EXTI_GetITStatus(EXTI_Line8) != RESET)
{
EXTI_ClearITPendingBit(EXTI_Line8);//清除标志
}
if (EXTI_GetITStatus(EXTI_Line9) != RESET)
{
EXTI_ClearITPendingBit(EXTI_Line9);//清除标志
}
OSIntExit();
}
5. 参考资料
a.《dm00287603-lcdtft-display-controller-ltdc-on-stm32-mcus-stmicroelectronics.pdf》这个是中文版的,来源于ST官网
b.《DM00031020_ENV18.pdf》来源于ST官网
c.参考的链接:
[https://www.cnblogs.com/firege/p/9435593.html](https://www.cnblogs.com/firege/p/9435593.html)-----强烈推荐,从原理到源码扫盲
[https://www.cnblogs.com/firege/p/5806040.html](https://www.cnblogs.com/firege/p/5806040.html)-----同上
[https://www.st.com/content/st_com/zh/products/microcontrollers-microprocessors/stm32-32-bit-arm-cortex-mcus/stm32-high-performance-mcus/stm32f4-series/stm32f429-439.html#products](https://www.st.com/content/st_com/zh/products/microcontrollers-microprocessors/stm32-32-bit-arm-cortex-mcus/stm32-high-performance-mcus/stm32f4-series/stm32f429-439.html#products)官网F429提供的各种库和资料
d.《datasheet-STM32F429.pdf》来源于datasheet网站
6. 调试问题及回顾
a.低功耗模式-停止模式MDK5.22下的调试。
b.低功耗模式-停止模式,TFT屏(ILI9341)唤醒后随机性出现屏幕裂纹。
在唤醒的初始化过程中,由于对ILI9341不太熟悉,因此直接使用了开机的初始化过程(复位LCD→初始化SPI→发送ILI9341的所有配置相关参数→PWM初始化→通过PWM控制背光打开)。直接在唤醒时调用,导致出现TFT存在屏幕裂纹(并非撕裂现象),该裂纹在设备断电的状态下依然存在,但慢慢地会消失。咨询相关厂家后,答复液晶有可能被极化,最后也没解决,有这方面的牛人交流交流。最后曲线救国,深入了解ILI9341的指令集,发现有熄屏和睡眠的模式,详细见上面代码。通过不用初始化的方式进行控制(F429进入停止模式之前通过SPI关闭TFT:ILI9341关屏→ILI9341进行睡眠模式;F429唤醒之后,通过SPI退出ILI9341睡眠模式→ILI9341开屏 )
c.通过第1和第2个连接并结合MDK进行数据的监测,通过逻辑分析仪监测ILI9341的同步时序判断。
d.实测的电流45ma,与官网的电气手册在低功耗停止模式下的电量有差距,这估计也是因为我们的STM32F429各个引脚的电路有关系,这部分未进行实测,待进行深入实验。
7. 手册截图
a.运行模式的电流大小:
b.低功耗睡眠模式下的功耗
c.低功耗停止模式下的功耗
d.低功耗待机模式下的功耗