EFM32PG1B those pits about RTCC and EM4

EFM32PG1B those pits about RTCC and EM4

Pit 1: RTCC initialization

 We are all familiar with RTC. I generally don't use it here as the so-called year, month and day timing function. I generally use RTC as the timing wake-up of the device. So how to initialize the RTCC of EFM32PG1B? I have summarized the following points:
1. Clock selection
2. Counting mode selection
3. Count value setting
4. Interrupt opening
 Let me talk about the first point: The clock tree of EFM32 felt more complicated when I first started, but it was actually careful Take a look, you will feel that its clock tree is just like that. just look at the picture.
RTCC clock tree
 As can be seen from the figure, there are three RTCC clock sources: LFXO, LFRCO, and ULFRCO. The first two are 32768hz, the latter is 1000hz. Here we choose ULFRCO as the clock source of LFECLK, and then enable the RTCC clock source to get it done. In short, look at the picture, follow the lines, and configure one by one.

	  CMU_ClockSelectSet(cmuClock_LFE, cmuSelect_ULFRCO);
	  CMU_ClockEnable(cmuClock_RTCC, true);

 When the clock is selected, it comes to the second point: the choice of counting mode. Here, you can choose the regular CNT counting mode. In this mode, the timer will compare RTCC_CNT with RTCC_CC[x]_CCV, and if they are equal, the RTCC interrupt will be triggered. I chose channel 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,     /* Start counting when init done.                           */  \
  false,    /* Disable RTCC during debug halt.                          */  \
  false,    /* Disable precounter wrap on ch. 0 CCV value.              */  \
  false,    /* Disable counter wrap on ch. 1 CCV value.                 */  \
  rtccCntPresc_1, /* 977 us per tick.                                  */  \
  rtccCntTickPresc, /* Counter increments according to prescaler value. */  \
  false,    /* No RTCC oscillator failure detection.                    */  \
  rtccCntModeNormal, /* Normal RTCC mode.                               */  \
  false,    /* No leap year correction.                                 */  \
}
#define RTCC_CH_INIT_COMPARE_DEFAULT                                        \
{                                                                           \
  rtccCapComChModeCompare,     /* Select output compare mode.     */        \
  rtccCompMatchOutActionToggle, /* Create pulse on compare match.  */        \
  rtccPRSCh0,                  /* PRS channel 0 (not used).       */        \
  rtccInEdgeNone,              /* No edge detection.              */        \
  rtccCompBaseCnt,             /* Counter comparison base.        */        \
  0,                           /* No compare mask bits set.       */        \
  rtccDayCompareModeMonth      /* Don't care */                             \
}

 The third point is the setting of the count value, that is, how often the RTCC interrupt is triggered. We chose a 1khz ultra-low frequency clock source, and it takes 1 millisecond for each CNT to increase by 1. Then it is relatively simple, suppose I need 30s to trigger an interrupt, then:

	RTCC_CounterSet(0);//CNT清零
	RTCC_ChannelCCVSet(1, 30*1000-1);

 Everything is ready, only the last step: enable the required interrupts, there is no technical content, directly on the code, here to emphasize one point, our purpose of using RTCC is to wake up the device from EM4 state. Therefore, the following sentence must be added! ! !

RTCC_EM4WakeupEnable(true);//使能EM4唤醒

 Then enable interrupt

	RTCC_IntClear(RTCC_IF_CC1);
	RTCC_IntEnable(RTCC_IEN_CC1);
	NVIC_ClearPendingIRQ(RTCC_IRQn);
	NVIC_EnableIRQ(RTCC_IRQn);
	RTCC_Enable(true);

 The above is the initial configuration of all RTCCs. The above configuration is for waking up from the EM4 state.

Pit 2: Initialization of EM4 low power consumption mode

 This has kept me pitted for several days, because there is very little information about this board on the Internet. The only information also says that the wake-up of this series of chips in EM4 mode can only be done through Pin interrupt. But according to the reference manual, the RTCC clock and interrupt can be triggered and awakened under EM4. So I didn't say anything, just watch it little by little.
Insert picture description here
 By the way, EM4 has two modes: EM4H and EM4S. We don't need to shut down the device, so low power consumption is enough, choose EM4H.
 What are the steps of initialization? In fact, it is relatively simple. It only needs to configure one register: EMU_EM4CTRL refers to the
specific meaning of each bit in the figure below.
Insert picture description here

  	//进入EM4模式
  	EMU_EM4Init_TypeDef em4Init = EMU_EM4INIT_DEFAULT;
  	EMU_EM4Init(&em4Init);
#define EMU_EM4INIT_DEFAULT                                                                \
{                                                                                          \
  false,                             /* Retain LFXO configuration upon EM4 entry */        \
  false,                             /* Retain LFRCO configuration upon EM4 entry */       \
  false,                              /* Retain ULFRCO configuration upon EM4 entry */      \
  emuEM4Hibernate,                     /* Use EM4 shutoff state */                           \
  emuPinRetentionDisable,            /* Do not retain pins in EM4 */                       \
}

Is it simple?

Pit 3: EM4 mode enable

 This is the reason why I have been pitted for several days. The reason is that I was lazy. In this step, I directly used the library function without looking at the contents of the library function, which led to many detours.

void EMU_EnterEM4H(void)
{
    
    
  BUS_RegBitWrite(&EMU->EM4CTRL, _EMU_EM4CTRL_EM4STATE_SHIFT, 1);
  EMU_EnterEM4();
}

 The problem lies in the sub-function EMU_EnterEM4();
 this function may have some bugs in the device, and some statements that are useless for the project have been added, such as:
__disable_irq();
this sentence directly caused my RTCC interruption to fail. Play a role, the device becomes brick after entering EM4 mode sleep, it must be powered on again to POR.
 In fact, it’s very simple to enter EM4. It’s still the EMU_EM4CTRL register. The 17:16 of this register takes care of this. You only need to write these two bits sequentially into 2, 3, 2, 3, 2, 3, 2, 3, and 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;

 That's all, I hope it helps! ! ! My style has never been philosophical, so those who wish to philosophize may only use my code as a reference. The real knowledge needs to be explored by oneself, don’t be philosophical.

Guess you like

Origin blog.csdn.net/m0_38127906/article/details/107238902