jenswilly.dk


Repetitive Interrupt Timer on LPC1347

For my ROV project I need to control an RC servo to tilt the camera up and down. I've gotten that working nicely using a 16-bit timer to generate an appropriate PWM waveform.

But when I change the the position by a lot – for example, going from one endpoint to the middle position – the servo moves too fast. (Which, incidentally, draws a huge current which makes my 5 V rail drop enough to reset the MAX7456 – but that is fixable.) So I need to slow the movement down by gradually changing the position instead of jumping straight from one position to another.

The full servo movement corresponds to a change in timer match value by 1000 (the PWM timer is set up so the match values correspond to PWM pulse on-time in microseconds so minimum is 1000 and maximum is 2000). I would like the full range of movement to take one second so I thought that changing the position in increments of 10 at a frequency of 100 sounds about right.

Unfortunately, I'm fresh out of timers: CT32B0 and -1 are used for motor control PWM, CT16B0 is used for periodic analog-to-digital conversions (for the pressure sensor used as depth gauge) and CT16B1 is used for servo PWM. Yeah, sure, I guess I could use a timer for more than one purpose but since the LPC1347 actually has one more timer, I might as well use that: the Repetitive Interrupt Timer.

The Repetitive Interrupt Timer (RIT for short) generates interrupts every X clock cycles and if I configure the timer to fire an interrupt every 720,000 clock cycles I get a 100 Hz interrupt (on a 72 HMz PCLK) in which I can move the servo if necessary. Nice.

This is the code I came up with:

Repetitive Interrupt Timer on LPC1347

// MIN and MAX macros
#ifndef MIN
#define MAX(a,b) (((a)>(b))?(a):(b))
#define MIN(a,b) (((a)<(b))?(a):(b))
#endif

// Servo position variables
volatile uint16_t servo_position;
volatile uint16_t servo_target;

// Stop RI timer – otherwise we can't reset the counter
LPC_RITIMER->CTRL = 0;

// Init RI timer (we don't need to enable timer – it is always running as per the updated User Manual UM10524)
LPC_RITIMER->COMPVAL = 720000;
LPC_RITIMER->COMPVAL_H = 0;

// Reset counter (otherwise it might already be above the compare value and then it would take a loong time to overflow to zero)
LPC_RITIMER->COUNTER = 0;
LPC_RITIMER->COUNTER_H = 0;

// Set RITENCLR (clear on match), RITENBR (halt timer on debug) and RITEN (start timer)
LPC_RITIMER->CTRL = (1<< 1) | (1<< 2) | (1<< 3);

// Enable RIT interrupt
NVIC_EnableIRQ( RIT_IRQn ); 

// Interrupt routine 
// (Yes, it's a little weird that the interrupt routine is called OSTIMER but the NVIC interrupt is called RIT_IRQn)
void OSTIMER_IRQHandler()
{
    // Clear interrupt
    LPC_RITIMER->CTRL |= (1<< 0);   // Write RITINT to clear

    // If we're at target, do nothing
    if( servo_position == servo_target )
        return;

    if( servo_target > servo_position )
        servo_position += MIN( servo_target - servo_position, 10 );
    else // Not equal and not greater than, so it's less than – we don't need to check
        servo_position -= MIN( servo_position - servo_target, 10 );
}

4 comments on "Repetitive Interrupt Timer on LPC1347"
BC says:

// Reset counter (otherwise it might already be above the compare value and then it would take a loong time to overflow to zero)
LPC_RITIMER->COUNTER = 0;
LPC_RITIMER->COMPVAL_H = 0; <-----should this be COUNTER_H???

Jens Willy Johannsen says:

@BC: Yes, it should indeed - well spotted. I've fixed the code example. Thanks.

BC says:

Jens - I am trying to stop / disable / clear the RIT using a different interrupt (systick). I have tried:

NVIC_DisableIRQ(RIT_IRQn); //disable interrupt
LPC_RITIMER->CTRL &= ~(1<CTRL &= ~(1<CTRL |= (1<COUNTER = 0; //reset counter
LPC_RITIMER->COUNTER_H = 0; //reset counter

...but, this only prevents the interrupt for executing upon the following interrupt. The code returns to the RIT and finishes executing. It does not abort the interrupt immediately. Do you know how to abort in the middle of the RIT and "restart" at the beginning of the interrupt?

Thanks,

BC

Jens Willy Johannsen says:

@BC: I'm not sure if you can abort an interrupt handler. Other than setting a globally accessible variable from the SysTick interrupt and then checking that at appropriate places in the RIT interrupt handler and return if it is set…

Leave a Reply