ATtiny817 Xplained Mini RTC Configuration - c

I am using a ATtiny817 xplained Mini, I want to toggle LED using overflow interrupt for every 10 sec from RTC, but i am not able generate the interrupt. Is the configurations correct?
I have configured the Main clock source 32kHz (Low Power Oscillator), using 1KHz from it to clock the RTC with no prescaler.
#define RTC_SAMPLE_PERIOD (1024 * 10)
void RTC_init(void)
{
/* Configuring the Clock Source */
_PROTECTED_WRITE(CLKCTRL.OSC32KCTRLA, CLKCTRL_RUNSTDBY_bm);
_PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, !CLKCTRL_PEN_bm);
_PROTECTED_WRITE(CLKCTRL.MCLKCTRLA, !CLKCTRL_CLKOUT_bm | CLKCTRL_CLKSEL_OSCULP32K_gc);
while (!(CLKCTRL.MCLKSTATUS & CLKCTRL_OSC32KS_bm));
/* Initialize RTC */
while (RTC.STATUS > 0)
; //Wait for All registers to be Synchronized
/* Set Period */
RTC.PER = RTC_SAMPLE_PERIOD;
/* Configuring RTC CLOCK */
RTC.CLKSEL = RTC_CLKSEL_INT1K_gc; //Selecting 1kHz from 32KHz Low Power Oscillator (OSCULP32K)
/* Run in debug: enabled */
RTC.DBGCTRL |= RTC_DBGRUN_bm;
RTC.CTRLA = RTC_RTCEN_bm /* Enable: enabled */
| RTC_RUNSTDBY_bm; /* Run In Standby: enabled */
/* Enable Overflow Interrupt */
RTC.INTCTRL |= RTC_OVF_bm;
}
ISR(RTC_CNT_vect)
{
LEDupdateFlg = 1;
RTC.INTFLAGS |= RTC_OVF_bm;
}

Related

STM32F4 one master timer triggers two slave times

