Jared's DAC Code

Dependencies:   mbed

Dependents:   DCS_FINAL_CODE

Fork of Chemical_Sensor_DMA by Jared Baxter

Sample/adc.cpp

Committer:
DeWayneDennis
Date:
2015-12-19
Revision:
7:af255a90505e
Parent:
4:9fd291254686

File content as of revision 7:af255a90505e:

#include "adc.h"

/*
TODO:   calibration is done, i think
        change clock speed and hw averaging
*/

DigitalOut green(LED_GREEN);
DigitalOut red(LED_RED);



/* The ADCs are setup so that ADC0 and ADC1 are triggered by the PDB.
 * When the conversions are complete, ADC0 and ADC1 then trigger DMA0
 * and DMA1, respectively. ADC0 is using channel B and ADC1 is uing
 * channel A.  If they are on the same channel, then weird things 
 * happen.  I think they interfere with each other so they have to be
 * on separate channels if they're going to be triggered at the same 
 * time by the PDB.                                                */
void adc_init()
{
    // red, indicating not ready
    red = 0;
    green = 1;
    
    
    // Turn on the ADC0 and ADC1 clocks
    SIM_SCGC6 |= SIM_SCGC6_ADC0_MASK;
    SIM_SCGC3 |= SIM_SCGC3_ADC1_MASK;
    
    // Set ADC hardware trigger to PDB0
    SIM_SOPT7 = SIM_SOPT7_ADC0TRGSEL(0); // Select triggering by PDB and select pre-trigger A
    SIM_SOPT7 = SIM_SOPT7_ADC1TRGSEL(0); // Select triggering by PDB and select pre-trigger A
    
    // calibrate the ADC
    //__disable_irq();
    //if(adc_cal()) {red = 0; green = 0;} // if calibration fails, display yellow
    //if(adc_cal1()) {red = 0; green = 0;} // if calibration fails, display yellow
    //__enable_irq();
    
    
    // Setup Configuration Register 1 
    ADC0_CFG1 = 0; // clear register
    ADC0_CFG1 |= ADC_CFG1_ADICLK(0);    // select bus clock
    ADC0_CFG1 |= ADC_CFG1_MODE(3);      // select 16-bit 2's complement output
    ADC0_CFG1 |= ADC_CFG1_ADIV(0);      // select short sample time
    ADC0_CFG1 &= ~ADC_CFG1_ADLSMP_MASK; // select short sample time
    ADC0_CFG1 &= ~ADC_CFG1_ADLPC_MASK;  // select normal power configuration
    ADC1_CFG1 = 0; // clear register
    ADC1_CFG1 |= ADC_CFG1_ADICLK(0);    // select bus clock
    ADC1_CFG1 |= ADC_CFG1_MODE(3);      // select 16-bit 2's complement output
    ADC1_CFG1 |= ADC_CFG1_ADIV(0);      // select short sample time
    ADC1_CFG1 &= ~ADC_CFG1_ADLSMP_MASK; // select short sample time
    ADC1_CFG1 &= ~ADC_CFG1_ADLPC_MASK;  // select normal power configuration
    
    // Setup Configuration Register 2 
    ADC0_CFG2 = 0; // clear register
    //ADC0_CFG2 |= ADC_CFG2_ADHSC_MASK ;  // select high-speed conversion
    ADC0_CFG2 &= ~ADC_CFG2_MUXSEL_MASK; // select a channels    
    ADC1_CFG2 = 0; // clear register
    //ADC1_CFG2 |= ADC_CFG2_ADHSC_MASK ;  // select high-speed conversion
    ADC1_CFG2 &= ~ADC_CFG2_MUXSEL_MASK; // select a channels    
    
    // Setup Status and Control Register 2 
    ADC0_SC2 = 0;                    // clear register
    ADC0_SC2 |= ADC_SC2_REFSEL(0);   // select external voltage reference
    ADC0_SC2 |= ADC_SC2_DMAEN_MASK;  // enable DMA
    ADC0_SC2 |= ADC_SC2_ADTRG_MASK; // select hardware trigger
    ADC1_SC2 = 0;                    // clear register
    ADC1_SC2 |= ADC_SC2_REFSEL(0);   // select external voltage reference
    ADC1_SC2 |= ADC_SC2_DMAEN_MASK;  // enable DMA
    ADC1_SC2 |= ADC_SC2_ADTRG_MASK; // select hardware trigger
    
    // Setup Status and Control Register 3 now that calibration is complete
    ADC0_SC3 = 0; // Hardware Average set to 4 samples averaged
                  // Hardware Average Disabled
                  // select single conversion mode
    ADC1_SC3 = 0; // Hardware Average set to 4 samples averaged
                  // Hardware Average Disabled
                  // select single conversion mode
    // Setup Status and Control Register 3 now that calibration is complete
    //ADC0_SC3 = ADC_SC3_AVGS(0) | ADC_SC3_AVGE_MASK; // Hardware Average set to 16 samples averaged
                                                    // select single conversion mode
    //ADC1_SC3 = ADC_SC3_AVGS(0) | ADC_SC3_AVGE_MASK; // Hardware Average set to 16 samples averaged
    // Setup Status and Control Register 1A 
    ADC0_SC1B = 0; // clear register
    ADC0_SC1B &= ~ADC_SC1_DIFF_MASK; // select single-ended mode
    ADC0_SC1B |= ADC_SC1_AIEN_MASK;  // enable interrupt (for debugging)
    ADC0_SC1B |= ADC_SC1_ADCH(12);   // select channel 13
    ADC1_SC1A = 0; // clear register
    ADC1_SC1A &= ~ADC_SC1_DIFF_MASK; // select single-ended mode
    ADC1_SC1A |= ADC_SC1_AIEN_MASK;  // enable interrupt (for debugging)
    ADC1_SC1A |= ADC_SC1_ADCH(14);   // select channel 14
    
    
    // Check if ADC is finished initializing  TODO:  This part doesn't seem right, but I did it according to 871
    while( (ADC0_SC1B&ADC_SC1_COCO_MASK)) {}
    int gain = ADC0_RA; // read the register to clear SC1A[COCO]
    while( (ADC1_SC1A&ADC_SC1_COCO_MASK)) {}
    gain = ADC1_RA; // read the register to clear SC1A[COCO]
    
    red = 1;
    green = 1;
}


/* adc_cal
 * Calibrates the adc
 * Returns 0 if successful calibration
 * Returns 1 otherwise
 * */
int adc_cal(void)
{
    ADC0_CFG1 |= (ADC_CFG1_MODE(3)  | // 16 bits mode
                  ADC_CFG1_ADICLK(1)| // Input Bus Clock divided by 2 (20-25 MHz out of reset (FEI mode) / 2)
                  ADC_CFG1_ADIV(2)) ; // Clock divide by 4 (2.5-3 MHz)
    
    ADC0_SC3 |= ADC_SC3_AVGE_MASK |   // Enable HW average
                ADC_SC3_AVGS(3)   |   // Set HW average of 32 samples
                ADC_SC3_CAL_MASK;     // Start calibration process
    
    while(ADC0_SC3 & ADC_SC3_CAL_MASK); // Wait for calibration to end
    
    if(ADC0_SC3 & ADC_SC3_CALF_MASK) return 1;  // Check for successful calibration
    
    uint16_t calib = 0; // calibration variable 
    calib += ADC0->CLPS + ADC0_CLP4 + ADC0_CLP3 + ADC0_CLP2 + ADC0_CLP1 + ADC0_CLP0;
    calib /= 2;
    calib |= 0x8000;    // Set MSB 
    ADC0_PG = calib;
    calib = 0;
    calib += ADC0_CLMS + ADC0_CLM4 + ADC0_CLM3 + ADC0_CLM2 + ADC0_CLM1 + ADC0_CLM0;
    calib /= 2;
    calib |= 0x8000;    // Set MSB
    ADC0_MG = calib;
    
    return 0;
}

int adc_cal1(void)
{
    ADC1_CFG1 |= (ADC_CFG1_MODE(3)  | // 16 bits mode
                  ADC_CFG1_ADICLK(1)| // Input Bus Clock divided by 2 (20-25 MHz out of reset (FEI mode) / 2)
                  ADC_CFG1_ADIV(2)) ; // Clock divide by 4 (2.5-3 MHz)
    
    ADC1_SC3 |= ADC_SC3_AVGE_MASK |   // Enable HW average
                ADC_SC3_AVGS(3)   |   // Set HW average of 32 samples
                ADC_SC3_CAL_MASK;     // Start calibration process
    
    while(ADC1_SC3 & ADC_SC3_CAL_MASK); // Wait for calibration to end
    
    if(ADC1_SC3 & ADC_SC3_CALF_MASK) return 1;  // Check for successful calibration
    
    uint16_t calib = 0; // calibration variable 
    calib += ADC1->CLPS + ADC1_CLP4 + ADC1_CLP3 + ADC1_CLP2 + ADC1_CLP1 + ADC1_CLP0;
    calib /= 2;
    calib |= 0x8000;    // Set MSB 
    ADC1_PG = calib;
    calib = 0;
    calib += ADC1_CLMS + ADC1_CLM4 + ADC1_CLM3 + ADC1_CLM2 + ADC1_CLM1 + ADC1_CLM0;
    calib /= 2;
    calib |= 0x8000;    // Set MSB
    ADC1_MG = calib;
    
    return 0;
}











