EFM32PG1B关于RTCC和EM4的那些坑
- EFM32PG1B关于RTCC和EM4的那些坑
- 坑一:RTCC初始化
- 坑二:EM4低功耗模式的初始化
- 坑三:EM4模式使能
EFM32PG1B关于RTCC和EM4的那些坑
坑一:RTCC初始化
对于RTC我们都比较熟悉,我这里一般不把他用作所谓的年月日计时功能,我一般将RTC用作设备的定时唤醒。那么EFM32PG1B的RTCC又该如何初始化呢?我总结下来有如下几点:
1、时钟的选择
2、计数模式的选择
3、计数值设置
4、中断开启
先说第一点:EFM32的时钟树刚上手的时候感觉比较复杂,但其实仔细地看一下,会感觉它的时钟树也就那样。话不多说,上图。
从图中可以看出,RTCC的时钟源有三个:LFXO、LFRCO、ULFRCO。前两个是32768hz,后一个是1000hz。这里我们将LFECLK的时钟源选择为ULFRCO,之后再使能RTCC时钟源就搞定了,总之一句话,看着图、循着线、一条一条地配置。
CMU_ClockSelectSet(cmuClock_LFE, cmuSelect_ULFRCO);
CMU_ClockEnable(cmuClock_RTCC, true);
时钟选择好就到了第二点:计数模式的选择,这里就选择常规地CNT计数模式就可以,这种模式下定时器会比较RTCC_CNT与RTCC_CC[x]_CCV,如果相等就触发RTCC中断。我选用的是通道1。
RTCC_Init_TypeDef rtccInit = RTCC_INIT_DEFAULT;
RTCC_CCChConf_TypeDef rtccInitCompareChannel = RTCC_CH_INIT_COMPARE_DEFAULT;
RTCC_ChannelInit(1, &rtccInitCompareChannel);
// Initialize and start counting
RTCC_Init(&rtccInit);
#define RTCC_INIT_DEFAULT \ { \ false, \
false, \
false, \
false, \
rtccCntPresc_1, \
rtccCntTickPresc, \
false, \
rtccCntModeNormal, \
false, \
}
#define RTCC_CH_INIT_COMPARE_DEFAULT \ { \ rtccCapComChModeCompare, \
rtccCompMatchOutActionToggle, \
rtccPRSCh0, \
rtccInEdgeNone, \
rtccCompBaseCnt, \
0, \
rtccDayCompareModeMonth \
}
第三点是计数值的设置,也就是多久触发RTCC中断,我们选用了1khz的超低频时钟源,CNT每加1用时为1毫秒。那么就比较简单了,假设我需要30s触发中断,那么:
RTCC_CounterSet(0);//CNT清零
RTCC_ChannelCCVSet(1, 30*1000-1);
万事俱备,只差最后一步:使能所需要的中断,没啥技术含量,直接上代码,这里要着重说一点,我们使用RTCC的目的是将设备从EM4状态下唤醒。因此,下面这一句必须要加!!!
RTCC_EM4WakeupEnable(true);//使能EM4唤醒
然后使能中断
RTCC_IntClear(RTCC_IF_CC1);
RTCC_IntEnable(RTCC_IEN_CC1);
NVIC_ClearPendingIRQ(RTCC_IRQn);
NVIC_EnableIRQ(RTCC_IRQn);
RTCC_Enable(true);
以上就是所有RTCC的初始化配置了,以上配置都是为了从EM4状态唤醒而服务的。
坑二:EM4低功耗模式的初始化
这个可把我坑了好几天,因为网上关于这个板子的资料很少,仅有的资料也说这一系列的芯片在EM4模式下的唤醒只能通过Pin interrupt 。但我看参考手册上讲,EM4下RTCC的时钟和中断是可以触发且唤醒的。所以啥也不说了,一点儿一点儿看。
对了,EM4有两个模式:EM4H和EM4S。我们不需要设备关机,所以,低功耗就足够了,选择EM4H。
初始化的步骤是什么呢,其实比较简单,只需要配置一个寄存器就够了:EMU_EM4CTRL
具体每一bit的意思见下图
//进入EM4模式
EMU_EM4Init_TypeDef em4Init = EMU_EM4INIT_DEFAULT;
EMU_EM4Init(&em4Init);
#define EMU_EM4INIT_DEFAULT \ { \ false, \
false, \
false, \
emuEM4Hibernate, \
emuPinRetentionDisable, \
}
有没有很简单呢?
坑三:EM4模式使能
这一点是坑了我好几天的原因,原因就是偷了一下懒,这一步我直接使用了库函数而没有看库函数里的内容,导致走了好多弯路。
void EMU_EnterEM4H(void)
{
BUS_RegBitWrite(&EMU->EM4CTRL, _EMU_EM4CTRL_EM4STATE_SHIFT, 1);
EMU_EnterEM4();
}
问题就处在里面的子函数EMU_EnterEM4();
这个函数里面可能由于设备有一些BUG,里面增加了一些对项目无用的语句,比如:
__disable_irq();
这一句话直接导致我的RTCC中断一直都无法发挥作用,使设备进入EM4模式休眠后就变砖了,必须要重新上电POR才可以。
其实进入EM4很简单,还是EMU_EM4CTRL寄存器,这个寄存器的17:16就是管这个事情的,只需要将这两个比特依次写入2、3、2、3、2、3、2、3、2就ok了
int i;
uint32_t em4seq2 = (EMU->EM4CTRL & (~0x30000))
| (2 << 16);
uint32_t em4seq3 = (EMU->EM4CTRL & (~0x30000))
| (3 << 16);
EMU_Unlock();
for (i = 0; i < 4; i++)
{
EMU->EM4CTRL = em4seq2;
EMU->EM4CTRL = em4seq3;
}
EMU->EM4CTRL = em4seq2;
以上就是所有的内容了,希望有所帮助哦!!!我的风格从来都不是拿来主义,所以希望拿来主义的人可能拿我的代码也只能做个参考,真正的知识是需要自己付出心力去探求的,不要拿来主义哦。