billidean 0 13 февраля, 2014 Опубликовано 13 февраля, 2014 (изменено) · Жалоба Тут нарыл в даташите: - это к вопросу удвоения частоты тактирования таймеров. А в Референсе нашел следующее: , но это только для STM32F42/43хх. Значит в моем случае (STM32F407) на таймеры поступает прямая частота с PLL (не умноженная). Здесь еще один "прикол": при установках "RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;" и "RCC->CFGR |= RCC_CFGR_PPRE1_DIV1;" таймеры тикают с одинаковой частотой. В описании регистра RCC->CFGR сказано: При: #define RCC_CFGR_PPRE1_DIV1 ((uint32_t)0x00000000) /*!< HCLK not divided */ #define RCC_CFGR_PPRE1_DIV2 ((uint32_t)0x00001000) /*!< HCLK divided by 2 */ тиканье должно отличаться в два раза. Чота с этими таймерами/тактовыми ваще х.. какая-то. И эту хрень нужно постоянно таскать с собой в голове при написании кода . Изменено 13 февраля, 2014 пользователем billidean Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Golikov 0 13 февраля, 2014 Опубликовано 13 февраля, 2014 · Жалоба забудьте вы про умножение частоты)... нет его там, есть недоделение, то есть если вы на шину перифирии подадите клок с плл/2, то на таймеры придет просто клок с ПЛЛ, если клок/4, то на таймерах будет клок/2, а если подадите просто клок с плл, то так и будет, умножить там ничто частоту не может. а вы уверены что от того таймера и от того домена флаги крутите:)? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
billidean 0 13 февраля, 2014 Опубликовано 13 февраля, 2014 · Жалоба забудьте вы про умножение частоты)... нет его там, есть недоделение, то есть если вы на шину перифирии подадите клок с плл/2, то на таймеры придет просто клок с ПЛЛ, если клок/4, то на таймерах будет клок/2, а если подадите просто клок с плл, то так и будет, умножить там ничто частоту не может. я об этом и говорю, что без деления и при делении на 2 - получаем тактовую на таймер одинаковую. а вы уверены что от того таймера и от того домена флаги крутите:)? - конечно. Если я поставлю "RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;", то частота падает вдвое. З.Ы.: Блин.. хоть немного понятно стало. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Golikov 0 13 февраля, 2014 Опубликовано 13 февраля, 2014 · Жалоба не очень понятно падает она теперь или нет, но если стало немного понятно, то хорошо.... еще хорошим тоном перед |= является снять все прошлые флаги, ибо если какие то уже стоят может ничего и не произойти или произойти не то что хотели. А в вашем случае я так понимаю у вас много инициализаций что делают библиотечные функции, которые вы просматривать не стали. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 13 февраля, 2014 Опубликовано 13 февраля, 2014 · Жалоба Мне кажется с самого начала, что кварцевый генератор не включился. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
billidean 0 14 февраля, 2014 Опубликовано 14 февраля, 2014 (изменено) · Жалоба не очень понятно падает она теперь или нет, но если стало немного понятно, то хорошо.... - здесь я опечатался: Если я поставлю "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, а если подадите просто клок с плл, то так и будет, умножить там ничто частоту не может. - считаю точным описанием поведения определения частот тактирования таймеров. По поводу максимальных частот таймеров нашел таблицу: еще хорошим тоном перед |= является снять все прошлые флаги, ибо если какие то уже стоят может ничего и не произойти или произойти не то что хотели. А в вашем случае я так понимаю у вас много инициализаций что делают библиотечные функции, которые вы просматривать не стали. - сброс всех установочных регистров выполняется в функции SystemInit() - сначала все сбросы, а затем вызов функции SetSysClock(), которая уже и устанавливает частоты. Пока я не пишу свою функцию инициализации, а пытаюсь разобрать библиотечные, чтобы потом уже составить свою. Изменено 14 февраля, 2014 пользователем billidean Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
billidean 0 14 февраля, 2014 Опубликовано 14 февраля, 2014 (изменено) · Жалоба А теперь самое ИНТЕРЕСНОЕ: Вот код моей программки: #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) понять??? Изменено 14 февраля, 2014 пользователем billidean Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Golikov 0 14 февраля, 2014 Опубликовано 14 февраля, 2014 · Жалоба тут есть хитрость в мануале написано что типа вас никто не будет контролировать чтобы вы не подали больше чем можно. Таймер 6 может работать максимум от частоты 84, и вы обязаны так задать делители чтобы эту частоты не превысить. Подавая на него 168 вы получаете не стабильную работу, иногда это не заметно, иногда будет сбоить. За 84 они отвечают, а за 168 нет. Вот и настраивайте правильно! как то так... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 14 февраля, 2014 Опубликовано 14 февраля, 2014 · Жалоба Назовем, :bb-offtopic: Из жизни. Женщина установила спираль, чтобы не беременеть. Практика распространенная, интимная... Муж недоволен: - Что-то колется! - Никому не колется, а тебе колется! Это я к тому, что случай ТС выглядит уникальным явлением природы на фоне всеобщей благодати. Что же никому другому "не колется"? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
billidean 0 14 февраля, 2014 Опубликовано 14 февраля, 2014 · Жалоба тут есть хитрость.. Вы вот это имеете в виду (выделенная строчка): из настроек регистра RCC_CFGR? Что же никому другому "не колется"? просто я решил раскопать и расставить все точки над этими мутными "и". А все может быть просто потыкались/понастраивали_как-то свои девайсы да и проглотили эту непонятку, успокоив себя: "не знаю почему, но тактовая у меня вот такая..". Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Golikov 0 14 февраля, 2014 Опубликовано 14 февраля, 2014 · Жалоба ну да. все вам и написали на домен не может быть больше 42, как мы помним из других картинок что таймер может работать от двойной тактовой домена, то есть 84. Вот и все загадки - отгадки. У меня не возникает таких проблем, потому что я сразу запустил в топку это конфиг, и настроил тактовую частоту руками по мануалу. Потратил полдня, но зато уверен что никакой дефайн не переключится и я не буду потом сидеть и не понимать что за блин. Также прописал правильную реакцию на срывы клока и прочее... После этого проверил осцилом что все частоты заработали как надо, и дальше все таймеры автоматом по расчетным значениям затикали. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 14 февраля, 2014 Опубликовано 14 февраля, 2014 · Жалоба просто я решил раскопать и расставить все точки над этими мутными "и". Вот это правильный путь! Уверен, что докопавшись, вы убедитесь, что в STM32F4 все логично. Чего не могу сказать о библиотечных функциях. Но и они работают. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться