Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Правильность отсчета времени в таймере и RTC
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
dimon_rub
Здравствуйте. Прошу помощи по следующим вопросам.
1. Во всех примерах пределитель на RTC необходимо ставить 32767 при внешнем кварце на 32768. Когда ставится данный пределитель часы считают очень медленно 1 секунда где то в 10-15мин. Начал изменять путем подбора вышел на значение пределителя где то 32. ЧТО ЭТО ЗНАЧИТ.
2. В таймере то же какой то глючек. Может ошибка общая с 1 пунктом. Частота шины 36МГц. Опрашивается через функцию RCC_GetClocksFreq. Ставлю пределитель 36000 и счет до 1000 прерывание срабатывает гораздо раньше.

Контроллер STM32F103RC. 16МГц кварц, на RTC кварц 32768.

P.S. Нет источника питания. Питание контроллера взято с ST-Link V2.
Obam
2 в 32-ой степени ни на что не намекает?
Pridnya
Цитата(dimon_rub @ Oct 7 2016, 11:04) *
Здравствуйте. Прошу помощи по следующим вопросам.
1. Во всех примерах пределитель на RTC необходимо ставить 32767 при внешнем кварце на 32768. Когда ставится данный пределитель часы считают очень медленно 1 секунда где то в 10-15мин. Начал изменять путем подбора вышел на значение предlелителя где то 32. ЧТО ЭТО ЗНАЧИТ.

Контроллер STM32F103RC. 16МГц кварц, на RTC кварц 32768.

Это значит, что у вас ошибка в коде. Если кварц на 32768 Гц, то значение предделителя должно быть 32768, что приводит к ежесекундному увеличению времени на 1 секунду.
PS: Вы хотя бы код инициализации модуля RTC выложили.
dimon_rub
Код инициализации:
Код
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP, ENABLE);

    /* LSI clock stabilization time */
    for(tmp=0;tmp<5000;tmp++) {; }

    if (BKP_ReadBackupRegister(RTC_CONSISTENCY_CHECK_REG) != RTC_CONSYSTENCY_KEY_VALUE) {
        PWR_BackupAccessCmd(ENABLE);
        BKP_DeInit();
        RCC_LSEConfig(RCC_LSE_ON);
        while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET) {; }
        RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
        RCC_RTCCLKCmd(ENABLE);
        RTC_WaitForSynchro();
        //RTC_SetPrescaler(32767); /* RTC period = RTCCLK/RTC_PR = (32.768 KHz)/(32767+1) */
        RTC->PRLL  = 0x7FFF;
        //RTC->PRLL  = 0x20;

        RTC_WaitForLastTask();
        RTC_ITConfig(RTC_IT_SEC, ENABLE);
        RTC_WaitForLastTask();
        BKP_WriteBackupRegister(RTC_CONSISTENCY_CHECK_REG, RTC_CONSYSTENCY_KEY_VALUE);
    } else {
        RTC_WaitForSynchro();
        RTC_ITConfig(RTC_IT_SEC, ENABLE);
        RTC_WaitForLastTask();
    }

Цитата(Obam @ Oct 7 2016, 08:19) *
2 в 32-ой степени ни на что не намекает?


Немного не понял что имелось ввиду
Obam
"…вышел на значение пределителя где то 32. ЧТО ЭТО ЗНАЧИТ."

