billidean
Feb 12 2014, 13:45
Здравствуйте.
Хочу заставить светодиод мигать с тактом 1с.
Казалось бы - задача тривиальней некуда. Но я зашел в тупик.
Пишу простейший код:
CODE
#include "stm32f4xx.h"
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_tim.h"
int counter = 0;
int flag = 0;
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 base_timer;
TIM_TimeBaseStructInit(&base_timer);
/* Делитель учитывается как TIM_Prescaler + 1, поэтому отнимаем 1 */
base_timer.TIM_Prescaler = 16 - 1;
base_timer.TIM_Period = 1000-1;
base_timer.TIM_ClockDivision = TIM_CKD_DIV1;
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);
//**********************************************
while(1)
{
// отсчитываем каждые 1000 тактов таймера и переключаем светодиод
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;
}
}
}
- мигает как надо. Но здесь параметры:
base_timer.TIM_Prescaler = 16 - 1; и
base_timer.TIM_Period = 1000-1;, т.е. получается, что частота тактирования = 16МГц. Это можно объяснить тем, что идет тактирование от внутреннего генератора (8МГц), но с удвоенной частотой (это, типа, из-за использования предделителей, не равных 1 на шине АРВ1). Но так-то я раситывал на 168МГц.
Пробовал с разными коэффициентами - полная ерунда.
Если я раскомментирую строчку
Код
// SystemInit();
, то светик мигает почти с тактом в 1 сек, но "ПОЧТИ"=чуть-чуть быстрее.
В чем может быть моя неправда? Ткните носом, ПЛЗ. Или объясните матчасть (может все так и должно быть

).
ИМХО, кварц может глючит? (но проверить нечем, нет никаких девайсов)
Не вижу установки делителей для тактов периферийных шин.
billidean
Feb 12 2014, 14:11
В SystemInit() - вроде какие-то предделители устанавливаются... (я, если честно, не встречал таких, как вы говорите, при поисках всяких исходников для установки таймеров).
То, что я нарыл (по-быстрому) в инете, я и накидал в своем коде, НИКАКИХ доп. установок не встречал.
Можете по-подробнее объяснить мою недоработку. (если можно, то с кодом)
Цитата(billidean @ Feb 12 2014, 17:11)

