Jump to content

    
Sign in to follow this  
billidean

STM32F4::Discovery -> Помогите с таймером

Recommended Posts

Тут нарыл в даташите:

post-59925-1392298722_thumb.png

- это к вопросу удвоения частоты тактирования таймеров.

А в Референсе нашел следующее:

post-59925-1392299250_thumb.png

, но это только для STM32F42/43хх.

Значит в моем случае (STM32F407) на таймеры поступает прямая частота с PLL (не умноженная).

 

Здесь еще один "прикол": при установках "RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;" и "RCC->CFGR |= RCC_CFGR_PPRE1_DIV1;" таймеры тикают с одинаковой частотой. В описании регистра RCC->CFGR сказано:

post-59925-1392299690_thumb.png

При:

#define RCC_CFGR_PPRE1_DIV1 ((uint32_t)0x00000000) /*!< HCLK not divided */

#define RCC_CFGR_PPRE1_DIV2 ((uint32_t)0x00001000) /*!< HCLK divided by 2 */

тиканье должно отличаться в два раза.

 

Чота с этими таймерами/тактовыми ваще х.. какая-то. И эту хрень нужно постоянно таскать с собой в голове при написании кода :wacko: .

Edited by billidean

Share this post


Link to post
Share on other sites

забудьте вы про умножение частоты)... нет его там, есть недоделение, то есть если вы на шину перифирии подадите клок с плл/2, то на таймеры придет просто клок с ПЛЛ, если клок/4, то на таймерах будет клок/2, а если подадите просто клок с плл, то так и будет, умножить там ничто частоту не может.

 

 

а вы уверены что от того таймера и от того домена флаги крутите:)?

Share this post


Link to post
Share on other sites
забудьте вы про умножение частоты)... нет его там, есть недоделение, то есть если вы на шину перифирии подадите клок с плл/2, то на таймеры придет просто клок с ПЛЛ, если клок/4, то на таймерах будет клок/2, а если подадите просто клок с плл, то так и будет, умножить там ничто частоту не может.

я об этом и говорю, что без деления и при делении на 2 - получаем тактовую на таймер одинаковую.

 

а вы уверены что от того таймера и от того домена флаги крутите:)?

- конечно. Если я поставлю "RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;", то частота падает вдвое.

 

З.Ы.: Блин.. хоть немного понятно стало.

Share this post


Link to post
Share on other sites

не очень понятно падает она теперь или нет, но если стало немного понятно, то хорошо....

 

еще хорошим тоном перед |= является снять все прошлые флаги, ибо если какие то уже стоят может ничего и не произойти или произойти не то что хотели. А в вашем случае я так понимаю у вас много инициализаций что делают библиотечные функции, которые вы просматривать не стали.

Share this post


Link to post
Share on other sites
не очень понятно падает она теперь или нет, но если стало немного понятно, то хорошо....
- здесь я опечатался:

Если я поставлю "RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;", то частота падает вдвое.
- здесь вместо RCC_CFGR_PPRE1_DIV2 следует писать RCC_CFGR_PPRE1_DIV4.

Т.е. если устанавливаем RCC_CFGR_PPRE1_DIV1 или RCC_CFGR_PPRE1_DIV2, то частота, поступающая на таймер, не делится, а при RCC_CFGR_PPRE1_DIV4 - частота делится на 2, при RCC_CFGR_PPRE1_DIV8 - на 4, при RCC_CFGR_PPRE1_DIV16 - на 8.

Т.е. высказывание:

забудьте вы про умножение частоты)... нет его там, есть недоделение, то есть если вы на шину перифирии подадите клок с плл/2, то на таймеры придет просто клок с ПЛЛ, если клок/4, то на таймерах будет клок/2, а если подадите просто клок с плл, то так и будет, умножить там ничто частоту не может.
- считаю точным описанием поведения определения частот тактирования таймеров.

 

По поводу максимальных частот таймеров нашел таблицу:

post-59925-1392353784_thumb.png

 

