101 lines
3.0 KiB
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;
|
|
}
|
|
}
|