Jump to content

    
Sign in to follow this  
billidean

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

Recommended Posts

Здравствуйте.

Хочу заставить светодиод мигать с тактом 1с.

Казалось бы - задача тривиальней некуда. Но я зашел в тупик.

Пишу простейший код:

#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 сек, но "ПОЧТИ"=чуть-чуть быстрее.

 

В чем может быть моя неправда? Ткните носом, ПЛЗ. Или объясните матчасть (может все так и должно быть :05: ).

 

ИМХО, кварц может глючит? (но проверить нечем, нет никаких девайсов) :wacko:

Edited by IgorKossak
[codebox] для длинного кода, [code] - для короткого!!!

Share this post


Link to post
Share on other sites

В SystemInit() - вроде какие-то предделители устанавливаются... (я, если честно, не встречал таких, как вы говорите, при поисках всяких исходников для установки таймеров).

То, что я нарыл (по-быстрому) в инете, я и накидал в своем коде, НИКАКИХ доп. установок не встречал.

 

Можете по-подробнее объяснить мою недоработку. (если можно, то с кодом)

Share this post


Link to post
Share on other sites
В 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 вывожу какую-нибудь системную частоту, для проверки.

Share this post


Link to post
Share on other sites

В systemInit() dspsdftncz SetSysClock(), код которой:

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МГц.

 

Но вот, почему-то, это не работает.

Edited by billidean
[codebox] для длинного кода, [code] - для короткого!!!

Share this post


Link to post
Share on other sites

При установке base_timer.TIM_Prescaler = (42-1) и (21-1) получаю тоже неверный результат, светодиод разбегается с часами(секундомером) уже за 10-15 тиков (морганий).

Вы работали с подобной задачей/кодом? или все теория?

(Просто я уже много где потыкался, а результат пока один - тактовая на таймере непонятно-какая и чем определена)

Share this post


Link to post
Share on other sites

а где вы включаете внешний генератор, подключаете ПЛЛ, ждете стабильного сигнала, и переходите на него?

 

и если мне не изменяет память то в STM надо правильно определить тип вашего устройства, чтобы в огромном могучем файле правильно сработали дефайны, и задалась правильная частота.

 

в свое время надоело с этим убиваться, взял по мануалу правильно настроил клок, шин, проца, и всего. Там 3 флажка, 4 регистра, куда понятнее чем разбираться в 3 экранах дефайнов- передефайнов

Share this post


Link to post
Share on other sites
а еще не забыть настроить выходную ножку на максимальную частоту, а то на нее хоть клок подавай, а из нее еле еле лезет:)

Если просто статус выводить, а не частоту, то не надо. :rolleyes:

Share this post


Link to post
Share on other sites
в STM надо правильно определить тип вашего устройства, чтобы в огромном могучем файле правильно сработали дефайны, и задалась правильная частота.

- что вы имеете в виду?

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

 

По поводу контроля регистров (RCC_CFGR) - нашел какую-то реализацию printf'a, люди пишут, что работает, вечером попробую запустить. И если все пойдет нормально, то можно будет контролировать все регистры настройки системы.

Share this post


Link to post
Share on other sites

ага добро пожаловать в мир СТМ, не хрена это не определяет.

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

Share this post


Link to post
Share on other sites

Вы про stm32f4xx.h-файл?

Там всякие определения/размещения регистров, маски, макросы управления битами.

Так-то по всей линейке (F4) вроде по регистрам должно быть полное соответствие (помнится где-то встречал такую фразу по СТМ).

Edited by billidean

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