This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
您好!
这个问题与我们器件的功耗以及我们为其创建的应用相关。
我们的初始开发是在 Launchpad MSP-EXP430FR6989上完成的。
我们的定制板是围绕 MSP430FR5989开发的。
创建低功耗模式测试的目的是验证 RTC_C 的时间事件中断将唤醒系统并在睡眠周期后恢复运行
然后、测试包括:
a)为每个可能的时间间隔分钟、小时、中午和午夜的时间事件中断对 RTC_C 进行编程。
b)进入 LPM3.5
c)返回时通知用户发生了时间事件。
下面的代码片段应显示我们要执行的操作。
======================================================================== 测试函数================================================================================================================
/* *注 释*/ void testTimeEventMinute (void) { uint16_t count = 0; uint8_t 应答; log_print (log_always、"%s"、__function__); 静态日历 cm = { 0、 //! 秒数介于0-59之间 0、 //! 0-59之间的分钟数 14、 //! 0到23之间的一天中的一小时 3、 //! 周中的某天 16、 //! 1至31之间的月中某天 6、 //! 1到12之间的月份 2020年 //! 介于0-4095之间 }; TEST_EVENT_MINUT_CONTINUE = true; /* *清除日历模块中的所有中断 *在决定通知之前 * CM_clearInterrupt (RTC_C_TIME_EVENT_INTERRUPT | RTC_C_CLOCK_READ_READY_INTERRUPT | RTC_C_CLOCK_ALARM_INTERRUPT); /* *禁用日历模块中的所有中断 *在决定通知之前 * CM_disableInterrupt (RTC_C_TIME_EVENT_INTERRUPT | RTC_C_CLOCK_READ_READY_INTERRUPT | RTC_C_CLOCK_ALARM_INTERRUPT); /* *初始化 Calendar Manager * cm_init (&cm); /* *每隔一分钟就会收到通知 * CM_registerEvent (RTC_C_CALENDAREVENT_INTOTECHANGE); /* *在发生时间事件时生成中断 * CM_enableInterrupt (RTC_C_TIME_EVENT_INTERRUPT); /* *启动日历 * CM_START(); //询问用户是否要进入深度睡眠状态 //等待此事件 MP_PRINT (BACK_CHANNEL、"%s\n"r、"是否要进入低功耗模式等待此事件(y/n)? "); 应答= MP_getchar (BACK_CHANNEL); mp_print (后退通道、"%s"、%c\n\r\n、"您的答案->、答案); while (test_event_minute_continue == true) { 如果(答案='y') { /* *进入启用中断的低功耗模式 * _enable_interrupt (); //此代码用于深度睡眠-可以正常工作,但还无法通过它进行调试 log_print (log_always、"%s"进入深度睡眠\n\r\n、__function__); ctpl_enterLpm35 (CTPL_disable_restore_ON_reset);<--- 在这里、我们进入深度睡眠模式 log_print (log_always、"%s"从深度睡眠返回)\n\n"、__function__);<--- 我们从未从深度睡眠中返回(代码适用于 MSP430FR6989) } count++; 如果(计数= 0) { mp_print (BACK_CHANNEL、"."); LED_TOGGLE (1); } /* *检查第二个事件是否被触发 * 无符号长整型 val = 0; Val = bit_CHK (eventBitmap、rtcReadyInterruptTrigged); 如果(val = 1) { /* *记录每秒中断事件 * mp_print (BACK_CHANNEL、"Interrupt for second was trigged\n"r); /* *请日历管理器处理事件 * CM_handleSecondEvent(); } /* *检查事件分钟是否被触发 * Val = bit_CHK (eventBitmap、rtcTimeEventMinutInterruptTrigged); 如果(val = 1) { mp_print (BACK_CHANNEL、"Interrupt for Minute was trigged\n"r); /* *让测试事件处理程序处理该事件 * test_handleMinuteEvent(); } /* *检查事件小时是否被触发 * Val = bit_CHK (eventBitmap、rtcTimeEventHourInterruptTrigged); 如果(val = 1) { mp_print (BACK_CHANNEL、"小时中断已触发\n\r\n); /* *让测试事件处理程序处理该事件 * test_handleHourEvent(); } /* *检查事件中午是否被触发 * Val = bit_CHK (eventBitmap、rtcTimeEventNoonInterruptTrigged); 如果(val = 1) { mp_print (BACK_CHANNEL、"已触发中午中断\n\r\n); /* *让测试事件处理程序处理该事件 * test_handleNoonEvent(); } /* *检查是否触发了午夜事件 * Val = bit_CHK (eventBitmap、rtcTimeEventMidnightInterruptTrigged); 如果(val = 1) { mp_print (BACK_CHANNEL、"已触发午夜中断\n\r\n); /* *让测试事件处理程序处理该事件 * test_handleMidnightEvent(); } } log_print (log_always、"%s"完成\n\r\n、__function__); 返回; }
======================================================================== calendarManager 代码========================================================
/*! 文件 calendarManager.c
简要实施日历管理模块
此文件包含用于实现的代码
MightyPuffer 器件的日历管理功能
*
/*
========================================================
* calendarManager.c
*
*创建日期:2020年1月30日
*作者:首先
========================================================
*
#include "calendarManager.h"/*!<日历管理器定义和函数原型*/
/*
*注意:
*
void CM_init (日历*cm)
{
log_print (log_always、"%s"、__function__);
RTC_C_initCalendar (RTC_C_base、cm、RTC_C_FORMAT_BINARY);
返回;
}
/*
*注意:
*
void CM_start (void)
{
log_print (log_always、"%s"、__function__);
RTC_C_startClock (RTC_C_base);
返回;
}
/*
*注意:
*
void CM_stop (void)(空)
{
log_print (log_always、"%s"、__function__);
RTC_C_HOLDClock (RTC_C_BASE);
返回;
}
/*
*注意
*
空 CM_getTime (日历*cm)
{
日历 wrkCm;
log_print (log_always、"%s"、__function__);
wrkCm = RTC_C_getCalendarTime (RTC_C_base);/*!<告诉 driverlib 模块 RTC_C 执行该操作*
cm->seconds = wrkCm.seconds;/*!<*/
CM->Minutes = wrkCm.Minutes;/*!<*/
CM->Hours = wrkCm.Hours;/*!<*/
CM->DayOfWeek = wrkCm.DayOfWeek;/*!<*
cm->dayofmonth = wrkcm.dayofmonth;/*!<*
cm->month=wrkcm.month;/*!<*/
Cm->年= wrkcm.Year;/*!<*
返回;
}
/*
*注意:
*
void CM_registerEvent (uint16_t eventToRegister)
{
log_print (log_always、"%s"、__function__);
RTC_C_setCalendarEvent (RTC_C_base、eventToRegister);/*!<告诉 driverlib 模块 RTC_C 执行该操作*
返回;
}
/*
*注意:
*
void CM_enableInterrupt (uint8_t interruptToEnable)
{
log_print (log_always、"%s"、__function__);
RTC_C_enableInterrupt (RTC_C_base、interruptToEnable);/*!<告知 driverlib 模块 RTC_C 执行此操作*
返回;
}
/*
*注意:
*
void CM_clearInterrupt (uint8_t interruptToClear)
{
log_print (log_always、"%s"、__function__);
RTC_C_clearInterrupt (RTC_C_base、interruptToClear);/*!<告知 driverlib 模块 RTC_C 执行该操作*
返回;
}
/*
*注意:
*
void CM_disableInterrupt (uint8_t interruptToDisable)
{
log_print (log_always、"%s"、__function__);
RTC_C_DisableInterrupt (RTC_C_base、interruptToDisable);/*!<告知 driverlib 模块 RTC_C 执行该操作*
返回;
}
/*
*注意:
*
void CM_registerAlarm (RTC_C_configureCalendarAlarmParam *警报)
{
log_print (log_always、"%s"、__function__);
RTC_C_configureCalendarAlarm (RTC_C_base、alarm);/*!<告诉 driverlib 模块 RTC_C 执行该操作*
返回;
}
/*
*注意:
*
cm_status_e cm_compareDate (mp_date_t * nowDate、mp_date_t * thenDate)
{
CM_STATUS_e 状态= CM_SUCCESS;
log_print (log_always、"%s"、__function__);
/*
*比较月份
*
if (nowDate->mp_mon == thenDate->mp_mon)
{
/*
*比较当天
*
if (nowDate->mp_mday == thenDate->mp_mday)
{
状态= CM_DATE_NOW _EQU_then;
}
其他
{
/*
*比较当天
*
if (nowDate->mp_mday < thenDate->mp_mday)
{
状态= CM_DATE_NOW _LE_then;
}
其他
{
状态= CM_DATE_NOW:GT_then;
}
}
}
其他
{
/*
*比较月份
*
if (nowDate->mp_mon < thenDate->mp_mon)
{
状态= CM_DATE_NOW _LE_then;
}
其他
{
状态= CM_DATE_NOW:GT_then;
}
}
退货状态;
}
/*
*注意:
*比较是在 HH:MM 上进行的
*在此比较中不考虑秒数
*但这是我们当前的方法
*
CM_STATUS_e CM_COMPARE 时间(MP_TIME_t * nowTime、MP_TIME_t * thenTime)
{
CM_STATUS_e 状态= CM_SUCCESS;
log_print (log_always、"输入:%s\n\r\n、__function__);
/*
*
*比较小时
*
if (nowTime->mp_hour =thenTime->mp_hour)
{
/*
*比较分钟
*
if (nowTime->mp_min =thenTime->mp_min)
{
状态= CM_TIME_Now_EQU_then;
}
其他
{
/*
*比较分钟
*
if (nowTime->mp_min < thenTime->mp_min)
{
状态= CM_TIME_Now_LE_Then;
}
其他
{
状态= CM_TIME_Now_LE_Then;
}
}
}
其他
{
/*
*比较小时
*
if (nowTime->mp_hour < thenTime->mp_hour)
{
状态= CM_TIME_Now_LE_Then;
}
其他
{
状态= CM_TIME_Now_GT_then;
}
}
退货状态;
}
/*
*注意:
*
空 CM_handleSecondEvent (空)
{
eventBitmap = bit_CLR (eventBitmap、rtcReadyInterruptTrigged);
}
/*
*注意:
*
void CM_handleMinuteEvent (void)
{
log_print (log_always、"输入:%s\n\r\n、__function__);
eventBitmap = bit_CLR (eventBitmap、rtcTimeEventMinutInterruptTrigged);
}
/*
*注意:
*
无效 CM_handleHourEvent (空)
{log_print (log_always、"输入:%s\n\r\n、__function__);
eventBitmap = bit_CLR (eventBitmap、rtcTimeEventHourInterruptTrigged);
}
/*
*注意:
*
*在午夜事件的处理中
*我们获取当前日期和时间
*并执行日期比较
*
*
void CM_handleMidnightEvent (void)
{
MP_STATUS_e 状态= MP_SUCCESS;/*!<*/
CM_STATUS_e compareStatus = CM_SUCCESS;/*!<*/
CM_STATUS_e compareStatus1 = CM_SUCCESS;/*!<*/
mp_date_t 激活日期={0};/*!<*
mp_date_t 当天日期={0};/*!<*
mp_date_t endOfSeasonDate ={0};/*!<*
日历现在={0};/*!<*/
uint16_t seasonWindow = 0;/*!<*
log_print (log_always、"输入:%s\n\r\n、__function__);
/*
*检索季节窗口
*
状态= PC_retrieSeasonWindow (季节性窗口);
if (status!= MP_SUCCESS)
{
log_print (log_always、"%s -检测到错误\n\r\n、__function__);
返回;
}
/*
*立即从 Calendar Manager 硬件获取时间
*我们可以将其更改为使用第二个中断
*立即捕获日期和时间
*
cm_getTime (&now);/*!<*/
/*
*仅获取日期部分
*
当天 Date.mp_year = Now.Year;
todayDate.mp_mon |= now月份;
todayDate.mp_mday |= now.dayofmonth;
/*
*从检索激活日期
*主动填充协议
*
状态= PC_retrieActivationDate (&activationDate);
如果(status == MP_SUCCESS)
{
/*
*将今天的日期与激活日期进行比较
*
CompareStatus = CM_compareDate (&todayDate、&activationDate);
开关(比较状态)
{
案例 CM_DATE_Now_EQU_then:
log_print (log_always、"%s"我们处于激活日期\n\r\n、__function__);
eventBitmap = bit_set (eventBitmap、activationDateRedached);
中断;
案例 CM_DATE_Now_LE_Then:
log_print (log_always、"%s"我们早于激活日期\n"r、__function__);
eventBitmap = bit_set (eventBitmap、activationDateNotYetReached);
中断;
案例 CM_DATE_Now_GT_Then:
log_print (log_always、"%s"我们在激活日期之后\n\r\n、__function__);
/*
*现在我们需要了解我们是否仍处于淡季
*的季节窗口。
*这是通过将今天的日期与进行比较来完成的
*按激活日期+季节计算的日期
*
addDays ((int) activationDate.mp_mday、
(int) activationDate.mp_mon、
(int) activationDate.mp_year、
SeasonWindow、
endOfSeasonDate.mp_mday、
endOfSeasonDate.mp_mon、
endOfSeasonDate.mp_year);
/*
*将今天的日期与季末日期进行比较
*
compareStatus1 = CM_compareDate (&T)、endOfSeasonDate (&endOfSeasonDate);
开关(compareStatus1)
{
案例 CM_DATE_Now_EQU_then:
/*
*我们刚刚结束了赛季
*
*
案例 CM_DATE_Now_GT_Then:
/*
*本赛季结束后,Whave 已过
*
eventBitmap = bit_set (eventBitmap、activationDatePassed);
/*
*
*我们需要通过增加来修改激活日期
*按今天到之间的年份数计算的年份
*季末后的一年
*
activationDate.mp_year ++;
状态= PC_AdjustActivationDate (&activationDate);
if (status!= MP_SUCCESS)
{
log_print (log_always、"%s -检测到错误\n\r\n、__function__);
返回;
}
中断;
案例 CM_DATE_Now_LE_Then:
/*
*我们仍在季中
*可以进行正常处理
*
*
eventBitmap = bit_set (eventBitmap、dataStillInSeason);
中断;
}
}
}
/*
*清除事件
*
eventBitmap = bit_CLR (eventBitmap、rtcTimeEventMidnightInterruptTrigged);
返回;
}
/*
*注意:
*
void CM_handleNoonEvent (void)
{
log_print (log_always、"输入:%s\n\r\n、__function__);
eventBitmap = bit_CLR (eventBitmap、rtcTimeEventNoonInterruptTrigged);
}
/*
*注意:
*
void CM_hanleAlarm (void)
{
log_print (log_always、"输入:%s\n\r\n、__function__);
eventBitmap = bit_CLR (eventBitmap、rtcAlarmInterruptTrigged);
}
/*
================================================================
*中断服务例程(ISR)
================================================================
*
#if defined (__TI_Compiler_version__)|| Defined (__IAR_systems_ICC__)
#pragma vector=RTC_vector
_interrupt
#Elif defined (_GNU_)
__attribute__((中断(RTC_Vector))
#endif
/**
*这是中断服务例程(ISR)
*表示内部 RTC_C 日历
*至少有六个中断源可用、即
*
* RT0PSIFG:
*====
* RT0PSIFG 可被用于生成可由 RT0IP 位选择的中断间隔。
* RT0PS 以32768Hz 的低频振荡器时钟作为时钟源、
*所以间隔为
* 16384Hz、
* 8192Hz、
* 4096 Hz、
* 2048Hz、
* 1024 Hz、
* 512Hz、
* 256Hz、
*或128Hz
*是可能的。
*将 RT0PSIE 位置位将启用中断。
*
* RT1PSIFG:
*====
* RT1PSIFG 可被用于生成可由 RT1IP 位选择的中断间隔。
* RT1PS 由 RT0PS 的输出提供、其频率为128Hz (32768/256Hz)。
*因此、间隔为
* 64Hz、
* 32Hz、
* 16Hz、
* 8Hz、
* 4Hz、
* 2Hz、
* 1Hz、
*或0.5Hz
*是可能的。
*将 RT1PSIE 位置位会启用中断。
*
*
* RTCRDYIFG:
*===========
*
* RTCRDY 位为实时时钟中断 RTCRDYIFG 供源、并且在同步时非常有用
*使用系统时钟读取时间寄存器。 将 RTCRDYIE 位置位将启用中断。
*
*安全读取实时时钟寄存器的一种简便方法是使用 RTCRDYIFG 中断标志。
*
*设置 RTCRDYIE 使能 RTCRDYIFG 中断。
*
*启用后、会根据 RTCRDY 位的上升沿生成中断、
*导致 RTCRDYIFG 被置位。
*
*此时、应用程序有将近一秒钟的时间来安全地读取任何或所有实时时钟寄存器。
*
*此同步过程可防止在转换期间读取时间值。
*当中断被处理时、RTCRDYIFG 标志会自动复位、也可以通过软件复位。
*
*
* RTCTEVIFG:
*
* RTCAIFG:
*
* RTCOFIFG:
*
*这些标志被优先化并被组合在一起以提供一个单一的标志
*中断矢量。
*中断向量寄存器(RTCIV)用于确定请求的标志
*中断。
*
空 RTC_ISR (空)
{
开关(__evo_in_range (RTCIV、RTCIV_RT1PSIFG))
{
/*
*矢量0
*无中断
*
案例 RTCIV_NONE:
{
RTC_C_clearInterrupt (RTC_C_base、RTC_C_TIME_EVENT_INTERRUPT);
HWREG8 (RTC_C_BASE + OFS_RTCCTL0_L)&&~Ω RTCTEVIFG;
_no_operation();
}
中断;
/*
*矢量2
* RTCOFIFG
* 32kHz 晶体振荡器故障中断标志。
*此中断可用作 LPM3.5唤醒事件。
*它还指示备份操作期间的时钟故障。
* 0b =无中断挂起
* 1b =中断挂起。
*在最后一次复位后发生32kHz 晶体振荡器故障。
*
案例 RTCIV_RTCOFIFG:
{
RTC_C_clearInterrupt (RTC_C_base、RTC_C_osc_oscillator_FAULT_interrupt);
_no_operation();
}
中断;
/*
*矢量4
* RTCRDYIFG
*该矢量对应于
* RTC_C_CLOCK_READ_READY_INTERRUPT
*实时时钟就绪中断标志
* 0b =无法安全读取 RTC
* 1b = RTC 可被安全读取
*
*
案例 RTCIV_RTCRDYIFG:
{
/*
*每秒中断一次
*
eventBitmap = bit_set (eventBitmap、rtcReadyInterruptTrigged);
RTC_C_clearInterrupt (RTC_C_base、RTC_C_CLOCK_READ_READY_READY_INTERRUPT);
}
中断;
/*
*矢量6
* RTCEVIFG
*
案例 RTCIV_RTCTEVIFG:
{
/*
*实时时钟时间事件中断标志。
*在支持 LPM3.5的模块中、此中断
*可用作 LPM3.5唤醒事件。
* 0b =未发生时间事件
* 1b =发生了时间事件
*
/*
*我们使用日历模式(RTCMODE =1)
*
*读取寄存器控制1位0和1
* 1-0 RTCTEVx RW 0h 实时时钟时间事件
* 00b =分钟更改
* 01b =小时更改
* 10b =每天午夜(00:00)
* 11b =每天中午(12:00)
*
开关(HWREG8 (RTC_C_BASE + OFS_RTCCTL13_L)和 RTCTEV_3)
{
案例 RTCTEV__min:
{
/*
*每分钟中断一次
*
eventBitmap = bit_set (eventBitmap、rtcTimeEventMinutInterruptTrigged);
RTC_C_clearInterrupt (RTC_C_base、RTC_C_TIME_EVENT_INTERRUPT);
}
中断;
案例 RTCTEV__Hour:
{
/*
*每小时中断一次
*
eventBitmap = bit_set (eventBitmap、rtcTimeEventHourInterruptTrigged);
RTC_C_clearInterrupt (RTC_C_base、RTC_C_TIME_EVENT_INTERRUPT);
}
中断;
/*
*每天午夜中断
*
案例 RTCTEV__0000:
{
eventBitmap = bit_set (eventBitmap、rtcTimeEventMidnightInterruptTrigged);
RTC_C_clearInterrupt (RTC_C_base、RTC_C_TIME_EVENT_INTERRUPT);
}
中断;
/*
*每天中午中断
*
RTCTEV__1200案例:
{
eventBitmap = bit_set (eventBitmap、rtcTimeEventNoonInterruptTrigged);
RTC_C_clearInterrupt (RTC_C_base、RTC_C_TIME_EVENT_INTERRUPT);
}
中断;
默认值:
{
RTC_C_clearInterrupt (RTC_C_base、RTC_C_TIME_EVENT_INTERRUPT);
RTC_C_DisableInterrupt (RTC_C_base、RTC_C_TIME_EVENT_INTERRUPT);
}
中断;
}
}
中断;
/*
*矢量8
* RTCAIFG
*
案例 RTCIV_RTCAIFG:
{
eventBitmap = bit_set (eventBitmap、rtcAlarmInterruptTrigged);
RTC_C_clearInterrupt (RTC_C_base、RTC_C_CLOCK_ALARM_INTERRUPT);
}
中断;
/*
*矢量 A
* RT0PSIFG
*
案例 RTCIV_RT0PSIFG:
{
_no_operation();
}
中断;
/*
*矢量 C
* RT1PSIFG
*
案例 RTCIV_RT1PSIFG:
{
_no_operation();
}
中断;
/*
*默认情况
*
默认值:
{
_no_operation();
}
中断;
}
}
/*模块结尾 calendarManager.c */
在下面的调试会话中、我们将进入 LPM3.5
在第138行放置断点并恢复执行
实际上会进入深度睡眠模式。
调试器指示
器件型号:MSP430FR5989
您好!
随着我们接近项目结束、我们现在将解决 一些绩效问题。
随着我们的应用及其运行的器件部署在现场、功耗至关重要。
现场器件由两节 AA 电池供电。
我们客户的要求规定、电池应在提交的文件中运行一年以上、而不会造成性能损失。
为了实现此目标、我们在器件需要执行的日常周期之间将器件置于其最低功耗模式。
为此、我们选择了 LPM3.5。
在此模式下、我们的电流消耗为9.8uA、这很好、但不足以满足要求。
我们对文档的阅读告诉我们、我们应该能够降低到0.4uA。
我们的设计使用外部 RTC (来自 NXP 的 PCF8523)为 MCU (MSP430FR5989)提供32、768 kHz 的输入频率
原理图的片段显示了我们连接外部 RTC 并通过 PJ4_LXFIN 提供时钟的方式。
此外、还附上了测试低功耗模式3.5的测试代码。
这是允许我们验证9.8uA 数据点的代码。
问题实际上是、我们还能做些什么来降低功耗。
很抱歉、我已经等了这么长时间才解释了所有这些内容。
非常感谢您对这些问题提供的帮助。
此致
Jean-Pierre Saintfeld
此.zip 文件可能看起来像是 CTPL 演示程序。 具体而言、我看不到您在上面发布的任何代码。 您打算附加什么?
对于 CLKOUT 上拉、1K 看起来相当强。 UM (UM10301第16节)建议使其尽可能大(较弱)。 演示板(UM10760图3)使用22K。
更一般而言、运行 CLKOUT 本身消耗大约1uA [参考 PCF8523数据表表表表48]。 我记得、当我们使用 PCF8523T 时、我们让它进行计数并使用中断唤醒我们。
Bruce、
再次向您提供帮助、帮助您解决这些问题。
我认为我在我的帖子中犯了一个错误。
我们尝试解决两种情况:
1) 1)第一个问题是回答以下问题:
-假设输入引脚 PJ.4 LXFIN 上有一个外部时钟、那么我们可以获得的最低功耗将是多少。
为了证明这一点、我们需要一些代码示例、允许我们执行以下操作:
test_ctpl_gpio_mspfr5989.zip 就是这样的计划。 此后、我们对其进行了轻微更新、并已证明了这一点。
在本例中、我们可以下降到0.012uA。 MSPFET 调试器的存在阻碍了我们的初始测量、该调试器消耗了一些电流
即使从 USB 集线器断开连接也是如此。 一旦器件完全没有任何其他外部影响、我们的测量就可以精确地进行。
我们认为,我们现在可以利用你建议的22k R11的规定来解决这个问题。
2) 2)第二个问题 是我错误地将其插入顶部的问题。
我认为、为了减少混淆、我应该将这个问题标记为已解决、并为与 RTC_C 相关的问题打开一个新问题
从 LPM3.5唤醒的时间事件。
再次感谢您的友好帮助
JP 圣费尔德