I've been working on an application and I'm having problems getting an accurate timing result from a timer interrupt. I've set the priority to zero and because I noticed the audio and sd drivers use this level tried compiling a version of Circle OS 3.8 with those set to 1 just in case, although I wouldn't have been expecting any interrupt activity from those sources.
I cut out the relevant parts of the code into a small sample application to demonstrate. When the application displays 5:00 minutes have elapsed a stopwatch shows 5:18, so it's running about 6% slow. Does anyone have ideas on what I'm doing wrong?
#include <stdio.h>
#include "stm32f10x_tim.h"
#include "stm32f10x_nvic.h"
#include "stm32f10x_rcc.h"
#define __STM32F10x_H
#include "circle_api.h"
const char Application_Name[8+1] = {"Timer"}; // Max 8 characters
#define ACC_SAMPLE_RATE 160
int StopwatchTimer = 0;
void TIM3_IRQHandler( void ) __attribute__ ((interrupt ("IRQ")));
void TIM3_IRQHandler( void )
{
StopwatchTimer++;
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
}
enum MENU_code Application_Ini(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
UTIL_SetPll(SPEED_VERY_HIGH);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
TIM_TimeBaseStructure.TIM_Period = 72000000 / 0x10 / ACC_SAMPLE_RATE;
TIM_TimeBaseStructure.TIM_Prescaler = 0x1;
TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit( TIM3, &TIM_TimeBaseStructure );
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Timing;
/* in FWLib v1.0 : TIM_OCInitStructure.TIM_Channel = TIM_Channel_1; */
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; /* now in FWLib v2.0 */
TIM_OCInitStructure.TIM_Pulse = 0x0;
TIM_OC2Init( TIM3, &TIM_OCInitStructure ); /* changed against FWLib v2.0 */
/* TIM3 enable counter */
TIM_Cmd( TIM3, ENABLE );
/* Immediate load of TIM3 Precaler value */
TIM_PrescalerConfig( TIM3, 0x10, TIM_PSCReloadMode_Immediate );
/* Clear TIM3 update pending flag */
TIM_ClearFlag( TIM3, TIM_FLAG_Update );
/* Enable TIM3 Update interrupt */
TIM_ITConfig( TIM3, TIM_IT_Update, ENABLE );
#define TIM3_IRQ_ID 0x00B4
UTIL_SetIrqHandler(TIM3_IRQ_ID, TIM3_IRQHandler);
/* Enable the TIM3 Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init( &NVIC_InitStructure );
return MENU_CONTINUE_COMMAND;
}
void __io_putchar(char c) {}
void ShowStopwatch()
{
u32 mins, tenths;
char s[64];
mins = StopwatchTimer / ACC_SAMPLE_RATE / 60;
tenths = (StopwatchTimer / (ACC_SAMPLE_RATE / 10)) % 600;
DRAW_SetCursorPos(15, 60);
DRAW_SetCharMagniCoeff(2);
sprintf(s, "%02d:%02d.%01d", mins, tenths / 10, tenths % 10);
DRAW_Puts(s);
DRAW_SetCharMagniCoeff(1);
}
enum MENU_code Application_Handler(void)
{
if(BUTTON_GetState() == BUTTON_PUSHED)
{
BUTTON_WaitForRelease();
return MENU_Quit();
}
ShowStopwatch();
return MENU_CONTINUE; // Returning MENU_LEAVE will quit to CircleOS
}