cancel
Showing results for 
Search instead for 
Did you mean: 

STM32f103 and measuring of LSI frequency

sh-m_news4
Associate
Posted on January 10, 2016 at 02:45

Hello,

I'm trying to use LSI for RTC, but can't calculate correct prescaler value for RTC. And for each time I got different results(~+/-15sec. for each 2minutes), when test it.

I found note in Reference manual (7.2.5 LSI clock Note) for STM32F103C8T6 that said: LSI measuring is only available for high-density, XL-density and connectivity line devices.

Is exist some possibility to measuring of LSI frequency for STM32F103C8T6, for use this value to calculate RTC prescaler?

Code for configure RTS with LIS:

RCC->

APB1ENR

|= RCC_APB1ENR_BKPEN | RCC_APB1ENR_PWREN;

//Enable the APB1 backup domain and power

PWR->

CR

|= PWR_CR_DBP;

//Enable access to backup domain

RCC->

CSR

|= RCC_CSR_LSION;

//LSI 40k oscillator enabled

while

((RCC->

CSR

& RCC_CSR_LSIRDY) == 0);

//LSI ready

RCC->

BDCR

|= RCC_BDCR_RTCSEL_LSI;

//Select LSE as the RTC clock source

RCC->

BDCR

|= RCC_BDCR_RTCEN;

//Enable the RTC clock

wait_sync

();

//Poll the RSF bit in the RTC_CRL register until the RTC registers are synchronized

RTC->

CRL

&= ~RTC_CRL_RTOFF;

wait_ready

();

//Poll the RTOFF bit in the RTC_CRL register until the last operation on the RTC registers is over

/*

RTC->CRH |= RTC_CRH_SECIE;

NVIC->ISER[0] = NVIC_ISER_SETENA_3;

NVIC->IABR[0] |= NVIC_IABR_ACTIVE_3;

*/

RTC->

CRH

&= ~RTC_CRH_SECIE;

RTC->

CRH

&= ~RTC_CRH_OWIE;

RTC->

CRH

&= ~RTC_CRH_ALRIE;

RTC->

CRL

|= RTC_CRL_CNF;

//enter into RTC configuration mode

RTC->

PRLH

= 0;

RTC->

PRLL

= 40000-1;

//set iterations count for 1 second, LSI = 40k(39.967Hz)

RTC->

CNTH

= 0x0000;

//reset RTC value

RTC->

CNTL

= 0x0000;

//reset RTC value

RTC->

CRL

&= ~RTC_CRL_CNF;

//exit form RTC configuration mode

while

((RCC->

BDCR

& RCC_BDCR_RTCEN) != RCC_BDCR_RTCEN);

PWR->

CR

&= ~PWR_CR_DBP;

// disable access to RTC registers

#rcc_bdcr_rtcen #stm32f103c8t6 #dwt->cyccnt
5 REPLIES 5
Posted on January 10, 2016 at 04:13

Later STM32 designs make it easier. Perhaps you can loop it externally via MCO (PA8) to a timer and measure against HSE.

You could also use a 32-bit counter like DWT_CYCCNT, and time stamp the RTC 1 Hz with nominal settings, and then tune the base on that estimate.

Seem to remember some of mine being closer to 37 KHz

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
matic
Associate III
Posted on January 10, 2016 at 08:21

Unfortunately, only SYSCLK, HSE, HSI and PLLCLK/2 are connected to MCO on STM32F103C8.

Posted on January 10, 2016 at 15:08

May be I'm thinking of the RTC TAMPER pin...

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
sh-m_news4
Associate
Posted on January 11, 2016 at 14:07

Thanks clive1,

I'm using DWT_CYCCNT for calculate LSI frequency on first RTC init. But this method is uncomfortable and complicated for using it few times. For my STM32F103C8, LSI works on ~969kHz(sometime: 940kHz-260kHz). I review docs(Ref. manual and AN2604) about TAMPER(PC13) calibration. But I do not found any information where stored TAMPER value, and how get this value after BKP->RTCCR |= BKP_RTCCR_CCO flag was set. Hire is code on DWT counter:


#define HSI_CLOCK_FREQUENCY 16000000

#define RTC_CALIBRATION_DIVIDER 25

#define RTC_CALIBRATION_CYC_COUNT HSI_CLOCK_FREQUENCY/RTC_CALIBRATION_DIVIDER


void
setupHSI() {

RCC->CR |= RCC_CR_HSION; 
//Enable HSI

while
((RCC_CR_HSIRDY)==0); 
//Wait HSI stabilization

RCC->CFGR |= RCC_CFGR_SW_HSI; 
//HSI selected as system clock

RCC->CFGR |= RCC_CFGR_SWS_HSI; 
//HSI oscillator used as system clock

while
((RCC_CR_HSIRDY)==0); 
//Wait HSI stabilization

}



void
setPeriodAndClearCounter(uint32_t period) {

if
(60000<period)period=60000;

RTC->CRL |= RTC_CRL_CNF; 
//enter into RTC configuration mode

RTC->PRLH = period >> 16;

RTC->PRLL = period; 
//set period for RTC counter incrementation

RTC->CNTH = RTC->CNTL = 0; 
//reset RTC counter value

RTC->CRL &= ~RTC_CRL_CNF; 
//exit form RTC configuration mode

}


void
calibrate() {

uint32_t cycCnt, rtcValue;

CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; 
//enable dwt counter

DWT->CYCCNT = 0; 
//reset dwt counter

DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; 
//start dwt counter

setPeriodAndClearCounter(1);


while
((cycCnt=DWT->CYCCNT) <= RTC_CALIBRATION_CYC_COUNT); 
//repeats count = 16MHz/25 = 640k

rtcValue = ((RTC->CNTH << 16) | RTC->CNTL); 
//read RTC counter value


DWT->CTRL &= ~DWT_CTRL_CYCCNTENA_Msk; 
//stop dwt counter

CoreDebug->DEMCR &= ~CoreDebug_DEMCR_TRCENA_Msk; 
//disable dwt counter


setPeriodAndClearCounter(rtcValue*RTC_CALIBRATION_DIVIDER); 
//calculate LSI speed RTC result * 25 and set RTC deriver

}

Posted on January 11, 2016 at 18:23

I might approach that a bit differently, but the LSI clock is not at all stable, and you have very little control over the temperature/voltage

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..