/*
  This simple program makes writes the time to the screen (Secure CRT), makes 
  LEDs flash, and reads from a variable resistor 
  It used timer1 and interupts
*/

#include <p30f6015.h>

#define	FCY	117920000
#include <libpic30.h>
#include <delay.h>
#include <adc10.h>
#include <pwm.h>
#include <uart.h>
#include <string.h>
#include <stdio.h>
#include <qei.h>
#include <timer.h>
#include <ports.h>

#define PERIOD  7300 // for 1000 Hz pwm frequency
#define MAX_DUTY 2*7300 // MAX_DUTY = 2*PERIOD since pwm prescaler is 2

// Configuration Bits
_FOSC(CSW_FSCM_OFF & FRC_PLL16); //FRC 7.37MHz * 16 = 117.92MHz/29.48MIPS Tcy=33.9nS
_FWDT(WDT_OFF);  // watchdog timer off
_FBORPOR(PBOR_OFF & BORV27 & PWRT_16 & MCLR_EN);  //brown out parameters
_FGS(GWRP_OFF);

// define some variables

unsigned int AD_value;
unsigned int GO;

/***********************************************************************/

// external input interupt handler

void __attribute__((interrupt,no_auto_psv)) _INT4Interrupt( void )
{
  unsigned int dutycyclereg, dutycycle;
  char updatedisable;

  // turn off the pwm signal

  dutycycle = (unsigned int)0;
  dutycyclereg = 3;
  updatedisable = 0;
  SetDCMCPWM( dutycyclereg, dutycycle, updatedisable );  // duty cycle set to low

  
  // turn off the LED to indicate power if off

  TRISDbits.TRISD7 = 0;
  PORTD = 0b0000000100000000;  // signal the power is off
  
  // Disable the interrupt

  DisableINT4;

  // now just wait

  while(1);
}

/***********************************************************************/

// timer 1 interupt handler

void __attribute__((interrupt,auto_psv)) _T1Interrupt( void )
{ 
  unsigned int ReadQEI( void );
  extern unsigned int AD_value;
  extern unsigned int GO;

 // read from the A/D channel

  ADCON1bits.SAMP = 1; // start the sampling
  while(!ADCON1bits.DONE);
  AD_value = ReadADC10(0);

  // reset Timer 1 interrupt flag 

  IFS0bits.T1IF = 0;

  // we have a new value

  GO = 1;
}

/****************************************************************************************************/ 

// Initialize external interrupt 4

void Init_INT4(void)
{
  unsigned int config;

  config = FALLING_EDGE_INT & // interrupt on a falling edge
           EXT_INT_ENABLE &        // enable the interrupts
           //EXT_INT_PRI_0 ;
           GLOBAL_INT_ENABLE;
            
  ConfigINT4( config );


   // turn on the LED to show interrupt is set

  TRISDbits.TRISD7 = 0; 
  PORTD = 0b0000000010000000;  // signal the interrupt is set

  // prepare for an input on RD11

  TRISDbits.TRISD11 = 1;

  // enable the interrupt

  DisableINT4;
  EnableINT4;

  return;
}
/****************************************************************************************************/ 

// Initialize timer 1

void Init_Timer1( unsigned int period )
{
  unsigned int config;

  config = T1_INT_PRIOR_4 & // set interrupt priority to 2
           T1_INT_ON;       // enable the interrupts
            
  ConfigIntTimer1( config );

  config =  T1_ON &  // turn on the timer
            T1_IDLE_CON & // operate during sleep
            T1_GATE_OFF & // timer gate accumulation is disabled
            T1_PS_1_256 &   // timer prescale is 256
            T1_SYNC_EXT_OFF & // don't synch with external clock
            T1_SOURCE_INT; // use the internal clock

  OpenTimer1( config, period );

  return;
}

/***********************************************************************/

// setup ADC10

  void adc_init(void){

  unsigned int config1, config2, config3, configport, configscan;

  ADCON1bits.ADON = 0 ; // turn off ADC

  SetChanADC10(
       ADC_CH0_NEG_SAMPLEA_VREFN & // negative reference for channel 0 is VREF negative
       ADC_CH0_POS_SAMPLEA_AN3    // 
      // ADC_CHX_NEG_SAMPLEA_VREFN &  // negative reference for channel 1 is VREF negative
      // ADC_CHX_POS_SAMPLEA_AN3AN4AN5
                 );

  ConfigIntADC10( ADC_INT_DISABLE ); // disable the interrupts

  config1 = 
       ADC_MODULE_ON &  //turn on ADC module
       ADC_IDLE_CONTINUE & // let it idle if not in use
       ADC_FORMAT_INTG &   // unsigned integer format
       ADC_CLK_AUTO  &  // manual trigger source
       ADC_AUTO_SAMPLING_OFF  & // do not continue sampling
       ADC_SAMPLE_SIMULTANEOUS & // sample both channels at the same time
       ADC_SAMP_ON; // enable sampling

  config2 = 
       ADC_VREF_AVDD_AVSS & // voltage reference
       ADC_SCAN_OFF & // don't scan
       ADC_CONVERT_CH0 & // convert channel 0
       ADC_SAMPLES_PER_INT_1 & // 1 samples per interupt
       ADC_ALT_BUF_OFF & // don't use the alternate buffer
       ADC_ALT_INPUT_OFF; // don't use an alternate input

  config3 = 
       ADC_SAMPLE_TIME_2 & // auto sample time bits
       ADC_CONV_CLK_SYSTEM & // use the system clock
       ADC_CONV_CLK_13Tcy;  // conversion clock speed (coeff of TCY is ADCS)
       
  configport = 
        ENABLE_AN3_ANA;   // parameters to be configured in the to ADPCFG 

  configscan = 
       SCAN_NONE; // scan select parameter for the ADCSSL register
  
  OpenADC10( config1, config2, config3, configport, configscan );
}

