Reputation: 938
I have to configure system clock on my STM32F4 Discovery board and I cannot get it right. I used "System clock configuraction" program from STM website ( http://www.st.com/web/en/catalog/tools/PF257927# ). I've set HCKL to 168 and generated source file with PPL(HSI) option and pasted it to my project, calling generated SystemInit()
function. The generated source file in comments at its top indicates that ABP1 prescaler is set to 4. I've created a timer that should interrupt my program once a second:
NVIC_InitTypeDef NVIC_InitStructure;
TIM_TimeBaseInitTypeDef TIM_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_InitStructure.TIM_Period = 168000000 / 4; // clockspeed/prescaler
TIM_InitStructure.TIM_Prescaler = 0;
TIM_InitStructure.TIM_ClockDivision = 0;
TIM_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM5, &TIM_InitStructure);
TIM_ITConfig(TIM5, TIM_IT_Update, ENABLE);
TIM_Cmd(TIM5, ENABLE);
However my TIM5_IRQHandler
seems to be called every 0,5 second. Why is that? Am I doing something wrong or am I misunderstanding something?
Upvotes: 1
Views: 4556
Reputation: 71586
Here is some code I wrote for that board that uses the pll at 168Mhz and the timer and interrupt (blah). See if/how it compares to yours, I dont use their library
I highly recommend you start by polling first, get the system clock and timer configured one at thing at a time then get the interrupt as close to the core, clearing correctly, etc and the last step is to do an interrupt and handler.
//-------------------------------------------------------------------
void PUT32 ( unsigned int, unsigned int );
void PUT16 ( unsigned int, unsigned int );
unsigned int GET32 ( unsigned int );
unsigned int GET16 ( unsigned int );
//-------------------------------------------------------------------
#define RCCBASE 0x40023800
#define RCC_CR (RCCBASE+0x00)
#define RCC_PLLCFGR (RCCBASE+0x04)
#define RCC_CFGR (RCCBASE+0x08)
#define GPIODBASE 0x40020C00
#define TIM5BASE 0x40000C00
#define FLASH_ACR 0x40023C00
//-------------------------------------------------------------------
volatile unsigned int intcounter;
//-------------------------------------------------------------------
// CAREFUL, THIS IS AN INTERRUPT HANDLER
void tim5_handler ( void )
{
intcounter++;
PUT32(TIM5BASE+0x10,0x00000000);
}
// CAREFUL, THIS IS AN INTERRUPT HANDLER
//-------------------------------------------------------------------
void ClockInit ( void )
{
unsigned int ra;
//enable HSE
ra=GET32(RCC_CR);
ra&=~(0xF<<16);
PUT32(RCC_CR,ra);
ra|=1<<16;
PUT32(RCC_CR,ra);
while(1)
{
if(GET32(RCC_CR)&(1<<17)) break;
}
PUT32(RCC_CFGR,0x00009401); //PPRE2 /2 PPRE1 /4 sw=hse
//slow flash accesses down otherwise it will crash
PUT32(FLASH_ACR,0x00000105);
//8MHz HSE, 168MHz pllgen 48MHz pll usb
//Q 7 P 2 N 210 M 5 vcoin 1 pllvco 336 pllgen 168 pllusb 48
ra=(7<<24)|(1<<22)|(((2>>1)-1)<<16)|(210<<6)|(5<<0);
PUT32(RCC_PLLCFGR,ra);
// enable pll
ra=GET32(RCC_CR);
ra|=(1<<24);
PUT32(RCC_CR,ra);
//wait for pll lock
while(1)
{
if(GET32(RCC_CR)&(1<<25)) break;
}
//select pll
PUT32(RCC_CFGR,0x00009402); //PPRE2 /2 PPRE1 /4 sw=pllclk
//if you didnt set the flash wait states you may crash here
//wait for it to use the pll
while(1)
{
if((GET32(RCC_CFGR)&0xC)==0x8) break;
}
}
//-------------------------------------------------------------------
int notmain ( void )
{
unsigned int ra;
unsigned int lastcount;
unsigned int newcount;
ClockInit();
ra=GET32(RCCBASE+0x30);
ra|=1<<3; //enable port D
PUT32(RCCBASE+0x30,ra);
ra=GET32(RCCBASE+0x40);
ra|=1<<3; //enable TIM5
PUT32(RCCBASE+0x40,ra);
//d12 = d15 led outputs
ra=GET32(GPIODBASE+0x00);
ra&=0x00FFFFFF;
ra|=0x55000000;
PUT32(GPIODBASE+0x00,ra);
//push pull
ra=GET32(GPIODBASE+0x04);
ra&=0xFFFF0FFF;
PUT32(GPIODBASE+0x04,ra);
//start with green led
PUT32(GPIODBASE+0x18,0xE0001000);
//setup timer
PUT32(TIM5BASE+0x00,0x00000000);
PUT32(TIM5BASE+0x2C,168000000/4); //auto reload
PUT32(TIM5BASE+0x0C,0x00000001); //interrupt enable
PUT32(TIM5BASE+0x10,0x00000000); //clear interrupt
PUT32(TIM5BASE+0x00,0x00000001);
intcounter = 0;
//enable interrupt 50 TIM5
PUT32(0xE000E104,0x00040000);
lastcount = intcounter;
while(1)
{
newcount=intcounter;
if(lastcount!=newcount)
{
switch(lastcount&0x3)
{
case 0: PUT32(GPIODBASE+0x18,0xE0001000); break;
case 1: PUT32(GPIODBASE+0x18,0xD0002000); break;
case 2: PUT32(GPIODBASE+0x18,0xB0004000); break;
case 3: PUT32(GPIODBASE+0x18,0x70008000); break;
}
lastcount=newcount;
}
}
return(0);
}
//-------------------------------------------------------------------
//-------------------------------------------------------------------
Some notes I wrote about what I saw at the time:
TIM5 is actually a 32 bit counter not 16 like many of the others. If we count to 168,000,000 * 4 ticks that should be 4 seconds right? Well we get 8 seconds per led blink. I think what is going on is there are two AHB divisors PPRE1 and PPRE2 with different speed limits. To keep PPRE2 at or under 84Mhz it wants a divide by 2, to keep PPRE1 under 42MHz it wants a divide by 4. The clock tree diagram doesnt really show these two divisors (that I can see) but it has a thing for the timers where if divisor is non-zero then multiply by 2. I assume what this all means is PPRE1 which is a divide by 4 is multiplied by 2 to feed the timers. And that appears to match, if you change PPRE1 to divide by 8 and the it takes 16 seconds for the led to change.
So I saw it being too long, you are seeing it be too short by a power of 2? I am using the external source you are using internal?
Upvotes: 1