В SystemInit() - вроде какие-то предделители устанавливаются... (я, если честно, не встречал таких, как вы говорите, при поисках всяких исходников для установки таймеров).
То, что я нарыл (по-быстрому) в инете, я и накидал в своем коде, НИКАКИХ доп. установок не встречал.
Можете по-подробнее объяснить мою недоработку. (если можно, то с кодом)
Наверное, устанавливаются... только во что? Типа такого (это для другого процессора):
Код
RCC->CFGR =
RCC_CFGR_HPRE_0 * 0 | // HPRE[3:0] bits (AHB prescaler): SYSCLK / 1 = 24 MHz (max)
RCC_CFGR_PPRE1_0 * 0 | // PRE1[2:0] bits (APB1 prescaler): HCLK / 1 = 24 MHz (max)
RCC_CFGR_PPRE2_0 * 0 | // PRE2[2:0] bits (APB2 prescaler): HCLK / 1 = 24 MHz
А еще я на MCO вывожу какую-нибудь системную частоту, для проверки.
billidean
Feb 12 2014, 14:29
В systemInit() dspsdftncz SetSysClock(), код которой:
CODE
static void SetSysClock(void)
{
/******************************************************************************/
/* PLL (clocked by HSE) used as System clock source */
/******************************************************************************/
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
/* Enable HSE */
RCC->CR |= ((uint32_t)RCC_CR_HSEON);
/* Wait till HSE is ready and if Time out is reached exit */
do
{
HSEStatus = RCC->CR & RCC_CR_HSERDY;
StartUpCounter++;
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
if ((RCC->CR & RCC_CR_HSERDY) != RESET)
{
HSEStatus = (uint32_t)0x01;
}
else
{
HSEStatus = (uint32_t)0x00;
}
if (HSEStatus == (uint32_t)0x01)
{
/* Select regulator voltage output Scale 1 mode, System frequency up to 168 MHz */
RCC->APB1ENR |= RCC_APB1ENR_PWREN;
PWR->CR |= PWR_CR_VOS;
/* HCLK = SYSCLK / 1*/
RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
/* PCLK2 = HCLK / 2*/
RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;
/* PCLK1 = HCLK / 4*/
RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;
/* Configure the main PLL */
RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
(RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);
/* Enable the main PLL */
RCC->CR |= RCC_CR_PLLON;
/* Wait till the main PLL is ready */
while((RCC->CR & RCC_CR_PLLRDY) == 0)
{
}
/* Configure Flash prefetch, Instruction cache, Data cache and wait state */
FLASH->ACR = FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;
/* Select the main PLL as system clock source */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= RCC_CFGR_SW_PLL;
/* Wait till the main PLL is used as system clock source */
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);
{
}
}
else
{ /* If HSE fails to start-up, the application will have wrong clock
configuration. User can add here some code to deal with this error */
}
}
А строка
/* Select regulator voltage output Scale 1 mode, System frequency up to 168 MHz */ - вообще внушает уверенность и оптимизм в 168МГц.
Но вот, почему-то, это не работает.
Получается, на периферийной шине у вас 168 / 4 = 42 MHz. Если HSE запустился.
billidean
Feb 12 2014, 14:51
При установке base_timer.TIM_Prescaler = (42-1) и (21-1) получаю тоже неверный результат, светодиод разбегается с часами(секундомером) уже за 10-15 тиков (морганий).
Вы работали с подобной задачей/кодом? или все теория?
(Просто я уже много где потыкался, а результат пока один - тактовая на таймере непонятно-какая и чем определена)
На кварце нагрузочные конденсаторы имеются? Емкость правильная для используемого кварца?
Golikov A.
Feb 12 2014, 17:39
а где вы включаете внешний генератор, подключаете ПЛЛ, ждете стабильного сигнала, и переходите на него?
и если мне не изменяет память то в STM надо правильно определить тип вашего устройства, чтобы в огромном могучем файле правильно сработали дефайны, и задалась правильная частота.
в свое время надоело с этим убиваться, взял по мануалу правильно настроил клок, шин, проца, и всего. Там 3 флажка, 4 регистра, куда понятнее чем разбираться в 3 экранах дефайнов- передефайнов
Можно вывести на светодиод бит SWS1 из RCC_CFGR, чтобы удостовериться, что PLL used as the system clock.
Golikov A.
Feb 12 2014, 17:58
а еще не забыть настроить выходную ножку на максимальную частоту, а то на нее хоть клок подавай, а из нее еле еле лезет
Цитата(Golikov A. @ Feb 12 2014, 20:58)

а еще не забыть настроить выходную ножку на максимальную частоту, а то на нее хоть клок подавай, а из нее еле еле лезет

Если просто статус выводить, а не частоту, то не надо.
billidean
Feb 13 2014, 03:06
Цитата(Golikov A. @ Feb 12 2014, 21:39)

в STM надо правильно определить тип вашего устройства, чтобы в огромном могучем файле правильно сработали дефайны, и задалась правильная частота.
- что вы имеете в виду?
При создании проекта я выбирал кристалл, и это, как я предполагаю, и определяет всякие там дефайны.
По поводу контроля регистров (RCC_CFGR) - нашел какую-то реализацию
printf'a, люди пишут, что работает, вечером попробую запустить. И если все пойдет нормально, то можно будет контролировать все регистры настройки системы.
Golikov A.
Feb 13 2014, 06:11
ага добро пожаловать в мир СТМ, не хрена это не определяет.
Посмотрите огромный хедер, там куча ветвей для одного итого же проца в зависимости от серии, того какой плотности это устройство (вроде так это у СТМ) называется. И проверьте правильные ли дефайны у вас стоят. Ставлю на то что стоят по умолчанию, на какой-то массовый проц из серии.... я так пару недель бился об этот файл...
billidean
Feb 13 2014, 06:44
Вы про stm32f4xx.h-файл?
Там всякие определения/размещения регистров, маски, макросы управления битами.
Так-то по всей линейке (F4) вроде по регистрам должно быть полное соответствие (помнится где-то встречал такую фразу по СТМ).
Golikov A.
Feb 13 2014, 06:50
ага про него. Посмотрите какой проц в итоге определен, посмотрите сходиться ли это с вашим процом (смотрите все, там участвует и размер флэши и все), а заодно чем равны делители выставляющие частоту.
Да, есть полное соответствие. Ничего больше определять не надо. Разве что частоту резонатора.
А что, на светодиод вывести, что я предложил, не катит? printf - это здорово, но сложнее, чем таймер запустить.
billidean
Feb 13 2014, 07:10
Цитата(ViKo @ Feb 13 2014, 10:53)