Вот и пойми что имелось ввиду (;
SasaVitebsk
Цитата(dimon_rub @ Oct 7 2016, 11:04) *
Здравствуйте. Прошу помощи по следующим вопросам.
1. Во всех примерах пределитель на RTC необходимо ставить 32767 при внешнем кварце на 32768. Когда ставится данный пределитель часы считают очень медленно 1 секунда где то в 10-15мин. Начал изменять путем подбора вышел на значение пределителя где то 32. ЧТО ЭТО ЗНАЧИТ.
2. В таймере то же какой то глючек. Может ошибка общая с 1 пунктом.

Непонятно, что именно вы называете ошибкой. В таймере ошибки точно нет. Наверное она у вас в голове.
Если вам непонятно почему при кварце 32768 задаётся 32767, то тут стандартный подход. При задании 0 = делит 1:1. Иначе получится как в MSP430FR433 к примеру. При задании 0 и 1 делит на 1. При задании 65535 делит на 65535. Поделить на 65536 не получается, хотя таймер 16-ти битный. Вопрос: так в каком CPU косяк?
А реализуется эта фича просто. Сравнение производится после вычитания.
Задаётся предделитель как правило так:
TIM_PWM_LIGHT->PSC = FPWM_PSC-1; // Прескалер
TIM_PWM_LIGHT->ARR = FPWM_MAX-1; // Частота ШИМ 200 Гц

Цитата
Частота шины 36МГц. Опрашивается через функцию RCC_GetClocksFreq. Ставлю пределитель 36000 и счет до 1000 прерывание срабатывает гораздо раньше.
Контроллер STM32F103RC. 16МГц кварц, на RTC кварц 32768.

P.S. Нет источника питания. Питание контроллера взято с ST-Link V2.

Там, насколько я помню частота таймера в 2 раза выше чем частота шины к которой он подключен.

32768 = 2^15. То есть по сути 16-тый разряд двоичного счётчика. Вот на что вам намекали.
esaulenka
В RTC у STMа есть особенность, что они довольно критичны к качеству кварца. Точнее, к самому кварцу, его обвязке (в лице двух конденсаторов) и монтажу (количеству флюса вокруг).
В погоне за микропотреблением узел получился весьма нежным.

Можно вывести на ногу CLKOUT частоту кварца (подробности - в reference manual) и проверить осциллографом, что оно работает стабильно.
Напрямую в ноги часового кварца тыкать бесполезно - сразу же останавливается.

Очень похоже, что кварц постоянно останавливается-запускается.
Obam
Оп-па, вот что значит переключиться с 16-битки, не то что-то ляпнул ;(
dimon_rub
Цитата(esaulenka @ Oct 7 2016, 09:52) *
В RTC у STMа есть особенность, что они довольно критичны к качеству кварца. Точнее, к самому кварцу, его обвязке (в лице двух конденсаторов) и монтажу (количеству флюса вокруг).
В погоне за микропотреблением узел получился весьма нежным.

Можно вывести на ногу CLKOUT частоту кварца (подробности - в reference manual) и проверить осциллографом, что оно работает стабильно.
Напрямую в ноги часового кварца тыкать бесполезно - сразу же останавливается.

Очень похоже, что кварц постоянно останавливается-запускается.


Дело в том что пробовал поднять RTC на LSI. Ситуация та же. Изменение регистра счета происходит примерно через 10-15 мин

Инициализация таймера:
RCC_GetClocksFreq(&rcc_Clocks);

//Включается тактирование таймера TIM6
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6,ENABLE);
// Настраиваем делитель что таймер тикал 1000 раз в секунду (
TIM6->PSC = (rcc_Clocks.PCLK1_Frequency / 1000) - 1; //36000
// Чтоб прерывание случалось раз в секунду
TIM6->ARR = 1000 ;
//разрешаем прерывание от таймера
TIM6->DIER |= TIM_DIER_UIE;
// Начать отсчёт!
TIM6->CR1 |= TIM_CR1_CEN;
//Разрешение TIM6_DAC_IRQn прерывания
NVIC_EnableIRQ (TIM6_IRQn);

СКАЖИТЕ ПОЖАЛУЙСТА через какое время должно срабатывать прерывание
esaulenka
Код выглядит нормально.
Разве что, не очень понятно, что содержится в rcc_Clocks. Можно легко и просто испортить дефайны, чтобы там оказалось что-то не то.

Единственное замечание: у STM'ок есть кэширование регистррв таймера (в т.ч. ARR). Чтобы принудительно его обновить, надо сделать TIMx->EGR = TIM_EGR_UG;


PS дурацкий вопрос: это точно STM32F103 ? Не китаец? ;-)
dimon_rub
Цитата(esaulenka @ Oct 7 2016, 13:42) *
Код выглядит нормально.
Разве что, не очень понятно, что содержится в rcc_Clocks. Можно легко и просто испортить дефайны, чтобы там оказалось что-то не то.



Единственное замечание: у STM'ок есть кэширование регистррв таймера (в т.ч. ARR). Чтобы принудительно его обновить, надо сделать TIMx->EGR = TIM_EGR_UG;

Спасибо попробую.


PS дурацкий вопрос: это точно STM32F103 ? Не китаец? ;-)


RCC_ClocksTypeDef rcc_Clocks;

Поднял RTC на LSI. На LSE не как не хочет. Совсем начал зависать наверно действительно что то с кварцом. На SLI вроде работает но есть одно каждая десятая секунда как будто задерживается (9 в логе). Возможно неправильно выбран пределитель. По аналогии с LSE поставил 39999. ПОДСКАЖИТЕ какой нужно. Вывод лога с USART опрос каждую секунду по таймеру регистров счета:
RTC_GetCounter=00000000<0><0>; RTC_GetDivide00002783<0><0>
RTC_GetCounter=00000001<0><0>; RTC_GetDivide00006477<0><0>
RTC_GetCounter=00000002<0><0>; RTC_GetDivide00010172<0><0>
RTC_GetCounter=00000003<0><0>; RTC_GetDivide00013863<0><0>
RTC_GetCounter=00000004<0><0>; RTC_GetDivide00017553<0><0>
RTC_GetCounter=00000005<0><0>; RTC_GetDivide00021243<0><0>
RTC_GetCounter=00000006<0><0>; RTC_GetDivide00024936<0><0>
RTC_GetCounter=00000007<0><0>; RTC_GetDivide00028626<0><0>
RTC_GetCounter=00000008<0><0>; RTC_GetDivide00032316<0><0>
RTC_GetCounter=00000009<0><0>; RTC_GetDivide00036006<0><0>
RTC_GetCounter=00000009<0><0>; RTC_GetDivide00039699<0><0>
RTC_GetCounter=00000010<0><0>; RTC_GetDivide00003385<0><0>
RTC_GetCounter=00000011<0><0>; RTC_GetDivide00007073<0><0>
RTC_GetCounter=00000012<0><0>; RTC_GetDivide00010762<0><0>
RTC_GetCounter=00000013<0><0>; RTC_GetDivide00014452<0><0>
RTC_GetCounter=00000014<0><0>; RTC_GetDivide00018140<0><0>
RTC_GetCounter=00000015<0><0>; RTC_GetDivide00021827<0><0>
RTC_GetCounter=00000016<0><0>; RTC_GetDivide00025517<0><0>
RTC_GetCounter=00000017<0><0>; RTC_GetDivide00029204<0><0>
RTC_GetCounter=00000018<0><0>; RTC_GetDivide00032893<0><0>
RTC_GetCounter=00000019<0><0>; RTC_GetDivide00036582<0><0>
RTC_GetCounter=00000019<0><0>; RTC_GetDivide00000271<0><0>
RTC_GetCounter=00000020<0><0>; RTC_GetDivide00003957<0><0>
RTC_GetCounter=00000021<0><0>; RTC_GetDivide00007644<0><0>
RTC_GetCounter=00000022<0><0>; RTC_GetDivide00011330<0><0>
RTC_GetCounter=00000023<0><0>; RTC_GetDivide00015018<0><0>
RTC_GetCounter=00000024<0><0>; RTC_GetDivide00018703<0><0>
RTC_GetCounter=00000025<0><0>; RTC_GetDivide00022388<0><0>
RTC_GetCounter=00000026<0><0>; RTC_GetDivide00026073<0><0>
RTC_GetCounter=00000027<0><0>; RTC_GetDivide00029761<0><0>
RTC_GetCounter=00000028<0><0>; RTC_GetDivide00033446<0><0>
RTC_GetCounter=00000029<0><0>; RTC_GetDivide00037131<0><0>
RTC_GetCounter=00000029<0><0>; RTC_GetDivide00000813<0><0>
RTC_GetCounter=00000030<0><0>; RTC_GetDivide00004500<0><0>
RTC_GetCounter=00000031<0><0>; RTC_GetDivide00008185<0><0>
RTC_GetCounter=00000032<0><0>; RTC_GetDivide00011869<0><0>
RTC_GetCounter=00000033<0><0>; RTC_GetDivide00015554<0><0>
RTC_GetCounter=00000034<0><0>; RTC_GetDivide00019242<0><0>
RTC_GetCounter=00000035<0><0>; RTC_GetDivide00022927<0><0>
RTC_GetCounter=00000036<0><0>; RTC_GetDivide00026611<0><0>
RTC_GetCounter=00000037<0><0>; RTC_GetDivide00030294<0><0>
RTC_GetCounter=00000038<0><0>; RTC_GetDivide00033981<0><0>
RTC_GetCounter=00000039<0><0>; RTC_GetDivide00037665<0><0>
RTC_GetCounter=00000039<0><0>; RTC_GetDivide00001347<0><0>
RTC_GetCounter=00000040<0><0>; RTC_GetDivide00005032<0><0>