I'm a little bit stuck about timer synchronization with STM32F446RE.
I want to use 1 timer as master and two timers as slaves. The master timer (i.e. TIM2) has a period of 5 seconds and starts the other two timers at the same time.
The slave timers have own periods (1st slave has a period of 4 seconds and 2nd slave has a period of max 3 seconds). The 2nd slave timer (i.e. TIM1) will generate a one-pulse output. Both slaves should run 1 time and stop. They only should get activated again if the master timer sends a trigger. I want to use the 1. slave to adapt the period of the 2nd slave by calling an interrupt handler where I write the registers ARR and PSC and CCR1 (for one pulse).
I tried to do this with HAL but it's getting more and more confusing. Does anybody have a nice idea how to code this (little code-snippet would be very nice) with writing registers instead of HAL?
I also had a look to the timer cookbook of STM at chapter 6 but didn't get it working yet. https://www.st.com/content/ccc/resource/technical/document/application_note/group0/91/01/84/3f/7c/67/41/3f/DM00236305/files/DM00236305.pdf/jcr:content/translations/en.DM00236305.pdf
Thank you very much for any feedback!
Kind regards,
Tobi
OK the first part is done.
Configuration of TIM2:
- configure as master with a period of 10 seconds.
- use TIM_TRGO_UPDATE as output trigger for slave timer(s).
I first created the timer with STM32CubeMX and then examined the HAL-functions that got called.
static void Timer2_Init(){
/* activate clock for TIM2 peripheral */
__HAL_RCC_TIM2_CLK_ENABLE();
/* Prescaler */
TIM2->PSC = 44999; // bus is running with 90MHz
/* set counter mode */
TIM2->CR1 &= ~(TIM_CR1_DIR | TIM_CR1_CMS);
TIM2->CR1 |= TIM_COUNTERMODE_UP;
/* Auto-Reload Register */
TIM2->ARR = 20000;
/* Set Clock Division */
TIM2->CR1 &= ~ TIM_CR1_CKD;
TIM2->CR1 |= TIM_CLOCKDIVISION_DIV1;
/* set Auto-Reload-Preload */
//TIM2->CR1 |= (0 << 7);
/* Update Event - if this timer is configured as Master with output TRGO_UPDATE
* the slave timer TIM 1 will get a trigger and run one time
*
* This bit can be set by software, it is automatically cleared by hardware.
* 0: No action
* 1: Reinitialize the counter and generates an update of the registers. Note that the prescaler
* counter is cleared too (anyway the prescaler ratio is not affected). For more see manual. */
//TIM2->EGR = TIM_EGR_UG;
/* Set Clock Source */
TIM2->SMCR &= ~(TIM_SMCR_SMS | TIM_SMCR_TS | TIM_SMCR_ETF | TIM_SMCR_ETPS | TIM_SMCR_ECE | TIM_SMCR_ETP);
/* Master Configuration */
TIM2->CR2 &= ~TIM_CR2_MMS;
TIM2->CR2 |= TIM_TRGO_UPDATE;
TIM2->SMCR &= ~TIM_SMCR_MSM;
TIM2->SMCR |= TIM_SMCR_MSM;
TIM2->CR1 = TIM_CR1_CEN;
}
Next the initialization of TIM1:
- configure as master.
- set ARR for 5 seconds.
- set CCR1 for pulse lenght of 1 second.
Again I used STM32CubeMX to create the code first and then examined the content of all HAL functions.
static void Timer1_Init(){
/* activate clock for TIM1 peripheral */
__HAL_RCC_TIM1_CLK_ENABLE();
/* Edited Registers of HAL_TIM_Base_Init(&htim1) */
/* Prescaler */
TIM1->PSC = 17999; // bus is running with 180MHz
/* set counter mode */
TIM1->CR1 &= ~(TIM_CR1_DIR | TIM_CR1_CMS);
TIM1->CR1 |= TIM_COUNTERMODE_UP;
/* Auto-Reload-Register */
TIM1->ARR = 49999;
TIM1->CR1 &= ~ TIM_CR1_CKD;
TIM1->CR1 |= TIM_CLOCKDIVISION_DIV1;
/* repetition counter if pulse should be displayed more than 1 time */
TIM1->RCR = 0;
/* Auto-Reload Preload Enable */
//TIM1->CR1 |=TIM_CR1_ARPE;
/* update event */
TIM1->EGR = TIM_EGR_UG;
/* Edited registers of HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) */
TIM1->SMCR &= ~(TIM_SMCR_SMS | TIM_SMCR_TS | TIM_SMCR_ETF | TIM_SMCR_ETPS | TIM_SMCR_ECE | TIM_SMCR_ETP);
/* One Pulse Mode: Edited registers of HAL_TIM_OnePulse_Init(&htim1, TIM_OPMODE_SINGLE) */
//TIM1->CR1 &= ~TIM_CR1_OPM;
TIM1->CR1 |= TIM_CR1_OPM;
/* Slave Mode configuration: edited registers of HAL_TIM_SlaveConfigSynchro(&htim1, &sSlaveConfig) */
TIM1->SMCR &= ~TIM_SMCR_TS;
TIM1->SMCR |= TIM_TS_ITR1;
TIM1->SMCR &= ~TIM_SMCR_SMS;
TIM1->SMCR |= (TIM_SMCR_SMS_2 | TIM_SMCR_SMS_1); // = TIM_SLAVEMODE_TRIGGER -
// TIM1->DIER &= ~TIM_DIER_TIE;
// TIM1->DIER &= ~TIM_DIER_TDE;
/* HAL_TIM_PWM_ConfigChannel: HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) */
/* Disable the Channel 1: Reset the CC1E Bit */
// TIM1->CCER &= ~TIM_CCER_CC1E;
/* Reset the Output Compare Mode Bits */
TIM1->CCMR1 &= ~TIM_CCMR1_OC1M;
TIM1->CCMR1 &= ~TIM_CCMR1_CC1S;
/* Select the Output Compare (OC) Mode 1 */
TIM1->CCMR1 |= (TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1); // = TIM_OCMODE_PWM1
/* Reset and set the Output N Polarity level to LOW */
TIM1->CCER &= ~TIM_CCER_CC1P;
TIM1->CCER |= TIM_CCER_CC1P; // = TIM_OCPOLARITY_LOW
/* Reset the Output N State */
// TIM1->CCER &= ~TIM_CCER_CC1NP;
//TIM1->CCER |= 0x00000000U;
/* Reset the Output N State */
// TIM1->CCER &= ~TIM_CCER_CC1NE;
/* IS_TIM_BREAK_INSTANCE */
/* Reset the Output Compare and Output Compare N IDLE State */
// TIM1->CR2 &= ~TIM_CR2_OIS1;
// TIM1->CR2 &= ~TIM_CR2_OIS1N;
/* Set the Output Idle state */
//TIM1->CR2 |= 0x00000000U;
/* Set the Capture Compare Register: Pulse */
TIM1->CCR1 = 40000;
/* Set the Preload enable bit for channel 1 */
TIM1->CCMR1 |= TIM_CCMR1_OC1PE;
/* Configure the Output Fast mode */
// TIM1->CCMR1 &= ~TIM_CCMR1_OC1FE;
//TIM1->CCMR1 |= 0x00000000U;
/* Edited registers by HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1) */
/* Enable the Capture compare channel */
TIM1->CCER |= (1 << 0); // = TIM_CCER_CC1E
/* Enable the main output */
TIM1->BDTR |= TIM_BDTR_MOE;
/* Initialize the GPIO Pin for output: HAL_TIM_MspPostInit(&htim1) */
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_8;
GPIO_InitStruct.Pin = GPIO_PIN_8;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF1_TIM1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* Enable Counter: will be automatically enabled with trigger event */
//TIM1->CR1 = TIM_CR1_CEN;
}
Next step is to configure a second slave timer (TIM3) that will edit the registers of TIM1.
static void Timer3_Init(){
/* activate clock for TIM1 peripheral */
__HAL_RCC_TIM3_CLK_ENABLE();
/* Edited Registers of HAL_TIM_Base_Init(&htim1) */
/* Prescaler */
TIM3->PSC = 50000; //44999;
/* set counter mode */
TIM3->CR1 &= ~(TIM_CR1_DIR | TIM_CR1_CMS);
TIM3->CR1 |= TIM_COUNTERMODE_UP;
/* Auto-Reload-Register */
TIM3->ARR = 11000;
TIM3->CR1 &= ~ TIM_CR1_CKD;
TIM3->CR1 |= TIM_CLOCKDIVISION_DIV1;
/* update event */
TIM3->EGR = TIM_EGR_UG;
/* Edited registers of HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) */
TIM3->SMCR &= ~(TIM_SMCR_SMS | TIM_SMCR_TS | TIM_SMCR_ETF | TIM_SMCR_ETPS | TIM_SMCR_ECE | TIM_SMCR_ETP);
/* One Pulse Mode: Edited registers of HAL_TIM_OnePulse_Init(&htim1, TIM_OPMODE_SINGLE) */
//TIM1->CR1 &= ~TIM_CR1_OPM;
TIM3->CR1 |= TIM_CR1_OPM;
/* Slave Mode configuration: edited registers of HAL_TIM_SlaveConfigSynchro(&htim1, &sSlaveConfig) */
TIM3->SMCR &= ~TIM_SMCR_TS;
TIM3->SMCR |= TIM_TS_ITR1;
TIM3->SMCR &= ~TIM_SMCR_SMS;
TIM3->SMCR |= (TIM_SMCR_SMS_2 | TIM_SMCR_SMS_1); // = TIM_SLAVEMODE_TRIGGER
/* HAL_TIM_PWM_ConfigChannel: HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) */
/* Disable the Channel 1: Reset the CC1E Bit */
/* Reset the Output Compare Mode Bits */
TIM3->CCMR1 &= ~TIM_CCMR1_OC1M;
TIM3->CCMR1 &= ~TIM_CCMR1_CC1S;
/* Select the Output Compare (OC) Mode 1 */
TIM3->CCMR1 |= (TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1); // = TIM_OCMODE_PWM1
/* Reset and set the Output N Polarity level to HIGH */
TIM3->CCER &= ~TIM_CCER_CC1P; // = TIM_OCPOLARITY_HIGH
/* Set the Capture Compare Register: Pulse */
TIM3->CCR1 = 0;
/* Set the Preload enable bit for channel 1 */
//TIM3->CCMR1 |= TIM_CCMR1_OC1PE;
HAL_NVIC_SetPriority(TIM3_IRQn, 0, 1);
HAL_NVIC_EnableIRQ(TIM3_IRQn);
TIM3->DIER = TIM_DIER_CC1IE; //DMA Interrupt Enable Register (DIER): Interrupt "Capture/Compare 1 interrupt enable"
/* warning: setting this bit will cause the timer running continuously, but timer should only start with trigger,
* so don't set the CEN bit - let the trigger do the job automatically */
//TIM3->CR1 = TIM_CR1_CEN;
}
And finally the IRQ Handler for TIM3:
void TIM3_IRQHandler(void)
{
if (((TIM3->SR & TIM_FLAG_CC1) == TIM_FLAG_CC1) != RESET)
{
if (((TIM3->DIER & TIM_DIER_CC1IE) == TIM_DIER_CC1IE) != RESET)
{
TIM3->SR = ~ TIM_FLAG_CC1;
/* do something *
}
}
}
I'm happy for any feedback about this code.
I just noticed that the internal RC oscillator is not very accurate at my test environment. In the manual DM00135183.pdf in section "6.2.2 HSI Clock" you can read about the accuracy and how to trim the HSI. But I think it might be better to use an external crystal oscillator or ceramic resonator if you want more accurate timing.
If there is anything I did wrong or what I want to do will not work in the expected way, please also leave a comment.

STM32L152 UART baudrate halfes using HSE

I'm trying to configure the baudrate of USART1 on an STM32L152. When using the external Clock the baudrate is half of what I configured (e.g. 57600 instead of 115200). However, when using the internal HSI everything is correct. The internal is 16 MHz and the external is an 8 MHz crystal that is used to drive the PLL for a 32 MHz system clock.
This is the RCC init code, which is pretty much standard I guess.
int RCC_Configuration(void)
{
/* DISABLE HSI and target clocks prior to clock config */
RCC_HSICmd(DISABLE);
RCC_PLLCmd(DISABLE);
RCC_HSEConfig(RCC_HSE_OFF);
/* Set HSE as sys clock*/
RCC_SYSCLKConfig(RCC_SYSCLKSource_HSE);
/* Enable ADC & SYSCFG clocks */
RCC_APB2Periph_SYSCFG , ENABLE);
/* Allow access to the RTC */
PWR_RTCAccessCmd(ENABLE);
/* Reset RTC Backup Domain */
RCC_RTCResetCmd(ENABLE);
RCC_RTCResetCmd(DISABLE);
/* LSI used as RTC source clock */
/* The RTC Clock may varies due to LSI frequency dispersion. */
/* Enable the LSI OSC */
RCC_LSICmd(ENABLE);
/* Wait until LSE is ready */
while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET);
/* Select the RTC Clock Source */
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
/* Enable the RTC */
RCC_RTCCLKCmd(ENABLE);
/* Wait for RTC APB registers synchronisation */
RTC_WaitForSynchro();
// ENABLE HSE
RCC_HSEConfig(RCC_HSE_ON);
ErrorStatus HSEStartUpStatus = RCC_WaitForHSEStartUp();
if(HSEStartUpStatus == SUCCESS)
{
/* 32Mhz = 8Mhz * 12 / 3 */
RCC_PLLConfig(RCC_PLLSource_HSE, RCC_PLLMul_12, RCC_PLLDiv_3);
/* Enable PLL */
RCC_PLLCmd(ENABLE);
/* Wait till PLL is ready */
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
{
}
/* Select PLL as system clock source */
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
/* Wait till PLL is used as system clock source */
while(RCC_GetSYSCLKSource() != 0x0C) // 0x0C = PLL
{
}
/* Enable the PWR clock */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
PWR->CR = PWR_CR_VOS_0; /* Select the Voltage Range 1 (1.8V) */
while((PWR->CSR & PWR_CSR_VOSF) != 0); /* Wait for Voltage Regulator Ready */
/* HCLK = SYSCLK */
RCC_HCLKConfig(RCC_SYSCLK_Div1);
/* PCLK1 = HCLK/2 */
RCC_PCLK1Config(RCC_HCLK_Div2);
/* PCLK2 = HCLK */
RCC_PCLK2Config(RCC_HCLK_Div1);
/* Enable the GPIOs clocks */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA | RCC_AHBPeriph_GPIOB | RCC_AHBPeriph_GPIOC| RCC_AHBPeriph_GPIOD| RCC_AHBPeriph_GPIOE| RCC_AHBPeriph_GPIOH, ENABLE);
/* Enable comparator, LCD and PWR mngt clocks */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_COMP | RCC_APB1Periph_LCD | RCC_APB1Periph_PWR,ENABLE);
}
return 0;
}
I'm using STDperiph to configure the UART1, which on this mcu will run on PCLK2. Checked all the init methods and the register contents. The mantissa and fraction of the baudrate register are correctly calculated and should yield the correct baud rate no matter what the PCLK value is.
This is the UART init code:
void usartinit(void)
{
USART_InitTypeDef USART_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitStructure.USART_BaudRate = 115200 ;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
/* Enable GPIO clock */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
GPIO_PinAFConfig(USARTx_GPIO, GPIO_PinSource9, GPIO_AF_USART1);
GPIO_PinAFConfig(USARTx_GPIO, GPIO_PinSource10, GPIO_AF_USART1);
/* Configure USART Tx as alternate function push-pull */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Pin = USARTx_TX;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_40MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(USARTx_GPIO, &GPIO_InitStructure);
/* Configure USART Rx as input floating */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Pin = USARTx_RX;
GPIO_Init(USARTx_GPIO, &GPIO_InitStructure);
/* USART configuration */
USART_Init(USART1, &USART_InitStructure);
/* Enable USART */
USART_Cmd(USART1, ENABLE);
}
The only possibility I can think of right now is that the crystal is just 4 MHz, but this is a Nucleo board and the MCO from the attached STLink is used for HSE, which definitely is 8 MHz.
What's the blatant mistake I'm making?
It seems the clock is messed up. Check the HSE_VALUE macro in your code. That might be using default Dev board crystal value. I would suggest to change that value to the crystal you are using. You can use this link to set the clock speed.
I think the previous answer is correct. When using HSI your system clock is 16MHz, whereas when using HSE you system clock is 32MHz.
I suspect HSE value is set to 16MHz.
You could also test this by setting the multiplier to 4 and the divider to 2 so that the system clock is 16MHz when running the HSE.
The HSE value will be in the startup code somewhere.
The value is used by the USART code so that it knows what frequency the USART is being driven with in order to calculate the baud rate.
Ok, finally figured it out. On the Nucleo boards in the default configuration, the HSE clock is connected to the MCO clock output of the STLink Programmer on the board. On multiple of my boards however this clock signal gets distorted so much that the target uC only sees 4 MHz. If I output the HSE on the MCO of the target it produces a 4 MHz square wave with a weird duty cycle of 75%. When probing the MCO input signal with a scope the probe capacitance is sufficent to produce the correct 8 MHz input.
So, I guess don't trust your eval boards... Will now get a few crystals and populate the "real" external clock on those boards.