Да, есть полное соответствие. Ничего больше определять не надо. Разве что частоту резонатора.
А что, на светодиод вывести, что я предложил, не катит? printf - это здорово, но сложнее, чем таймер запустить.
И светодиод задействую, по-необходимости, но это всё все-равно будет только вечером, дома. А пока на работе есть время поразбирать/подготовить какие-либо коды, в том числе и использование printf'a (он потом все-таки пригодится, и чем быстрее я его зпущу, тем проще будет дальнейшая жизнь и отладка).
По настройкам:
Код
#if !defined (HSE_VALUE)
/**
* @brief In the following line adjust the value of External High Speed oscillator (HSE)
used in your application
Tip: To avoid modifying this file each time you need to use different HSE, you
can define the HSE value in your toolchain compiler preprocessor.
*/
#define HSE_VALUE ((uint32_t)25000000) /*!< Value of the External oscillator in Hz */
#endif /* HSE_VALUE */
/**
* @brief In the following line adjust the External High Speed oscillator (HSE) Startup
Timeout value
*/
#if !defined (HSE_STARTUP_TIMEOUT)
#define HSE_STARTUP_TIMEOUT ((uint16_t)0x0500) /*!< Time out for HSE start up */
#endif /* HSE_STARTUP_TIMEOUT */
#if !defined (HSI_VALUE)
#define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/
#endif /* HSI_VALUE */
Здесь 25000000 нужно заменить на 8000000 (внешний кварц 8МГц вроде стоит).
HSE_STARTUP_TIMEOUT - менять думаю не стоит.
А вот почему на "заводе"
HSI_VALUE 16000000 поставили, это мне не понятно, вроде для этих кристаллов должна быть внутренняя частота 8МГц, или я ошибаюсь??
Цитата(billidean @ Feb 13 2014, 10:10)

А вот почему на "заводе" HSI_VALUE 16000000 поставили, это мне не понятно, вроде для этих кристаллов должна быть внутренняя частота 8МГц, или я ошибаюсь??
В руководстве на F40x показана частота 16000000 MHz.
billidean
Feb 13 2014, 08:06
Цитата(ViKo @ Feb 13 2014, 11:30)

В руководстве на F40x показана частота 16000000 MHz.
Да, нашел это место, спасибо. Тогда получается, что при НЕвызове функции
SystemInit() таймер_6 тактируется просто внутренней частотой, а не удвоенной (где-то это вычитал в инете и оказалось, что это обман).
Цитата(billidean @ Feb 13 2014, 11:06)

Да, нашел это место, спасибо. Тогда получается, что при НЕвызове функции SystemInit() таймер_6 тактируется просто внутренней частотой, а не удвоенной (где-то это вычитал в инете и оказалось, что это обман).
Не совсем...
billidean
Feb 13 2014, 08:59
Кстати, нашел еще один параметр, который надо поменять под свой внешний кварц:
#define PLL_M 25, нужно сделать 8.
Цитата(ViKo @ Feb 13 2014, 12:35)

Не совсем...
Так, немного подсоберу все в одну картину:
1. В функции SystemInit() происходит настройка частот системы и PLL на 168МГц(при работе с внешним кварцем), при условии установки правильных дефайнов (HSE_VALUE, PLL_M, и может еще каких..).
2. Если в настройках PLL параметр prescaler не равен 1, то таймеры (на шинах APBx) тактируются удвоенной частотой, иначе НЕудвоенной(прямой).
3. В случае, если мы не используем функцию SystemInit(), то мы не запускаем PLL (если, конечно, отдельно не прописали этот запуск), и следовательно: частота у нас используется внутренняя (16МГц), а таймеры тактируются тоже этой же частотой 16МГц (не удвоенной, т.к. PLL-prescaler в коде не был установлен).
Я правильно рассуждаю?
Цитата(billidean @ Feb 13 2014, 11:59)

