How to pulse an output

Hello,

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.

What would be the best way of doing that?

Thank you
Simon

1 Like

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.

I’ll try with Timer C, thank you

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);
}

1 Like