/* * * * * * * * * * * * * * For Debugging Purposes * * * * * * * * * * * * * * * * * * * * */


/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
 * DEBUG:  This is supposed to put the ADC in continuous     *
 *         mode so it samples without the PCB.  But for      *
 *         some reason it isn't working.  I haven't deleted  *
 *         it just in case it is needed for debug purposes   *
 *         in the future.                                    *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void adc_start() {
    // reset DMA
    dma_reset();
    
    // set ADC to continuous mode
    ADC0_SC3 |= ADC_SC3_ADCO_MASK;
    ADC1_SC3 |= ADC_SC3_ADCO_MASK;
    
    // set ADC to software trigger
    ADC0_SC2 &= ~ADC_SC2_ADTRG_MASK;
    ADC1_SC2 &= ~ADC_SC2_ADTRG_MASK;
    
    // start ADC conversion (SW trigger)
    ADC0_SC1B |= ADC_SC1_ADCH(13);   // write to SC1A causing a trigger
    ADC1_SC1A |= ADC_SC1_ADCH(14);   // write to SC1A causing a trigger
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
 * DEBUG:  This is supposed to revert back from adc_start()  *
 *         but because adc_start() isn't working, this       *
 *         function is good for nothing.  I held on to       *
 *         it just in case it is needed for debug purposes   *
 *         in the future.                                    *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void adc_stop() {
    // set ADC to hardware trigger
    ADC0_SC2 |= ADC_SC2_ADTRG_MASK;
    ADC1_SC2 |= ADC_SC2_ADTRG_MASK;
    
    // set to single conversion mode effectively stopping the ADC unless a timer triggers the ADC
    ADC0_SC3 &= ~ADC_SC3_ADCO_MASK; 
    ADC1_SC3 &= ~ADC_SC3_ADCO_MASK; 
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
 * DEBUG:  This is supposed to trigger a software conversion *
 *         and take a single sample.  However, it only       *
 *         worked for ADC1 for some reason.  It is here for  *
 *         possible debug purposes in the future.            *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void adc_single_sample() {
    ADC0_SC3 &= ~ADC_SC3_ADCO_MASK;  // single conversion mode
    ADC1_SC3 &= ~ADC_SC3_ADCO_MASK;  // single conversion mode
    ADC0_SC2 &= ~ADC_SC2_ADTRG_MASK; // set ADC to software trigger
    ADC1_SC2 &= ~ADC_SC2_ADTRG_MASK; // set ADC to software trigger
    ADC0_SC1B |= ADC_SC1_ADCH(13);   // write to SC1B causing a trigger
    ADC1_SC1A |= ADC_SC1_ADCH(14);   // write to SC1A causing a trigger
    
    // Set back to hardware trigger
    ADC0_SC2 |= ADC_SC2_ADTRG_MASK; // set ADC to software trigger
    ADC1_SC2 |= ADC_SC2_ADTRG_MASK; // set ADC to software trigger
}


void adc_print_registers() {
    Serial debug(USBTX,USBRX);
    debug.printf("ADC0_SC1a: %08x\r\n",ADC0_SC1A);  //(0x0000004d)
    debug.printf("ADC0_SC1b: %08x\r\n",ADC0_SC1B);  //(0x0000001f)
    debug.printf("ADC0_CFG1: %08x\r\n",ADC0_CFG1);  //(0x0000000c)
    debug.printf("ADC0_CFG2: %08x\r\n",ADC0_CFG2);  //(0x00000004)
    debug.printf("ADC0_RA:   %08x\r\n",ADC0_RA);    //(0x00000000)
    debug.printf("ADC0_RB:   %08x\r\n",ADC0_RB);    //(0x00000000)
    debug.printf("ADC0_SC2:  %08x\r\n",ADC0_SC2);   //(0x00000044)
    debug.printf("ADC0_SC3:  %08x\r\n\n",ADC0_SC3); //(0x00000000)
}