VSYNC | LPC1768 Timers - tarasjg/mbed-vga GitHub Wiki

VSYNC

PWM, while multi-channeled, only has one timer counter register. While this permits interesting capabilities such as three-phase power, it limits us in the case we want one channel to trigger multiple times before another channel triggers. Fortunately, VSYNC is relatively slow. 'Relatively' meaning that the occasional instruction here or there to configure something will not throw it unusably out of spec. This introduces the potential use of the LPC1768's general purpose timers.

The 'wait()' function of mbed OS configures Timer 3 to the specified amount of time and consumes the CPU in a loop until that time has passed. To initialize and then break out of this loop, the wait command can add about 4-5us of time onto the initially specified loop (for whatever reason, it seems to be worse when the time is longer). Due to this, it's poor practice to use wait commands in time critical code. Fortunately, general purpose timers feature an external match functionality which enables external pin control without generating interrupts or creating loop lockups.

Similar to the PWM configuration, a register is set that resets the timer counter on match, as well as a register that specifies when to trigger a certain action. In this case the action is toggling the pin. Quickly after toggle, the timer is disabled and re-substantiated with the new timing information. While less than ideal, this method only introduces inaccuracies in the order of 10s of nanoseconds rather than the microsecond error of the wait command.

The following is an example of how to enable a timer for pin toggling:

    //power timer 3 (0/1 used by DMA)
    LPC_SC -> PCONP |= (1<<23);
    //set timer periph clock - CCLK/4 = 25MHz by default
    LPC_SC -> PCLKSEL1 |= (0<<12);
    //pin select (MAT3.1 on 0.11 -> DIP 27)
    LPC_PINCON -> PINSEL0 |= (3<<22);
    //pin mode
    LPC_PINCON -> PINMODE0 |= (1<<23);
    //set TC reset time
    LPC_TIM3 -> MR0 = 359200;
    //set reset on MR0
    LPC_TIM3 -> MCR |= (1<<1);
    //toggle at 331200
    LPC_TIM3 -> MR1 = 331200;
    //set toggle on match
    LPC_TIM3 -> EMR |= (1<<1);
    //enable toggle on match
    LPC_TIM3 -> EMR |= (3<<6);
    //timer enable
    LPC_TIM3 -> TCR |= 1;

The reset procedure involves setting bit 0 of the timer control register to 0, followed by reconfiguration of the toggle match register, two 'writes' to bit 1 of the timer control register to reset the timer counter and prescale counter, and then re-enabling the timer by writing 1 to bit 0 of the timer control register. This turns out to be about 4 or 5 cycles. Consolidation of the reset of the reset bit and the enable of the timer into a single store command can save a cycle since these values are contained in the same register.

Regardless, at 10ns per cycle - the timing error can be assumed to be insignificant. Exact details are obscured without inspection of the compiled code. Further reading can be found in the ARM Cortex-M3 Technical Reference Manual, here and here.