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);
}
Related
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;
}
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.
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
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.
I am new to the processor STM32F107. I have to read the input value from an external source that is a balance. This balance is external to the board that contains the processor and communicates with it via PA4.
What I have to do to read the analogue input from the balance?
Here is my first attempt to read the input from the balance.
I use this function to setup the ADC:
void ADC_Configuration(void) {
ADC_InitTypeDef ADC_InitStructure;
/* PCLK2 is the APB2 clock */
/* ADCCLK = PCLK2/6 = 72/6 = 12MHz*/
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
/* Enable ADC1 clock so that we can talk to it */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
/* Put everything back to power-on defaults */
ADC_DeInit(ADC1);
/* ADC1 Configuration ------------------------------------------------------*/
/* ADC1 and ADC2 operate independently */
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
/* Disable the scan conversion so we do one at a time */
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
/* Don't do contimuous conversions - do them on demand */
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
/* Start conversin by software, not an external trigger */
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
/* Conversions are 12 bit - put them in the lower 12 bits of the result */
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
/* Say how many channels would be used by the sequencer */
ADC_InitStructure.ADC_NbrOfChannel = 1;
/* Now do the setup */ ADC_Init(ADC1, &ADC_InitStructure);
/* Enable ADC1 */ ADC_Cmd(ADC1, ENABLE);
/* Enable ADC1 reset calibaration register */
ADC_ResetCalibration(ADC1);
/* Check the end of ADC1 reset calibration register */
while(ADC_GetResetCalibrationStatus(ADC1));
/* Start ADC1 calibaration */
ADC_StartCalibration(ADC1);
/* Check the end of ADC1 calibration */
while(ADC_GetCalibrationStatus(ADC1));
}
And I use this function to get the input:
u16 readADC1(u8 channel) {
ADC_RegularChannelConfig(ADC1, channel, 1, ADC_SampleTime_1Cycles5);
// Start the conversion
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
// Wait until conversion completion
while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
// Get the conversion value
return ADC_GetConversionValue(ADC1);
}
The problem is that in N measurements of the same weight, I get N different results.
For example, the weight is 70kg and the output of the readADC1(ADC_Channel_4) is 715,760,748,711,759 etc.
What am I doing wrong?
The balance has a load cell inside it, which generates an analog voltage. The processor on the balance is some how not utilized (i assume this as not much details are present in your question).
The stm32 f107 controller has an on-chip ADC (analog to digital convertor). Connect the output of load cell (analog signal coming from balance) to the analog input pin of stm32 f107. Configure the ADC to sample and convert the analog signal into digital (use the example code as reference to write the software).
PA4 is multiplexed with ADC12_IN4 (an analogue input that can itself be mapped to channel 4 on either ADC1 or ADC2).
Programming the ADC, selecting the correct peripheral clocking and mapping multiplexed pins on STM32 is somewhat complex, but I strongly suggest that you utilise the STM32F10x Standard Peripheral Library which provides an API for all STM32F10x peripherals as well as numerous examples of how to use the library, including ADC examples.
The ADC itself may be polled, interrupt driven, use DMA, and be software triggered or free-running, self-clocked or clocked from a timer peripheral. The options are numerous, only some combinations are covered by the example code, but it is a good place to start nonetheless. To understand all the options and how to use them with the Standard Peripheral Library, you will need a fairly thorough understanding of the Reference Manual.
Another resource you may find useful is STM's MicroXplorer. This allows visual configuration and allocation of multiplexed pins and generates source code you can use directly.
Furthermore you may need some hardware signal conditioning at the input to ensure that the input is within the valid and tolerable range of the ADC input.