/*****************************************************************/

// setup pwm

  void pwm_init(void){

  unsigned int config1, config2, config3;
  unsigned int sptime;

  config1 = PWM_INT_DIS &     // disable the interrupt
            PWM_FLTA_DIS_INT; // disable the interrupt on fault

  ConfigIntMCPWM( config1 );

  config1 = PWM_EN & //  enable the PWM module
            PWM_IPCLK_SCALE4 & // input prescaler set to 2
            PWM_OP_SCALE1 & // post scalar set to 1
            PWM_MOD_UPDN; // free running mode

  config2 = PWM_MOD1_IND & // pwm modules run independently
            PWM_MOD2_IND & 
            PWM_MOD3_IND & 
            PWM_MOD4_IND & 
            PWM_PDIS1H & // disable 1 high
            PWM_PDIS2H & // disabale 2 high
            PWM_PDIS3H & // enable 3 high
	    PWM_PDIS4H  & // disable 4 high
            PWM_PDIS1L & // disable 1 low
            PWM_PDIS2L & // disable 2 low
            PWM_PDIS3L &  // disable 3 low
            PWM_PDIS4L ;  //disable 4 low

  config3 = PWM_UEN; // enable updates

  sptime = 0x0;

  OpenMCPWM( PERIOD, sptime, config1, config2, config3 );

}

/*****************************************************************/

// setup the UART

 void uart1_init(void) {
 
unsigned int config1, config2, ubrg;

config1 = UART_EN & // enable the UART
          UART_IDLE_CON & // set idle mode
          UART_DIS_WAKE & // disable wake-up on start
          UART_DIS_LOOPBACK & // disable loopback
          UART_DIS_ABAUD & // diable autobaud rate detect
          UART_NO_PAR_8BIT & // no parity, 8 bits
          UART_1STOPBIT;     // one stop bit

config2 = UART_INT_TX_BUF_EMPTY & // interrupt anytime a buffer is empty
          UART_TX_PIN_NORMAL & // set transmit break pin
          UART_TX_ENABLE & // enable UART transmission
          UART_INT_RX_CHAR & // recieve interrupt mode selected
          UART_ADR_DETECT_DIS & // disable address detect
          UART_RX_OVERRUN_CLEAR; // overrun bit clear

ubrg = 15; // 11520 baud

OpenUART1( config1, config2, ubrg); 
}

/*****************************************************************/

int main ( void )
{
  extern unsigned int AD_value;
  extern unsigned int GO;
  unsigned int dutycyclereg, dutycycle, period;
  char updatedisable;
  double scale, time, dt;
  int on;

  //  set up the A/D parameters

  adc_init();

  // set up the pwm

   // pwm_init();

  // set up the uart

  uart1_init();

  // set up the external interrupt
 
  // Init_INT4();

  // disable updates

  updatedisable = 0;
 
  // get some scaling out of the way

  scale = ((double) MAX_DUTY)/1024.0;

  // initialize timer1

  dt = 0.1;  // the sampling inverval in seconds

  // dt = N*256/29,480,000;  assuming a 256 prescalar.
  // so N = dt* 115156

  period = (unsigned int) (dt*115156.0);
 
  if (period > 32768 )
  {
     period = 32768;
  }

  Init_Timer1( period );

  AD_value = 0;
  time = 0;
  on = 0;

/********************* MAIN LOOP **********************/

  while(1){

    while(!GO );
    GO = 0;
    time = time + dt;

    if (on == 0)
    {
       PORTE = 0b11111111;
       on = 1;
    }
    else
    {
       PORTE = 0b00000000;
       on = 0;
    }
/*
   dutycycle = (unsigned int) ((double) AD_value)*scale;
 
    dutycyclereg = 4;
    SetDCMCPWM( dutycyclereg, dutycycle, updatedisable);
*/
   printf("%8.4f \n", time); 
  } 
}