Pridnya
Цитата(dimon_rub @ Oct 7 2016, 17:26) *
RCC_ClocksTypeDef rcc_Clocks;

Поднял RTC на LSI. На LSE не как не хочет. Совсем начал зависать наверно действительно что то с кварцом. На SLI вроде работает но есть одно каждая десятая секунда как будто задерживается (9 в логе). Возможно неправильно выбран пределитель. По аналогии с LSE поставил 39999. ПОДСКАЖИТЕ какой нужно. Вывод лога с USART опрос каждую секунду по таймеру регистров счета:

LSI - это внутренний RC-генератор, менее точный, чем кварцевый (LSE), частота его отличается от 40кГц, поэтому нужно подбирать значение предделителя под конкретный образецю
dimon_rub
Поднял RTC в качестве эксперимента на частоте основного кварца/128. Все вроде работает нормально но опять же при ежесекундном опросе через таймер есть глючек только теперь на каждой 10 секунде (в логе 10, 20 и т.д.). ОЧЕНЬ ИНТЕРЕСНО ЧТО ВРЕТ. Может это таймер. Сегодня еще поиграюсь. Может кто что посоветует где собака....
SasaVitebsk
То ли вы не можете внятно описать что вас не устраивает, то ли мы понять. Я так точно не могу понять.
Если вы опрашиваете узел, то могут быть биения. У вас асинхронный узел, по отношению к основному кварцу. Вы работаете на основном таймере при чтении RTC у вас будут биения. То есть раз в n число чтений либо проглатывать секунду либо удваивать.
bolden
А не должно быть так ?
// Чтоб прерывание случалось раз в секунду
TIM6->ARR = ( 1000 - 1 ) ;
SasaVitebsk
Ну да. Я же написал в первом посту. И объяснил почему так.
bolden
Цитата(SasaVitebsk @ Oct 10 2016, 22:06) *
Ну да. Я же написал в первом посту. И объяснил почему так.


Сорри. Не внимательно прочитал ветку.

ТС ниже выложил код инициализации таймера с той же ошибкой

bb-offtopic.gif Во многих примерах и уроках в интернете почему-то настройки таймера приводят с ошибкой
предделитель задают правильно, а от счётчика периода единицу отнимать забывают. для мигания светодиодом это несущественно (незаметно), а при измерении больших интервалов времени набегает прилично.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.