CTL High resolution timer
Hi,
Could someone please advise me on the best way to implement a high resolution timer whilst using and without breaking CTL?
At present we are using an 8MHz crystal and running at 72MHz. I need some fine resolution timing for things like dallas, generating square waves on a GPIO to drive a buzzer etc. What would be the simplest wait to give me an equivalent of:
#define WAIT_TICKS(x) ctl_timeout_wait(ctl_get_current_time()+x);
but where x is microseconds rather than milliseconds?
Processor is Cortex M3.
Thanks for your help,
Jo
-
Hi Michael,
Thanks for the fast response, much appreciated.
My experience thus far has always been using OS provided timers, either CTL (ms) or OS-20 (15xxx ticks persecond). The OS20 tick was always fine enough. My concern is using the hardware clocks and knocking CTL out of kilter. Also since I have not used them directly before I have no sample code, I don't suppose you could point me to a code snippet I could work from?
I have the "Definitive Guide To The Arm Cortex-M3" so hopefully I can find the answer in there.
Another thought I had is whether or not it would be possible to increase the frequency of SysTickHandler and use a counter to call a newly written high-resolution ISR and call the CTL ISR every ms?
Thanks for your help,
Jo
-
What flavour of Cortex -M3 are you using? Is it STM32? If so that's what we use and my advice would be to leave the SysTick purely for CTL and use the hardware timers. There should be plenty of timer peripherals whatever uP it is, and the SysTick is designed for just this purpose. Using the hardware clcoks won't knock CTL out of kilter, unless you do something REALLY bad (like write an ISR that takes 10's of msec to execute).
We have implemented a Delay(usec) function that uses TIM1 of the STM32 and would be happy to provide some sample code snippets (without giving away my companies IP of course) if that would help
Cheers,
Wolf
-
No probs.
This code sets up TIM1 as a free-running 1MHz timer. I have used Rowley's standard register & bit definitions from their STM32F10x.h header (supplied with the CPU support package). Note that this assumes you are running TIM1CLK clock at 36MHz (which you probably are if you're running at 72MHz).
The Delay() function has a maximum limit of 1/2 the maximum of the counter register (so 32767 for a 16-bit counter). This avoids any nasty wrap-around problems.
Note that this doesn't actually use up any of the TIM1 CCR's. We also use TIM1's CCR2 to trigger ADC scanning (at a rate of 1KHz) and CCR1 to trigger our TTCAN implementation. It's a bit complicated in that you can't get a 1KHz square wave by just setting a CCR to 1000 - you have to reload it in the ISR with 2000, 3000, 4000, etc, but it means we can use 1 timer for quite a few things at once.
Enjoy.
Wolf
//Initialisation:
#define TIMER_FREQUENCY 1000000 // 1MHzvoid Init()
{
// Enable Peripheral Clock
RCC_APB2ENR |= RCC_APB2ENR_TIM1EN;
// De-init TIM1 peripheral registers to their default reset values.
RCC_APB2RSTR = RCC_APB2RSTR_TIM1RST;
RCC_APB2RSTR = 0;// Clock Division = 0
// Auto-Reload Preload = NOT buffered
// Edge-Aligned mode
// Direction = UP
// One Pulse Mode = Off
// Update Request can be anything
// Update Event = Enabled
// Counter Disabled (for now)
TIM1_CR1 = 0;// Free-Running Period
TIM1_ARR = 0xFFFFu;
// Time-Base configuration - Scale to fixed Frequency of 1MHz
TIM1_PSC = (36000000 / TIMER_FREQUENCY) - 1;
// No Repetition Counter
TIM1_RCR = 0;// Force an update to load our ARR and Pre-Scalar shadow registers
TIM1_EGR = TIM1_EGR_UG;
// Enable the Counter
TIM1_CR1 |= TIM1_CR1_CEN;
}
// Blocking usec delay function. Designed to be re-entrant.
#define MAX_DELAY INT16_MAX // 32767 usec Max
void Delay(uint16 usec)
{
uint16 timeout = TIM1_CNT;// Conversion = (usec / 1MHz) * Freq
if (usec <= MaxDelay)
{
timeout += (uint16)(((uint32)usec * (TIMER_FREQUENCY / 1000uL)) / 1000uL);
}
else
{
timeout += (uint16)(((uint32)MAX_DELAY * (TIMER_FREQUENCY / 1000uL)) / 1000uL);
}
// This method provides very simple wrap-around handling, BUT limits the
// range to half of the available bits (due to the cast from unsigned to
// signed). For this function, we don't care about getting the full 16-bit
// range so simpler is better.
while ((int16)(timeout - TIM1_CNT) >= 0)
;
} -
No worries. Happy to help.
One thing to watch out for - if you want to use TIM1 to trigger the ADC, you need to have the Main Output enabled (MOE bit of BTDR register). You don't need to bring the CCR all the way out to it's I/O pin, but you do need the MOE on (took me ages to figure that out!).
I.E. at the end of your initialisation function, add this...
// TIM1 Main Output Enable (allows ADC to trigger)
TIM1_BDTR |= TIM1_BDTR_MOE;Cheers and Good Luck!
Wolf
Please sign in to leave a comment.
Comments
7 comments