Я правильно рассуждаю?
К PLL прескалеры периферийных шин не имеют отношения. В остальном - правильно.
Хороший пример того, что использование библиотечных функций не дает понимания работы узлов микроконтроллера.
Нужно открыть Руководство, и медленно водя мышой по битам регистров, осознать их магическое влияние на то или иное...
billidean
Feb 13 2014, 09:27
...да... вместо PLL-prescaler нужно понимать prescaler для шин (АРВ1 и АРВ2), которые задаются в RCC->CFGR.
UPD: спасибо за помощь.
Сейчас занимаюсь переводом главы USB on-the-go full-speed (OTG_FS) из Референса, Никто не встречал уже переведенной версии(?), иначе жалко будет потраченного времени.
Если перевод не найдется, то постараюсь аккуратно оформить и выложить в сеть.
topkin
Feb 13 2014, 10:17
Конфигурация тактовой частоты и первоначальных настроек происходит в файле system_stm32f4xx.c, функция SystemInit().
Поищите на сайте такую тулзу STM32F4xx_Clock_Configuration_V1.0.1.xls. Это эксель файл, где вы набором галочек конфигурируйте схему тактирования и вам автоматически генерируется файл system_stm32f4xx.c. Добавляете его в свой проект и все будет работать.
P.S. Ссылку дать не могу, поищите на сайте ST
Golikov A.
Feb 13 2014, 10:32
а откуда берется двойная частота без PLL? это скорее единичная и половинная...
и второй вопрос, а нафига переводить? Вы что ее со словарем переводите? Читать сразу на английском не катит? Не конечно здорово когда она есть в русском варианте, все вам спасибо скажут, но столько времени терять....
billidean
Feb 13 2014, 10:46
Цитата(Golikov A. @ Feb 13 2014, 13:32)

а откуда берется двойная частота без PLL? это скорее единичная и половинная...
см.:
Цитата
3. В случае, если мы не используем функцию SystemInit(), то мы не запускаем PLL (если, конечно, отдельно не прописали этот запуск), и следовательно: частота у нас используется внутренняя (16МГц), а таймеры тактируются тоже этой же частотой 16МГц (не удвоенной, т.к. PLL-prescaler в коде не был установлен).
Цитата(Golikov A. @ Feb 13 2014, 13:32)

и второй вопрос, а нафига переводить? Вы что ее со словарем переводите? Читать сразу на английском не катит? Не конечно здорово когда она есть в русском варианте, все вам спасибо скажут, но столько времени терять....
- дабы иметь под рукой русскую версию при начальной работе над USB (я еще не реализовывал этот интерфейс на СТМ), да и помочь другим начинающим.
Golikov A.
Feb 13 2014, 11:08
я просто пытался обратить ваше внимание на то что x1 x2 - это значение prescaller, то есть пред делителя, это разделить на 1 или на 2 частоту, а не умножить...
Цитата(Golikov A. @ Feb 13 2014, 14:08)

я просто пытался обратить ваше внимание на то что x1 x2 - это значение prescaller, то есть пред делителя, это разделить на 1 или на 2 частоту, а не умножить...
Нет, это "умножить". Это для простоты показано.
На самом деле, надо думать, при x2 подается удвоенная частота, с PLL (которая работает, для максимальной рабочей, на удвоенной 168 MHz, а не на 168 MHz). Может, я нафантазировал... может, просто не делится на 2, 4, 8 после прескалера, а делится на 1, 2, 4.
Golikov A.
Feb 13 2014, 12:15
ну типа того, в общем периферия системную частоту не обгонит
billidean
Feb 13 2014, 14:00
Тут нарыл в даташите:
Нажмите для просмотра прикрепленного файла - это к вопросу удвоения частоты тактирования таймеров.
А в Референсе нашел следующее:
Нажмите для просмотра прикрепленного файла, но это только для 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 */тиканье должно отличаться в два раза.
Чота с этими таймерами/тактовыми ваще х.. какая-то. И эту хрень нужно постоянно таскать с собой в голове при написании кода

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

?
billidean
Feb 13 2014, 15:52
Цитата(Golikov A. @ Feb 13 2014, 18:46)

забудьте вы про умножение частоты)... нет его там, есть недоделение, то есть если вы на шину перифирии подадите клок с плл/2, то на таймеры придет просто клок с ПЛЛ, если клок/4, то на таймерах будет клок/2, а если подадите просто клок с плл, то так и будет, умножить там ничто частоту не может.
я об этом и говорю, что без деления и при делении на 2 - получаем тактовую на таймер одинаковую.
Цитата(Golikov A. @ Feb 13 2014, 18:46)

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

