/*
This file is linked with the documentation ! */

//---------------------------------------------------------------------------
// File:   C:\pic\GPSDO\ADC_PIC16F1783.c
// Author: Wolfgang Buescher, DL4YHF 
// Date:   2016-02-12
// Purpose: ADC initialisation for PIC17(L)F178x.
// Development System :  Microchip MPLAB IDE v8.85, 
//                       XC8 C Compiler ("Free Mode") V1.35 .
//
//    
//---------------------------------------------------------------------------

#include "switches.h" // project specific 'compiler' switches & options 

// Include an awful lot of compiler-specific junk ... see gpsdo_pic_main.c
#ifdef __BORLANDC__  // compiling with Borland C ? Use WB's "PIC emulator" ..
# include "pic_emulator/xc.h"
#elif (defined __XC8) // compiling for PIC, using Microchip's "XC8" compiler ?
# include "xc.h"
# include "stdint.h"
#else // neither Borland nor XC8 (forget about CC5X) ...
# error Your compiler is not supported here yet. Please add support yourself.
#endif // using BORLAND C, Microchip's "XC8" ?


#include "adc_pic.h" // header for THIS module ("ADC functions for PIC" by DL4YHF)


//---------------------------------------------------------------------------
void ADC_Init(void) // Initialize the A/D converter.
{ // Details about the ADC in the PIC16F1782/3 datasheet, DS40001579E,
  // pages 141.., Ch. 17.1, "ADC Configuration" .
  // 
  // Note: ADC-associated port pins have already been initialized, e.g. RA0/AN0,
  //       including the TRIS and ANSEL settings (see gpsdo_pic_main.c) .

#if(0)  // removed, because with the 'FVR' as reference, the ADC was far too noisy !
  FVRCON = 0b10001010; // "Fixed Voltage Reference Control Register"...
      //     ||||||\|_ b1..0 = A/D-CONV.  voltage reference selection : 10bin = 2.048 V
      //     ||||\|___ b3..2 = COMPARATOR voltage reference selection : 10bin = 2.048 V
      //     ||||_____ b4 = "TSRNG" (temperature sensor range)  not used
      //     |||______ b5 = "TSEN"  (temperature sensor enable) 
      //     ||_______ b6 = "FVRRDY" ('ready flag', ignored here)
      //     |________ b7 = "FVREN" : 1 = fixed voltage reference enabled
#endif // ("FVR" not used for the ADC so don't initialise it here)

    
  // Channel selection : see DS40001579E page 149 (ADCON2) + 147 (ADCON0) 
  //                                 and page 140 (shows what the 'CHS' and 'CHSN'-bits are for)
  ADCON2 = 0b00001111;
      //     ||||\__|_ b3..b0 = "CHSN" : channel selection for the NEGATIVE input : 
      //     ||||                        1111 = "ADC Negative Reference, selected by ADNREF" (in ADCON1)
      //     ||||                        0000 = AN0 (would be wrong because AN0 is the *POSITIVE* input)  
      //     \__|_____ b7..b4 = auto-conversion trigger select:
      //                 1001 =  PSMC2 Falling Edge Event      (*)
      //                 1000 =  PSMC2 Rising Edge Event
      //                 0111 =  PSMC2 Period Match Event
      //                 0110 =  PSMC1 Falling Edge Event      (*)
      //                 0101 =  PSMC1 Rising Edge Event
      //                 0100 =  PSMC1 Period Match Event
      //                 0010 =  CCP2, Auto-conversion Trigger (**)
      //                 0001 =  CCP1, Auto-conversion Trigger
      //                 0000 = disabled (software trigger, single conversion)
      //                 other: illegal / 'reserved'
      // (*)  In the GPSDO, both PSMCs are already occupied.
      // (**) CCP2 *and* CCP1 *both* use Timer1.
      //         Timer1+CCP1 is already occupied to measure the GPS sync pulse,
      //         so the only chance for a jitter-free HARDWARE ADC trigger
      //         is CCP2 . Timer1 overflows 10 MHz / 65536 = 152.xxx times per second.
      //         But for the GPS, Timer1 *must* run over the entire 16 bit range.
      // Beware of another pitfall .. DS40001579E, page 179 :
      //  > 22.10   CCP Auto-Conversion Trigger
      //  > When any of the CCP’s are configured to trigger a
      //  > auto-conversion, the trigger will clear the
      //  > TMR1H:TMR1L register pair. This auto-conversion
      //  > does not cause a Timer1 interrupt. The CCP module
      //  > may still be configured to generate a CCP interrupt.
      //  > In this mode of operation, the CCPR1H:CCPR1L
      //  > register pair becomes the period register for Timer1 .
      // Thus "quickly reprogramming CCPR2 in the interrupt
      //       to prepare the next jitter-free A/D conversion"
      //       simply won't work. Eeeek. 
      // The only timer left (for a timer-triggered conversion)
      // would be the old 8-bit "Timer2" ("Timer/Counter"),
      // with its antique 2^n pre- and postscaler. 
      // Unfortunately, despite FOUR BITS TO SELECT THE ADC TRIGGER SOURCE,
      // Timer2 can NOT trigger the ADC via hardware -> need the ISR for this.
      // But code to initialize Timer2 doesn't belong here.. it's in gpsdo_pic_main.c .
  
#if( SWI_ADC_BITS_PER_SAMPLE==10 )
  ADCON0 = 0b10000001; // ADCON0 : DS40001579E page 147 ...
#else //     ||||||||  // not 10 but 12 bits per sample (slightly faster) :
  ADCON0 = 0b00000001;
#endif //    ||||||||
      //     |\___|||_ b0 = "ADON"     : 1=ADC enabled, 0=ADC disabled 
      //     |    ||__ b1 = "GO/!DONE" : 1=start/conversion in progress,
      //     |    |                      0=conversion complete / not in progress
      //     |    |___ b6..2 : "CHS4..0" = "Positive Differential Input Channel Select"
      //     |                 00000 = AN0 (first analog input)
      //     |________ b7 = "ADRMD" : 0 "ADRES formatted for 12-bit result"
      //                              1 "ADRES formatted for 10-bit result" (does this also mean FASTER CONVERSION) ? 

  // Reference voltage selection and conversion clock : see DS40001579E page 148
#if(1) // (0)=use the PIC's internal 'FVR' (fixed voltage reference), (1)=use 'VDD' (supply voltage) as reference
  ADCON1 = 0b10100000;  // using 'Vdd' as Vref : With Vdd=3.6 V, much LESS noise than with 'FVR'
#else  //    ||||||||
  ADCON1 = 0b10100011;  // using 'FVR' (2.048 V) as Vref : 20 dB more noise than with 'Vdd' ! 
#endif //    ||||||||
      //     ||||||\|_ b1..0 = "ADPREF" : ADC Positive Voltage Reference configuration
      //     ||||||                       00 = VREF+ on VDD, 01 = VREF+ on VREF+ pin,
      //     ||||||                       11 = internal 'Fixed Voltage Reference'
      //     ||||||___ b2    = "ADNREF" : ADC "Negative" Voltage Reference configuration
      //     |||||                        0  = VREF- on VSS (ground), 1 = VREF- on VREF- pin 
      //     |||||                       (never "negative" in the sense of a negative voltage!)
      //     |||||____ n.c. 
      //     |\_|_____ b6..4 = "ADCS" : 010 = Fosc/32, e.g. T_AD = 32/40MHz = 0.8 us 
      //     |________ b7    = "ADFM" : 1   = 2's complement, 0 = something exotic
    // -> movlw 0xA3 
    //    movwf 0x1E ; actually 0x9E which is ADCON1, with BSR=1 (?)
    //    return
    //  For some reason, the 'movwf 0x1E' also modified the content of PORTA ?!
    //  Why does ADCON1 (value doesn't seem to matter)
    //    modify PORTA (clear bit 3 = RA3) ?
    // 
  // With 15 * T_AD = 15 * 0.8 us = 1 / 83.3333 kHz, 80 kSamples / second
  // appered to be possible (when 'slightly violating the spec'),
  //  but (at so often) that's a false assumption. See speed test further below.
  // At a 'planned' single-channel sampling rate of 20 kHz, this would
  // allow 4-fold oversampling, and if the PIC16 (*and the C compiler*)
  // turns out good enough, we could even provide some anti-aliasing
  // (more than a stupid integrate-and-dump filter permits.. maybe an IIR..)
  //     To validate the above assumptions, there's a TEST for the ADC speed
  //     in GPSDO_PIC_MAIN.C, right after calling ADC_Init() .
  //
#if(0)  // (0)=normal compilation, (1)=TEST for the ADC speed... 
        // and the unpredictable sample & hold jitter seen at f_sample=80 kHz !
# asm
adc_test_loop:
  BANKSEL ( PORTA );  
  BSF   BANKMASK(PORTA),4    // ~ IOP_ADCCLK_PIN_HI
  BANKSEL ( ADCON0 );  
  BSF   BANKMASK(ADCON0), 1  // start next conversion as early as possible (bit 1 = "GO")
                             // (the current drawn by the sample and hold input caused
							 //  a 400 ns long 'spike' on the active analog input, 
							 //  which should appear a constant time after the rising edge
							 //  from 'IOP_ADCCLK_PIN_HI'. But the time was NOT constant ?!)
adc_test_wconv: // wait for analog/digitial conversion
  BTFSC BANKMASK(ADCON0), 1  // ADCON0 bit 1 = "GO" / "not DONE"
  GOTO  adc_test_wconv       // not "done" -> continue waiting
  BANKSEL ( PORTA );  
  BCF   BANKMASK(PORTA),4    // ~ IOP_ADCCLK_PIN_LO
  GOTO  adc_test_loop
  // 
  // On a PIC16F1783, got here with the following waveforms on an oscilloscope: 
  //          __     ____________________________________     ________________
  //            |   |                                    |   |
  //  PORTA.4   |___|      Sample & Hold switch closes   |___|
  //            .   .      .             S & H cap       .
  //            .   .      .             'fully charged' .
  //          _____________              ___________________________         
  //  AN0       .   .      |   ___-------                .          |   ___---
  //  (X mVpp)  .   .      \  /          .               .          \  /
  //            .   .      .\/           .               .           \/
  //            .   .      . .           .               .    (short dip caused by ADC
  //            .<->.<---->. .<--------->.               .     inrush current,
  //  t [ns]    .400.  520 200  ~~1400 ns                .     with a deliberately
  //            .   .                                    .     high impedance source,
  // For 12bit/ |<------------ loop time: 14.5 us ------>|     to find out when the 
  //     sample:    |<---"ADC busy" : ca. 13.8 us ------>|     ADC *really* 'samples').
  // For 10bit/ |<------------ loop time: 12.7 us ------>|
  //     sample:    |<---"ADC busy" : ca. 12.3 us ------>|
  //
  // With T_AD = 32 / 40 MHz = 0.8 us, these are slightly more than
  //                     (13.8/0.8=) 17 A/D conversion cycles ! 
  // The overhead of a few CPU instructions (with 0.1 us/instruction)
  // cannot be responsible for this. So where is the bug ?  
  //  (DS40001579E page 142, FIGURE 17-2, ANALOG-TO-DIGITAL CONVERSION TAD CYCLES) :
  // > T_AD cycle #15,   T_AD cycle #17 : 
  // >   Holding cap. discharge 
  //   (WB: But we DON'T WANT to discharge the cap when there is only ONE input!)
  // >   On the following cycle, GO bit is cleared, ADIF bit is set,
  // >   holding capacitor is connected to the analog input.
  // 
  //  (DS40001579E page 141):
  // > One full 12-bit conversion requires 15 T_AD periods.
  //  (DS40001579E page  1 ):
  // > - Fully differential 12-bit converter
  // > - Up to 75 ksps conversion rate 
  //      (Guess that's the typical marketing guerilla on 'page one'.
  //                    1 / ( 15 T_AD cycles * 1 us ) would be 66.666 kHz .
  //                    1 / ( 13 T_AD cycles * 1 us ) would be 76.923 kHz .
  //       Talking about a TWELVE BIT A/D converter on page 1, but bragging
  //       with the speed when running the converter at TEN BIT resolution.)
  // 
  //(DS40001579E page 377, table 30-14, "ADC Conversion Requirements"):
  // > Param No. |  Sym. |  Characteristic   |  Min |    Typ      | Max | Units |  Conditions
  // > ----------+-------+-------------------+------+-------------+-----+-------+---------------
  // > AD130     | T_AD  | ADC Clock Period  |  1.0 |     -       | 0.9 |  us   | T_osc based
  // > AD131     | T_CNV | Conversion Time,  |   -  | 15 (12 bit) |  -  | T_AD  | Set GO/!DONE bit
  // >           |       | not including     |   -  | 13 (10 bit) |  -  |       |  to conversion complete.
  // >           |       | acquisition time) |      |             |     |       | ADRES may be read on the
  // >           |       |                   |      |             |     |       | following T_CY(!) cycle.
  // > AD131     | T_ACQ | Acquisition Time  |   -  |    5.0      |  -  |  us   |
  //
  //
  // 17 T_AD cycles required instead of 15 ? Is 'T_ACQ' = 5.0 us carved in stone ?
  //    According to DS40001579E page 142, the ADC "inputs" the signal
  //    in T_AD cycle #1,  then disconnects the S & H capacitor from the input
  //    (between from cycle #1 and #2), then (in T_AD cycle #2) "samples", whatever that means,
  //    and digitizes the 'sampled value' in T_AD cycles #3 to #15. 
  //       

# endasm
#endif // ADC test ?

} // end ADC_Init()




/*
EOF ( ADC_PIC16F1783.c ) */