zoom/firmware/timer.c

101 lines
3.0 KiB
C

#include "config.h"
#include "timer.h"
/* Setup a 16-bit timer to overflow at the specified frequency
timer = 1-9
freq = Hz, or 0 to disable the timer.
interrupt = 1 to enable interrupt, 0 to disable
*/
int timer_setup_16bit(int timer, uint32_t freq, int ie)
{
uint32_t period;
uint16_t prescale;
if (timer < 1 || timer > 9)
return -1;
if (freq == 0) {
switch(timer) {
case 1: T1CONbits.TON = 0; return 0;
case 2: T2CONbits.TON = 0; return 0;
case 3: T3CONbits.TON = 0; return 0;
case 4: T4CONbits.TON = 0; return 0;
case 5: T5CONbits.TON = 0; return 0;
case 6: T6CONbits.TON = 0; return 0;
case 7: T7CONbits.TON = 0; return 0;
case 8: T8CONbits.TON = 0; return 0;
case 9: T9CONbits.TON = 0; return 0;
}
}
/* Figure out timer prescaler and period values. Max period
is 65535 (PRx = 65534) so we can still attain 100% duty
cycle when using a timer for PWM. */
if ((period = FCY / (freq * 1L)) <= 65535)
prescale = 0;
else if ((period = FCY / (freq * 8L)) <= 65535)
prescale = 1;
else if ((period = FCY / (freq * 64L)) <= 65535)
prescale = 2;
else if ((period = FCY / (freq * 256L)) <= 65535)
prescale = 3;
else
prescale = 3, period = 65535;
if (period > 0)
period -= 1;
switch (timer) {
#define __timer_setup_case(x) \
case x: \
T##x##CONbits.TON = 0; \
T##x##CONbits.TCKPS = prescale; \
PR##x = period; \
T##x##CONbits.TON = 1; \
break
__timer_setup_case(1);
__timer_setup_case(2);
__timer_setup_case(3);
__timer_setup_case(4);
__timer_setup_case(5);
__timer_setup_case(6);
__timer_setup_case(7);
__timer_setup_case(8);
__timer_setup_case(9);
#undef __timer_setup_case
}
/* Enable interrupt if requested */
timer_clear_txif(timer);
switch (timer) {
case 1: IEC0bits.T1IE = ie; break;
case 2: IEC0bits.T2IE = ie; break;
case 3: IEC0bits.T3IE = ie; break;
case 4: IEC1bits.T4IE = ie; break;
case 5: IEC1bits.T5IE = ie; break;
case 6: IEC2bits.T6IE = ie; break;
case 7: IEC3bits.T7IE = ie; break;
case 8: IEC3bits.T8IE = ie; break;
case 9: IEC3bits.T9IE = ie; break;
}
return 0;
}
/* sleep for between "ms" and "ms+1" milliseconds */
void msleep(int ms)
{
static int initialized = 0;
if (!initialized) {
timer_setup_16bit(1, 1000, 0);
initialized = 1;
}
/* Very basic, assumes timer1 is set up at 1 khz */
while (ms-- >= 0) {
IFS0bits.T1IF = 0;
while(IFS0bits.T1IF == 0)
continue;
}
}