еще хорошим тоном перед |= является снять все прошлые флаги, ибо если какие то уже стоят может ничего и не произойти или произойти не то что хотели. А в вашем случае я так понимаю у вас много инициализаций что делают библиотечные функции, которые вы просматривать не стали.
- сброс всех установочных регистров выполняется в функции SystemInit() - сначала все сбросы, а затем вызов функции SetSysClock(), которая уже и устанавливает частоты.

Пока я не пишу свою функцию инициализации, а пытаюсь разобрать библиотечные, чтобы потом уже составить свою.

Edited by billidean

Share this post


Link to post
Share on other sites

А теперь самое ИНТЕРЕСНОЕ:

Вот код моей программки:

#include "stm32f4xx.h"
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_tim.h"

#include "xprintf/xprintf.h"

#define TimerTick      (SystemCoreClock/1000-1)    // Получим 1 килогерц

int counter = 0;
int flag = 0;

// SysTick Interrupt Handler
//void SysTick_Handler(void)
void TIM6_DAC_IRQHandler(void)
{
    /* Так как этот обработчик вызывается и для ЦАП, нужно проверять,
    * произошло ли прерывание по "переполнению" счётчика таймера TIM6.
    */
    if (TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET)
    {
        /* Очищаем бит обрабатываемого прерывания */
        TIM_ClearITPendingBit(TIM6, TIM_IT_Update);

        flag = 1;
    }
}


int main(void)
{
    SystemInit();

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD , ENABLE);

    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOD, &GPIO_InitStructure);

    //**********************************************
    // Настроим таймер TIM
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE); // включаем тактирование таймера
   /* Другие параметры структуры TIM_TimeBaseInitTypeDef
   * не имеют смысла для базовых таймеров.
   */

    TIM_TimeBaseInitTypeDef base_timer;
//    TIM_TimeBaseStructInit(&base_timer);
  /* Делитель учитывается как TIM_Prescaler + 1, поэтому отнимаем 1 */
//    base_timer.TIM_Prescaler = 16 - 1; // 16MHz/16 = 1000KHz
//    base_timer.TIM_Prescaler = 168 - 1; // (168)MHz/168 = 1000KHz (168/RCC_CFGR_PPRE1_DIV1-freq from PLL (1/1) for APB1)
//    base_timer.TIM_Prescaler = 84 - 1; // (84)MHz/84 = 1000KHz (168/RCC_CFGR_PPRE1_DIV4-freq from PLL (1/2) for APB1)
    base_timer.TIM_Prescaler = 42 - 1; // (42)MHz/42 = 1000KHz (168/RCC_CFGR_PPRE1_DIV8-freq from PLL (1/4) for APB1)
    base_timer.TIM_Period = 1000-1; //период 1000 тактов == получим прерывания через 1мс (1KHz)
    base_timer.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM6, &base_timer);
    TIM_ARRPreloadConfig(TIM6, ENABLE);

  /* Разрешаем прерывание по обновлению (в данном случае -
   * по переполнению) счётчика таймера TIM6.
   */
    TIM_ClearITPendingBit(TIM6, TIM_IT_Update);
    TIM_ITConfig(TIM6, TIM_IT_Update, ENABLE);
    TIM_Cmd(TIM6, ENABLE);  // Включаем таймер

  /* Разрешаем обработку прерывания по переполнению счётчика
   * таймера TIM6. это же прерывание
   * отвечает и за опустошение ЦАП.
   */
    NVIC_SetPriority(TIM6_DAC_IRQn, 15);
    NVIC_EnableIRQ(TIM6_DAC_IRQn);
    //**********************************************

    xprintf("dv\n");

    while(1)
    {
        if( flag == 1 )
        {
            if(counter == 0)
            {
                GPIO_SetBits(GPIOD, GPIO_Pin_12);
            }
            counter++;
            if(counter == 1000)
            {
                GPIO_ResetBits(GPIOD, GPIO_Pin_12);
            }
            if(counter == 2000)
            {
                counter = 0;
            }
            flag = 0;
        }
    }
}

Вот настройки моей системы:

#if !defined  (HSE_VALUE) 
  #define HSE_VALUE    ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */
#endif /* HSE_VALUE */
...
/************************* PLL Parameters *************************************/
/* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N */
#define PLL_M      8
#define PLL_N      336

/* SYSCLK = PLL_VCO / PLL_P */
#define PLL_P      2

 

Система каждую 1 секунду переключает состояние светодиода (горит/НЕгорит) (проверялось на плате STM32F4-Discovery).

Обратим внимание на строки:

//    base_timer.TIM_Prescaler = 16 - 1; // (16)MHz/16 = 1000KHz (16MHz - internal clock without SystemInit()-function)
//    base_timer.TIM_Prescaler = 168 - 1; // (168)MHz/168 = 1000KHz (168/RCC_CFGR_PPRE1_DIV1-freq from PLL (1/1) for APB1)
//    base_timer.TIM_Prescaler = 84 - 1; // (84)MHz/84 = 1000KHz (168/RCC_CFGR_PPRE1_DIV4-freq from PLL (1/2) for APB1)
    base_timer.TIM_Prescaler = 42 - 1; // (42)MHz/42 = 1000KHz (168/RCC_CFGR_PPRE1_DIV8-freq from PLL (1/4) for APB1)
    base_timer.TIM_Period = 1000-1; //период 1000 тактов == получим прерывания через 1мс (1KHz)

Т.е. при использовании параметра для PLL - prescale=RCC_CFGR_PPRE1_DIV1, таймер (TIM6) тактируется частотой 168МГц, что СОВСЕМ НЕ СООТВЕТСТВУЕТ приведенной выше таблице (из официального документа-DataSheet на кристалл).

 

Как эту всю байду с тактированием таймеров (конкретно - для TIM6) понять??? :wacko:

Edited by billidean

Share this post


Link to post
Share on other sites

тут есть хитрость в мануале написано что типа вас никто не будет контролировать чтобы вы не подали больше чем можно.

Таймер 6 может работать максимум от частоты 84, и вы обязаны так задать делители чтобы эту частоты не превысить. Подавая на него 168 вы получаете не стабильную работу, иногда это не заметно, иногда будет сбоить. За 84 они отвечают, а за 168 нет.

 

 

Вот и настраивайте правильно! как то так...

Share this post


Link to post
Share on other sites

Назовем, :bb-offtopic:

Из жизни. Женщина установила спираль, чтобы не беременеть. Практика распространенная, интимная... Муж недоволен:

- Что-то колется!

- Никому не колется, а тебе колется!

 

Это я к тому, что случай ТС выглядит уникальным явлением природы на фоне всеобщей благодати. Что же никому другому "не колется"?

Share this post


Link to post
Share on other sites
тут есть хитрость..

Вы вот это имеете в виду (выделенная строчка):

post-59925-1392363648_thumb.png

из настроек регистра RCC_CFGR?

 

Что же никому другому "не колется"?

просто я решил раскопать и расставить все точки над этими мутными "и". А все может быть просто потыкались/понастраивали_как-то свои девайсы да и проглотили эту непонятку, успокоив себя: "не знаю почему, но тактовая у меня вот такая..".

Share this post


Link to post
Share on other sites

ну да.

все вам и написали

на домен не может быть больше 42, как мы помним из других картинок что таймер может работать от двойной тактовой домена, то есть 84. Вот и все загадки - отгадки.

 

 

У меня не возникает таких проблем, потому что я сразу запустил в топку это конфиг, и настроил тактовую частоту руками по мануалу. Потратил полдня, но зато уверен что никакой дефайн не переключится и я не буду потом сидеть и не понимать что за блин. Также прописал правильную реакцию на срывы клока и прочее...

 

После этого проверил осцилом что все частоты заработали как надо, и дальше все таймеры автоматом по расчетным значениям затикали.

Share this post


Link to post
Share on other sites
просто я решил раскопать и расставить все точки над этими мутными "и".

Вот это правильный путь! Уверен, что докопавшись, вы убедитесь, что в STM32F4 все логично. Чего не могу сказать о библиотечных функциях. Но и они работают.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this