Перейти к содержанию
    

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

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

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: .

Изменено пользователем billidean

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

 

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

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

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Мне кажется с самого начала, что кварцевый генератор не включился.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Если я поставлю "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(), которая уже и устанавливает частоты.

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

Изменено пользователем billidean

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

#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:

Изменено пользователем billidean

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

 

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

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

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

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

тут есть хитрость..

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

post-59925-1392363648_thumb.png

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

 

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

ну да.

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

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

 

 

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

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

просто я решил раскопать и расставить все точки над этими мутными "и".

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...