Kinetis KEA: Frequency of LED toggling for the timer interrupt generated

I am using a Kinetis KEA64 microcontroller from NXP.
The actual frequency of clock is 20 MHz, and a timer interrupt is generated at every 2.5ms. I have an interrupt handler that toggles an LED when this timer interrupt is generated. LED is toggling on this timer interrupt but i dont know exactly the frequency of LED. Does my LED toggles at 5kHz? Is it correct?
void interrupt_application_timer_FTM0()
{
SIM_SCGC |= SIM_SCGC_FTM0_MASK; /* Enable Clock for FTM0 */
FTM0_SC |= FTM_SC_PS(7); /* Select Preescaler in this case 128. 20 Mhz /128 =156.25 Khz. */
/* Counter increase by one every 6.4 us */
/* Enable Channle 0*/
FTM0_C0SC |= FTM_CnSC_CHIE_MASK; /* Enable channel 0 interrupt */
FTM0_C0SC |= FTM_CnSC_MSA_MASK; /* Channel as Output compare mode */
/*Select interrupt frequency*/
FTM0_C0V = FTM_CnV_VAL(391) ; /* Interrupt every 2.5ms */
FTM0_SC |= FTM_SC_CLKS(1); /*FTM0 use system clock*/
/* Set the ICPR and ISER registers accordingly */
NVIC_ICPR |= 1 << ((INT_FTM0-16)%32);
NVIC_ISER |= 1 << ((INT_FTM0-16)%32);
}
Here is my interrupt handler
void FTM0_IRQHandler()
{
if (1==((FTM0_C0SC & FTM_CnSC_CHF_MASK)>>FTM_CnSC_CHF_SHIFT) ) /* If the CHF of the channel is equal to 0 */
{
(void)FTM0_C0SC; /* Read to clear flag */
FTM0_C0SC ^= FTM_CnSC_CHF_MASK; /* Clear flag */
FTM0_C0V = FTM0_C0V + 391 ; /* Refresh interrupt period */
if (LED_counter>=50){
/* Toggle LED */
/* Reset counter */
LED0_TOGGLE;
LED_counter = 0;
}
LED_counter++;
}
}
Use scope for frequency measuring
In the MCU, you can enable bus clock to one pin (Busclockout), enable that and check the bus clock so that you can confirm your calculations
Then use scope at LED to confirm your frequency

