There are enough examples of reading stuff with ICP.
- You cant have a top value for the counter, or you will get fucked up readings because of wrap-arounds.
-> Top must be 0xFFFF, choose different counter mode.
- The hardware stores the counter value at external pin change, the interrupt then reads this stored value.
-> Read the ICR5 register instead of micros().
This way you get NO problems with wrap-arounds (do 16bit uint).
This way you get ZERO jitter even if interrupt is delayed.
This way you get much FINER resolution than micros() can ever give you.
You may not be able to use the icp timer for pwm, or you may have to compromise on pwm / icp frequency.
Using ICP you may then ditch the whole RC signal averaging/deadband stuff and enjoy the snappiness of hardware enhanced precision.
Good read on topic:
http://www.atmel.com/images/doc2549.pdfI consider the possibility for such a patch to make it into the mainstream "shared" as pretty low. Unless we make a lot of noise.
This is some timer1 code ICP from another project (dumbed down to 8 bit resolution):
Code: Select all
volatile uint16_t last = 0;
volatile uint8_t chan = 0;
#if defined(ICP)
ISR(TIMER1_CAPT_vect)
{
uint16_t now,diff;
now = ICR1;
diff = now - last;
last = now;
if (diff>6000) chan = 0; // Sync gap
else if (chan < RC_CHANNELS)
{
if (1800<diff && diff<4200)
{
if (diff <= 2000) rcValue[chan] = 0;
else if (diff >= 4000) rcValue[chan] = 255;
else rcValue[chan] = (diff - 1976) >> 3;
chan++;
}
else chan = 20;
}
else if (chan == RC_CHANNELS)
{
gotir = 1;
chan++;
}
}
void InitPPMin()
{
// Setup timer1 for input capture (PSC=8 -> 0.5ms precision, top at 20ms)
TCCR1A = 0;
TCCR1B = (1 << CS11) | (1 << ICNC1) | (1 << ICES1);
TIMSK1 |= (1 << ICIE1); // Enable timer1 input capture interrupt
}
#else // sample PPM using pinchange interrupt