?
- конечно. Если я поставлю "RCC->CFGR |=
RCC_CFGR_PPRE1_DIV2;", то частота падает вдвое.
З.Ы.: Блин.. хоть немного понятно стало.
Golikov A.
Feb 13 2014, 16:10
не очень понятно падает она теперь или нет, но если стало немного понятно, то хорошо....
еще хорошим тоном перед |= является снять все прошлые флаги, ибо если какие то уже стоят может ничего и не произойти или произойти не то что хотели. А в вашем случае я так понимаю у вас много инициализаций что делают библиотечные функции, которые вы просматривать не стали.
Мне кажется с самого начала, что кварцевый генератор не включился.
billidean
Feb 14 2014, 04:30
Цитата(Golikov A. @ Feb 13 2014, 19:10)

не очень понятно падает она теперь или нет, но если стало немного понятно, то хорошо....
- здесь я опечатался:
Цитата
Если я поставлю "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.
Т.е. высказывание:
Цитата(Golikov A. @ Feb 13 2014, 18:46)

забудьте вы про умножение частоты)... нет его там, есть недоделение, то есть если вы на шину перифирии подадите клок с плл/2, то на таймеры придет просто клок с ПЛЛ, если клок/4, то на таймерах будет клок/2, а если подадите просто клок с плл, то так и будет, умножить там ничто частоту не может.
- считаю точным описанием поведения определения частот тактирования таймеров.
По поводу максимальных частот таймеров нашел таблицу:
Нажмите для просмотра прикрепленного файлаЦитата(Golikov A. @ Feb 13 2014, 19:10)

еще хорошим тоном перед |= является снять все прошлые флаги, ибо если какие то уже стоят может ничего и не произойти или произойти не то что хотели. А в вашем случае я так понимаю у вас много инициализаций что делают библиотечные функции, которые вы просматривать не стали.
- сброс всех установочных регистров выполняется в функции SystemInit() - сначала все сбросы, а затем вызов функции SetSysClock(), которая уже и устанавливает частоты.
Пока я не пишу свою функцию инициализации, а пытаюсь разобрать библиотечные, чтобы потом уже составить свою.
billidean
Feb 14 2014, 06:58
А теперь самое ИНТЕРЕСНОЕ:
Вот код моей программки:
Код
#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) понять???
Golikov A.
Feb 14 2014, 07:18
тут есть хитрость в мануале написано что типа вас никто не будет контролировать чтобы вы не подали больше чем можно.
Таймер 6 может работать максимум от частоты 84, и вы обязаны так задать делители чтобы эту частоты не превысить. Подавая на него 168 вы получаете не стабильную работу, иногда это не заметно, иногда будет сбоить. За 84 они отвечают, а за 168 нет.
Вот и настраивайте правильно! как то так...
Назовем,

Из жизни. Женщина установила спираль, чтобы не беременеть. Практика распространенная, интимная... Муж недоволен:
- Что-то колется!
- Никому не колется, а тебе колется!
Это я к тому, что случай ТС выглядит уникальным явлением природы на фоне всеобщей благодати. Что же никому другому "не колется"?
billidean
Feb 14 2014, 07:49
Цитата
тут есть хитрость..
Вы вот это имеете в виду (выделенная строчка):
Нажмите для просмотра прикрепленного файлаиз настроек регистра RCC_CFGR?
Цитата
Что же никому другому "не колется"?
просто я решил раскопать и расставить все точки над этими мутными "и". А
все может быть просто потыкались/понастраивали_
как-то свои девайсы да и проглотили эту
непонятку, успокоив себя: "не знаю почему, но тактовая у меня вот такая..".
Golikov A.
Feb 14 2014, 08:00
ну да.
все вам и написали
на домен не может быть больше 42, как мы помним из других картинок что таймер может работать от двойной тактовой домена, то есть 84. Вот и все загадки - отгадки.
У меня не возникает таких проблем, потому что я сразу запустил в топку это конфиг, и настроил тактовую частоту руками по мануалу. Потратил полдня, но зато уверен что никакой дефайн не переключится и я не буду потом сидеть и не понимать что за блин. Также прописал правильную реакцию на срывы клока и прочее...
После этого проверил осцилом что все частоты заработали как надо, и дальше все таймеры автоматом по расчетным значениям затикали.
Цитата(billidean @ Feb 14 2014, 10:49)

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