Getting uptime from RTC

I wanted to get uptime of the system from the RTC in seconds. The point is that while I can sum up values from the RTC time register (RTC_TR) it only works up to 24 hours and then overflows while one day is being added to RTC date register (RTC_DR).
How do I count seconds from the time I start up the system? I don't need the calendar.
Below the explaination of what do I mean by "overflow"
I've configured RTC according to STM's RTC_LSI example for StdPeriph and set only the time and not the date.
However when I get the time from RTC_TR using RTC_GetTime function, after 23h59m59s, the time goes back to 0h0m0s.
Of course RTC_TR holds time in its BCD format in tens and units of current hour, minute and second and days are counted in RTC_DR. Anyway I'd like it to keep on adding hours and not to add the days to the date register as I want to calculate only uptime and I'm afraid that if I started counting the months and days I'd have problems.
void RtcConfig(void)
{
RTC_InitTypeDef RTC_InitStructure;
RTC_TimeTypeDef RTC_TimeStructure;
RTC_DateTypeDef RTC_DateStructure;
uint32_t LSIFreq = 0;
/* Enable the PWR clock */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
/* Allow access to Backup Domain */
PWR_BackupAccessCmd(ENABLE);
/* Disable wake-up source(ALARM) to guarantee free access to WUT level-OR input */
RTC_ITConfig(RTC_IT_ALRA, DISABLE);
/* Clear Wakeup flag */
PWR_ClearFlag(PWR_FLAG_WU);
/* Enable wake-up source(ALARM) to guarantee free access to WUT level-OR input */
RTC_ITConfig(RTC_IT_ALRA, ENABLE);
/* Enable the LSI OSC */
RCC_LSICmd(ENABLE);
/* Wait till LSI is ready */
while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET)
{}
/* Check if the StandBy flag is set (leaving stand-by) */
if (PWR_GetFlagStatus(PWR_FLAG_SB) != RESET)
{
/* Clear StandBy flag */
PWR_ClearFlag(PWR_FLAG_SB);
/* Check if the StandBy flag is cleared */
if (PWR_GetFlagStatus(PWR_FLAG_SB) != RESET)
{
while(1);
}
RTC_WaitForSynchro();
/* No need to configure the RTC as the RTC config(clock source, enable,
prescaler,...) are kept after wake-up from STANDBY */
}
else
{
/* RTC Configuration ******************************************************/
/* Reset Backup Domain */
RCC_BackupResetCmd(ENABLE);
RCC_BackupResetCmd(DISABLE);
/* Select the RTC Clock Source */
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
/* Enable the RTC Clock */
RCC_RTCCLKCmd(ENABLE);
/* Wait for RTC APB registers synchronisation */
RTC_WaitForSynchro();
/* Get the LSI frequency: TIM14 is used to measure the LSI frequency */
LSIFreq = GetLSIFrequency();
RTC_InitStructure.RTC_HourFormat = RTC_HourFormat_24;
RTC_InitStructure.RTC_AsynchPrediv = 99;
RTC_InitStructure.RTC_SynchPrediv = (LSIFreq/100) - 1;
RTC_Init(&RTC_InitStructure);
/* Set the time to 00h 00mn 00s AM */
RTC_TimeStructure.RTC_H12 = RTC_H12_PM;
RTC_TimeStructure.RTC_Hours = 0;
RTC_TimeStructure.RTC_Minutes = 0;
RTC_TimeStructure.RTC_Seconds = 0;
RTC_SetTime(RTC_Format_BIN, &RTC_TimeStructure);
}
}
uint32 GetLSIFrequency(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
RCC_ClocksTypeDef RCC_ClockFreq;
/* TIM14 configuration *******************************************************/
/* Enable TIM14 clock */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14, ENABLE);
/* Reset TIM14 registers */
TIM_DeInit(TIM14);
/* Configure TIM14 prescaler */
TIM_PrescalerConfig(TIM14, 0, TIM_PSCReloadMode_Immediate);
/* Connect internally the TIM14_CH1 to the RTC clock output */
TIM_RemapConfig(TIM14, TIM14_RTC_CLK);
/* TIM14 configuration: Input Capture mode ---------------------
The reference clock(LSE or external) is connected to TIM14 CH1
The Rising edge is used as active edge,
The TIM14 CCR1 is used to compute the frequency value
------------------------------------------------------------ */
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV8;
TIM_ICInitStructure.TIM_ICFilter = 0x0;
TIM_ICInit(TIM14, &TIM_ICInitStructure);
/* Enable the TIM14 global Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = TIM14_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/* Enable TIM14 counter */
TIM_Cmd(TIM14, ENABLE);
/* Reset the flags */
TIM14->SR = 0;
/* Enable the CC1 Interrupt Request */
TIM_ITConfig(TIM14, TIM_IT_CC1, ENABLE);
/* Wait until the TIM14 get 2 LSI edges (refer to TIM14_IRQHandler() in
stm32F0xx_it.c file) ******************************************************/
while(CaptureNumber != 2)
{
}
/* Deinitialize the TIM14 peripheral registers to their default reset values */
TIM_DeInit(TIM14);
/* Compute the LSI frequency, depending on TIM14 input clock frequency (PCLK1)*/
/* Get SYSCLK, HCLK and PCLKx frequency */
RCC_GetClocksFreq(&RCC_ClockFreq);
/* Disable TIM14 counter */
TIM_Cmd(TIM14, DISABLE);
TIM_ITConfig(TIM14, TIM_IT_CC1, DISABLE);
/* PCLK1 prescaler equal to 1 => TIMCLK = PCLK1 */
return ((RCC_ClockFreq.PCLK_Frequency / PeriodValue) * 8);
}
void RTC_GetTime(uint32_t RTC_Format, RTC_TimeTypeDef* RTC_TimeStruct)
{
uint32_t tmpreg = 0;
/* Check the parameters */
assert_param(IS_RTC_FORMAT(RTC_Format));
/* Get the RTC_TR register */
tmpreg = (uint32_t)(RTC->TR & RTC_TR_RESERVED_MASK);
/* Fill the structure fields with the read parameters */
RTC_TimeStruct->RTC_Hours = (uint8_t)((tmpreg & (RTC_TR_HT | RTC_TR_HU)) >> 16);
RTC_TimeStruct->RTC_Minutes = (uint8_t)((tmpreg & (RTC_TR_MNT | RTC_TR_MNU)) >>8);
RTC_TimeStruct->RTC_Seconds = (uint8_t)(tmpreg & (RTC_TR_ST | RTC_TR_SU));
RTC_TimeStruct->RTC_H12 = (uint8_t)((tmpreg & (RTC_TR_PM)) >> 16);
/* Check the input parameters format */
if (RTC_Format == RTC_Format_BIN)
{
/* Convert the structure parameters to Binary format */
RTC_TimeStruct->RTC_Hours = (uint8_t)RTC_Bcd2ToByte(RTC_TimeStruct->RTC_Hours);
RTC_TimeStruct->RTC_Minutes = (uint8_t)RTC_Bcd2ToByte(RTC_TimeStruct->RTC_Minutes);
RTC_TimeStruct->RTC_Seconds = (uint8_t)RTC_Bcd2ToByte(RTC_TimeStruct->RTC_Seconds);
}
}
uint32 RtcGetTimeSec(void)
{
RTC_TimeTypeDef RTC_TimeStructure;
uint32 currenttimesec = 0;
/* Get the Current time in second */
RTC_GetTime(RTC_Format_BIN, &RTC_TimeStructure);
currenttimesec = ((RTC_TimeStructure.RTC_Hours * 3600) +(RTC_TimeStructure.RTC_Minutes * 60) +
RTC_TimeStructure.RTC_Seconds);
return currenttimesec;
}
What does it mean overflows. Show your code & maths
In 32bits you can store:
Seconds Hours Days Years
4294967295 1193046.471 49710.26962 136.1925195
If your predicted up-time is more than 136.2 years use 64bit unsigned integer and you wil be able to count up to:
Seconds Hours Days Years Decades Centuries Millenniums Aeons (10e9 years)
18446744073709600000 5124095576030430 213503982334601 584942417355 58494241736 5849424174 584942417 585
Hope that will be enough yor you.

Clock configuration of RTC in Stm32L in LSI/LSE/HSE only?

I am implementing Real Time Clock on STM32L152RB Discovery board using IAR compiler. I have implemented the Clock configuration on HSI and using PLL I have multiplied it by 4. Code -->
/* Enable HSI Clock */
RCC_HSICmd(ENABLE);
/*!< Wait till HSI is ready */
while (RCC_GetFlagStatus(RCC_FLAG_HSIRDY) == RESET);
RCC_PLLConfig(RCC_PLLSource_HSI,RCC_PLLMul_4,RCC_PLLDiv_2);
RCC_PLLCmd(ENABLE);
while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
/* Set HSI as sys clock*/
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
The problem is while configuring Real Time clock I have to set the secondary clock LSE as the RTC Clock source, which in my case my source clock is HSI. Rest of the steps which includes enable PWR controller, enable rtc domain access, rtc clock source, rtc_init(), then settime and gettime, are alright as per I know. Here is the code I tried -->
/* Enable RTC clocks and rtc related functions */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
PWR_RTCAccessCmd(ENABLE);
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); //This part I think is wrong
RCC_RTCCLKCmd(ENABLE);
RTC_InitTypeStructure.RTC_HourFormat=RTC_HourFormat_12;
RTC_InitTypeStructure.RTC_AsynchPrediv=0x7F;
RTC_InitTypeStructure.RTC_SynchPrediv=0xFF;
RTC_Init(&RTC_InitTypeStructure);
/* End RTC Clock */
RTC_TimeTypeTime.RTC_Hours=18;
RTC_TimeTypeTime.RTC_Minutes=11;
RTC_TimeTypeTime.RTC_Seconds=4;
RTC_TimeTypeTime.RTC_H12=RTC_H12_PM;
RTC_SetTime(RTC_Format_BIN, &RTC_TimeTypeTime);
while(1){
f_SleepMs(10);
RTC_GetTime(RTC_Format_BIN, &RTC_TimeTypeTime);
RELEASE_MSG("\r%d:%d:%d",RTC_TimeTypeTime.RTC_Hours,RTC_TimeTypeTime.RTC_Minutes,RTC_TimeTypeTime.RTC_Seconds);
}
Output I get is 0:0:0
Solved doing this,
/* Allow access to the RTC */
PWR_RTCAccessCmd(ENABLE);
/* Reset RTC Backup Domain */
RCC_RTCResetCmd(ENABLE);
RCC_RTCResetCmd(DISABLE);
/* LSE Enable */
RCC_LSEConfig(RCC_LSE_ON);
/* Wait until LSE is ready */
while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET);
/* RTC Clock Source Selection */
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
/* Enable the RTC */
RCC_RTCCLKCmd(ENABLE);
LSE can only work with External Crystal or oscillator. For internal crystal LSI can be used.
I can confirm that this works for the STM32F051 (STM32F0Discovery):
RTC_InitTypeDef R;
RTC_TimeTypeDef T;
// Enable PWR clock
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
/* Enable the Backup Domain Access */
PWR_BackupAccessCmd(ENABLE);
/* Disable RTC clock */
RCC_RTCCLKCmd(DISABLE);
/* Enable RTC clock */
RCC_RTCCLKCmd(ENABLE);
RCC_LSEDriveConfig(RCC_LSEDrive_High); // i think this is optional
/* LSE Enable */
RCC_LSEConfig(RCC_LSE_ON);
/* Wait until the LSE crystal is ready */
while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET){
}
/* Set RTC clock source to LSE */
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
R.RTC_AsynchPrediv = 0x7F;
R.RTC_SynchPrediv = 0xFF;
/* Enable RTC clock */
RCC_RTCCLKCmd(ENABLE);
/* Waits until the RTC Time and Date registers are synchronized with RTC APB clock.*/
RTC_WaitForSynchro();
/* Set hour format to 24hrs */
R.RTC_HourFormat = RTC_HourFormat_24;
/* initialize the RTC */
if (RTC_Init(&R) == ERROR){
printf("RTC init failed \r\n");
}
printf("RTC done. \r\n");
while(1){
RTC_GetTime(RTC_Format_BIN, &T);
printf("the time is %02d : %02d : %02d \r\n", T.RTC_Hours, T.RTC_Minutes, T.RTC_Seconds);
}

Resources