Monday, 4 August 2014

Some other uses for the LPC810 Multi Rate Timer (MRT)

In the last post a clock cycle accurate delay which stalled the CPU bus rather than eat up CPU cycles was created using the Multi Rate Timer while in this post we  look at some other simple uses for the remaining 3 channels of the MRT.

A Millisecond delay routine on channel 2, this delay routine will poll the Status register to see if the timer is still running and consume CPU cycles whist running, it will not however block interrupts which is necessary for long delays although a callback timer shown below may be more appropriate in some cases.

/* Delay by a number of milliseconds
 * Note the divide of SystemCoreClock will affect the accuracy
 * The overhead is approximately 286 +/- 10 (varies with the actual divide) clock cycles which is about 24us @ 12MHZ
 * Uses channel 2 of the MRT
 */

void delay_ms(int delay) {
 LPC_MRT->Channel[2].INTVAL = (((SystemCoreClock / 250L) * delay) >> 2)
   - 286 ;
 while (LPC_MRT->Channel[2].STAT & 0x02)
  ; //wait while running
}

It is initilized like so

 LPC_MRT->Channel[2].CTRL = (0x01 << 1); //MRT2 (delay_ms) single shot mode , no interrupts

A Profile timer on channel 1

/* Profiler on MRT Channel 1 */
volatile static uint32_t __profile_clocks;
#define PROFILE_START()  LPC_MRT->Channel[1].INTVAL = 0xffffffff //Force count down from max value
#define PROFILE_STOP()  __profile_clocks = LPC_MRT->Channel[1].TIMER //snatch timer value
#define PROFILE_COUNT()  (0x7fffffffUL - 8 - __profile_clocks )   //Return the number of clock cycles counted
#define PROFILE_PREPARE() (__profile_clocks)// fudge to even init clock cycles



The Profile timer is initilized like so

 LPC_MRT->Channel[1].CTRL = (0x01 << 1); //MRT1 (Profiler) single shot mode , no interrupts

and used like below

PROFILE_PREPARE();
PROFILE_START();
halt_clk(30);
PROFILE_STOP();
xprintf("30 profile clocks are %d\n\r",PROFILE_COUNT());

Finally on channel 0 we have a timer function that will execute a callback function after a specified amount of clock cycles, it can be made to repeat or used as a single shot timer.

/* timer()
 * the timer() function executes callback after clk clock cycles
 * repeat signals if the callback is to be repeated.
 * Uses MRT Channel 0
 */
void (*__callback)(void);

void timer(int clk,void (*callback)(void),bool repeat){
 if (repeat)
  LPC_MRT->Channel[0].CTRL = 0x1 ; /* MRT0 repeat mode , interrupts enabled */
 else
  LPC_MRT->Channel[0].CTRL = (0x01 << 1) | 0x1 ; /* MRT0 single shot mode , interrupts enabled */
 __callback = callback;
 LPC_MRT->Channel[0].INTVAL = clk | (1 << 31);
ISER[0] = (1 << 10); /* enable interrupts */
}
/* MRT_IRQHandler used for timer() function */
void MRT_IRQHandler(void){
 LPC_MRT->Channel[0].STAT = 0x1 ; /* clr interupt request */
 if (__callback)
  __callback();

}



No comments:

Post a Comment