/*
 * pwm_light.c
 */


#include <xc.h>

#define PERIOD_LOW   312
#define PERIOD_HIGH  31250

void timer_setup(void)
{
  T0CONbits.TMR0ON = 0; // stop the timer
  T0CONbits.T08BIT = 0; // timer configured as 16-bit
  T0CONbits.T0CS = 0; // use FOSC
  T0CONbits.PSA = 0; // use prescaler
  T0CONbits.T0PS = 0b111; // prescaler 1:256

  INTCONbits.T0IF = 0; // reset timer interrupt flag
  INTCONbits.T0IE = 0; // no interrupts timer interrupts

  T0CONbits.TMR0ON = 1; // start the timer
}

void adc_setup(void)
{
    ANSELAbits.ANSA0 = 1; // RA0 = analog input

    ADCON1bits.PVCFG = 0b00; // Positive reference = +VDD
    ADCON1bits.NVCFG = 0b00; // Negative reference = GND

    ADCON2bits.ADFM = 1; // format = right justified
    ADCON2bits.ACQT = 0b111; // acquisition time = 20*TAD
    ADCON2bits.ADCS = 0b110; // conversion clock = FOSC/64

    ADCON0bits.ADON = 1; // turn on ADC
}

int main(void)
{
    int period = PERIOD_HIGH;

    TRISBbits.TRISB0 = 0; // output

    timer_setup();

    TMR0 = -period;
    adc_setup();

    ADCON0bits.CHS = 0; // select channel 0 (AN0)
    ADCON0bits.GODONE = 1;

    for (;;) {
        while (INTCONbits.TMR0IF != 1) ;
        LATBbits.LATB0 = !LATBbits.LATB0;
        INTCONbits.TMR0IF = 0;

        if (ADCON0bits.GODONE == 0) {
            // conversion completed
            period = PERIOD_LOW + ADRES * ((PERIOD_HIGH - PERIOD_LOW) / 1024);
            // retrigger conversion
            ADCON0bits.GODONE = 1;
        }

        TMR0 = -period;
    }
    return 0;
}
