We’re using BL4S200 boards and I need to pulse some outputs for short periods of time (on demand, not a periodic signal). Resolution must be in the 10th of microseconds range (e.g. a pulse of 100µs).
Having access to a kind of high resolution counter would have been nice, but it seems we only have a counter in the millisecond range.
At that resolution/duration, I’d say to write assembly code flagged as “__nodebug”, with interrupts disabled at the start and restored at the end.
Hopefully you won’t have anything else that will mind getting blocked for the duration of the pulse.
Take a look a the code referencing __numcycles_1us in “BLxS2xx.LIB” to see how it calculates delays.
You could also investigate the use of a Timer C interrupt to trigger code that will turn off the output after a specified time. This would avoid blocking other processes waiting for the duration of the pulse to end. Take a look at Samples/TIMERC/TIMER_C_INT.c for an example of a periodic interrupt in the millisecond range. You’d have to read through the Rabbit documentation on how to configure Timer C so that you can get a one-shot interrupt of a higher-resolution duration.
The other two samples in that directory demonstrate use of Timer C to control an output pin. It may be possible to use Timer C to generate a single pulse of a specific duration without any need to trigger an interrupt and execute code.
Here’s a sleep function based on Timer C. It’s not optimized, there’s no bound checking, but it can be used as a starting point. The code is based on the sample file “TIMER_C_INT.c”. Some definitions are in this file.
void SleepUs(word delayUs)
{
float timerCDivIdeal = (((float)delayUs/1000.0) * (float)MAIN_PCLK_FREQUENCY / 16. / 1000. - 1.);
// The actual timer C divider value is rounded to an unsigned long integer type.
unsigned long timerCDivider = (unsigned long)(timerCDivIdeal + 0.5);
// ensure timer C is disabled
WrPortI(TCCSR, &TCCSRShadow, 0x00);
WrPortI(TCDLR, NULL, (int)(0xff & timerCDivider));
WrPortI(TCDHR, NULL, 0xff & (timerCDivider/0x100));
timerc_count = 0;
// enable timer C
WrPortI(TCCSR, &TCCSRShadow, 0x01); // enable timer C
while (timerc_count < 1) { }
WrPortI(TCCSR, &TCCSRShadow, 0x00); // disable timer C
}
int main(void)
{
int i;
unsigned long start, end;
printf("Rabbit's peripheral clock frequency is taken to be %.4f MHz.
",
MAIN_PCLK_FREQUENCY / 1.e6);
printf("The ideal (to 2 decimal places) timer C divider value is %.2f.
",
TIMERC_DIVIDER_IDEAL);
printf("The actual timer C divider value used herein is %lu.
",
TIMERC_DIVIDER);
printf("If perfect clocks, an approximate %.4f%% count error is expected.
",
(TIMERC_DIVIDER_IDEAL / TIMERC_DIVIDER - 1.) * 100.);
// ensure timer C is disabled
WrPortI(TCCSR, &TCCSRShadow, 0x00);
// set up timer C to use pclk/16
WrPortI(TCCR, &TCCRShadow, 0x09);
// install timer C's ISR
SetVectIntern(TIMERC_OFS / 0x10, timerC_isr);
// The very first call is not accurate, because there's an extra interrupt.
SleepUs(1000);
// Now let's busy-wait many times to check if it's accurate enough.
start = MS_TIMER;
for (i = 0; i < 500; ++i)
{
SleepUs(1000);
}
end = MS_TIMER;
printf("time elapsed == %lu ms timerc_count=%lu
", end - start, timerc_count);
}