Friday, January 4, 2013

Generating a clock signal with dsPIC33F

 dsPIC33F generates a 500kHz clock signal
Generating a 500kHz clock signal with the dsPIC33F to run a Game Boy camera entails using Timer2 or Timer3 and one of the Output Compare peripherals. Here's how...

Toggle Mode

The simplest way to generate a clock signal is to use Toggle Mode of one of the Output Compare peripherals. I'll choose Timer2 and Output Compare 1. Every time the TMR2 matches OC1R, a pin will be toggled. If we set the Timer2 period to 1usec, the period of the resulting signal will be twice that, or a frequency of 500kHz.

Setting up the timer is relatively straightforward. Set the prescale to 1:1 by setting the TCKPS bits of the T2CON register to 0. Then set the Timer2 period register, PR2, to 40 to get our 1MHz toggle frequency.

Next, we have to set up the output pin that will deliver the clock signal.. One can map the output compare peripheral to any remappable pin you like. I chose RP13 (RB13). Just set RP13_O = OC1_O or to spell it out, RPOR6bits.RP13R = 0b10010.

Then, set the output compare register. Any value less than PR2 will work for this simple example. When the timer counter TMR2 matches OC1R, the output pin will toggle.

If we had both output compare registers running off the same timer, we could change the phase between them by changing OC1R and OC2R. That is, if OC1R were 0 and OC2R were 20 with a PR2 of 40, then OC1 would toggle in sync with Timer2's period while OC2 would toggle halfway between the Timer2 period.

I set up such an experiment, with OC1R = 0 and OC2R = 2000 with a PR2 = 4000. Here are the resulting waveforms, with output compare 1 on top, 2 on the bottom.

 Using timer2 with OC1 and OC2, phase shifted

Continuous Pulse Mode

Toggle Mode is interesting and all, but the dsPIC needs to do more than generate a clock signal. To configure the camera's internal registers, data is sent serially. Each data bit is synchronized with the rising edge of the clock signal. Here's the timing diagram reproduced from the M64282FP camera datasheet.
There's a way to make this happen by using Timer2, configuring the output compare peripheral to use Continuous Pulse Mode instead of Toggle Mode, and using an interrupt handler to shift out the bits. Let's start by getting the timer going.

In Toggle Mode, the output pin changes state every time the timer counter matches OC1R the primary output compare register. Continuous Pulse Mode changes the pin state whenever there's a match with OC1R and also the secondary output compare register, OC1RS. Here's what these two modes look like.

 Toggle Mode and Continuous Pulse Mode timing
What we want is a timer period of 200 (that is, 40MHz / 200 = 500kHz), and we want the on period to be 100 and the off period to be 100. If we set OC1R to 50 and OC1R to 150, the on time is between 50 and 150 with a duration of 100, while the off time starts at 150 and ends at 50, also with a duration of 100.

/* setup timer2 */
T2CONbits.T32 = 0; // timer2: disable 32-bit timer mode
T2CONbits.TCKPS = 0; // timer2: prescale 1:1
T2CONbits.TCS = 0; // timer2: asynch
T2CONbits.TGATE = 0; // timer2: non-gated
PR2 = 200; // timer2: 40MHz / 80 = 500kHz (2us period)

// phase shift the output pulse versus timer
OC1R = 50;
OC1RS = 150;
OC1CONbits.OCM = 0b101; // oc1: toggle mode
OC1CONbits.OCTSEL = 0; // oc1: timer2 source

Timer and Output Compare Interrupts

The dsPIC, like many microcontrollers, can fire an interrupt based on timer events. The dsPIC can interrupt on timer period matches as well as output compare matches. Before I get to writing the interrupt handler to shift bits out to the camera, first I'll toggle another pin with our interrupt handler.

RB12 will be the new signal pin. Initialize the tristate register with TRISBbits.TRISB12 = 0 and toggle the pin with LATBbits.LATB12 = ~LATBbits.LATB12 in the interrupt handler.

Our interrupt handler looks like this.

void __attribute__ ((interrupt,no_auto_psv)) _T2Interrupt(void)
{
LATBbits.LATB12 = ~LATBbits.LATB12;
}

After we've set up the timer and output compare registers, enable the Timer2 interrupt with the corresponding Interrupt Enable bit in the IEC0 register: IEC0bits.T2IE = 1

The interrupt fires when TMR2 matches PR2, a 5 cycle latency occurs to handle the interrupt, then the output pin is toggled. So while the clock is happily being generated, the period interrupt handler can change output bits between clock edges on RB12.

 Interrupts occur at period match, red line/peak

Sending the serial configuration data is the next step but we'll get to that another time.