Search code examples
debuggingstm32rtciarreal-time-clock

STM32F1 RTC_EnterConfigMode not always setting Config Mode


Preface: This is all being evaluated when attached to the target using an ST-Link and in debug mode in IAR Embedded Workbench IDE.

The Real Time Clock in the STM32F1 is supported in the Standard Peripheral Libraries provided by STM. I'm trying to set the RTC to 107301722, or "Sat, 26 May 2013 22:02:02 GMT", using RTC_SetCounter().

void RTC_SetCounter(uint32_t CounterValue) /*From Std Periph Lib */
{ 
  RTC_EnterConfigMode();
  /* Set RTC COUNTER MSB word */
  RTC->CNTH = CounterValue >> 16;
  /* Set RTC COUNTER LSB word */
  RTC->CNTL = (CounterValue & RTC_LSB_MASK);
  RTC_ExitConfigMode();
}

Note that it calls RTC_EnterConfigMode(), which is a requirement for modifying RTC register values: "To write in the RTC_PRL, RTC_CNT, RTC_ALR registers, the peripheral must enter Configuration Mode. This is done by setting the CNF bit in the RTC_CRL register."

void RTC_EnterConfigMode(void) /*From Std Periph Lib */
{
  /* Set the CNF flag to enter in the Configuration Mode */
  RTC->CRL |= RTC_CRL_CNF;
}

This is the code for entering config mode. Simple enough. And here's the disassembly (no optimizations are enabled). The 0x10 is the bit position of the CNF flag.

//  RTC->CRL |= RTC_CRL_CNF;
RTC_EnterConfigMode:
    0x8053ed6: 0x4829         LDR.N     R0, ??DataTable13_1     ; RTC_CRL
    0x8053ed8: 0x8800         LDRH      R0, [R0]
    0x8053eda: 0xf050 0x0010  ORRS.W    R0, R0, #16             ; 0x10
    0x8053ede: 0x4927         LDR.N     R1, ??DataTable13_1     ; RTC_CRL
    0x8053ee0: 0x8008         STRH      R0, [R1]
//}
    0x8053ee2: 0x4770         BX        LR

What I've found is if I break anywhere from the call to RTC_SetCounter() to the disassembly at line 0x8053ee0, Config Mode gets enabled, but if I move the breakpoint to the disassembly at line 0x8053ee2 or later, Config Mode does not get set, and therefore the RTC does not get set.

I have not tried anything in the realm of trying to analyze what happens in a non-debug setting simply because part of what I'm working toward is a unit test involving setting the time. The unit test will require debugger attachment.

Is this strictly a debugger problem? Are there any rational reasons to explain this behavior that could lead to a workable solution?


Solution

  • It would turn out that I have overlooked a very important function that is provided to allow current RTC register actions which are not complete to finish: RTC_WaitForLastTask().

    /**
      * @brief  Waits until last write operation on RTC registers has finished.
      * @note   This function must be called before any write to RTC registers.
      * @param  None
      * @retval None
      */
    void RTC_WaitForLastTask(void)
    {
      /* Loop until RTOFF flag is set */
      while ((RTC->CRL & RTC_FLAG_RTOFF) == (uint16_t)RESET)
      {
      }
    }
    

    If I had paid more attention to the other register flags that were set in RTC_CRL, I might have noticed that RTOFF was an issue.