Jared Baxter / Mbed 2 deprecated Impedance_Fast_Circuitry

Dependencies:   mbed-dsp mbed

Fork of DSP_200kHz by Mazzeo Research Group

DMA_sampling/adc.cpp

Committer:
baxterja
Date:
2017-06-01
Revision:
74:ebc9f09fda11
Parent:
55:2526b3317bc8

File content as of revision 74:ebc9f09fda11:

#include "adc.h"

/*
From page 869 of the user manual:

Before the ADC module can be used to complete conversions, an initialization procedure
must be performed. A typical sequence is:
1. Calibrate the ADC by following the calibration instructions in Calibration function.
2. Update CFG to select the input clock source and the divide ratio used to generate
ADCK. This register is also used for selecting sample time and low-power
configuration.
3. Update SC2 to select the conversion trigger, hardware or software, and compare
function options, if enabled.
4. Update SC3 to select whether conversions will be continuous or completed only once
(ADCO) and whether to perform hardware averaging.
5. Update SC1:SC1n registers to select whether conversions will be single-ended or
differential and to enable or disable conversion complete interrupts. Also, select the
input channel which can be used to perform conversions.
*/
DigitalOut green(LED_GREEN);
DigitalOut red(LED_RED);

Serial debug(USBTX, USBRX);


void adc_init()
{    

    // 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
       
    // turn on the clock to the PDB
//    SIM->SCGC6 |= SIM_SCGC6_PDB_MASK;
    
    // set ADC trigger to PDB0
//    SIM_SOPT7 = SIM_SOPT7_ADC0TRGSEL(0);  
    
    // This lets the clocks go to the ADC
//    SIM_SCGC6 |= SIM_SCGC6_ADC0_MASK;
//    SIM_SCGC3 |= SIM_SCGC3_ADC1_MASK;
    
/*    // This lets the clocks go to the PDB
    SIM_SCGC6 |= SIM_SCGC6_PDB_MASK;
      
    // Set PDB to be enabled and have continous triggers
    PDB0_SC = PDB_SC_DMAEN_MASK // DMA Enable
            | PDB_SC_TRGSEL(0xf) // Software trigger
            | PDB_SC_PDBEN_MASK // Set to continuous mode
            | PDB_SC_LDOK_MASK; // Loading mask
    
    PDB0_SC |= PDB_SC_SWTRIG_MASK; // enable software trigger (start the PDB)
    
    
    // This now routes the triggers
    SIM_SOPT7 = SIM_SOPT7_ADC0TRGSEL(0);
    SIM_SOPT7 = SIM_SOPT7_ADC1TRGSEL(0);
*/

/* From page 853 of the user manual
Prior to calibration, the user must configure the ADC's clock source and frequency, low
power configuration, voltage reference selection, sample time, and high speed
configuration according to the application's clock source availability and needs.
*/
    ADC0->SC1[0] = 0x0C; //AIEN = 0, DIFF = 0, Channel = AD12 (PTB2)
    ADC1->SC1[0] = 0x0E; //AIEN = 0, DIFF = 0, Channel = AD14 (PTB10)

    ADC0->CFG1 = 0x0C; //ADLPC = 0, ADIV = 0, ADLSMP = 0, MODE = 0b11, ADICLK = 00 (16-bit single-ended)
    ADC1->CFG1 = 0x0C; //ADLPC = 0, ADIV = 0, ADLSMP = 0, MODE = 0b11, ADICLK = 00 (16-bit single-ended)

//    ADC0_CFG1 = 0x00; //ADLPC = 0, ADIV = 0, ADLSMP = 0, MODE = 0b00, ADICLK = 00 (16-bit single-ended)
//    ADC1_CFG1 = 0x00; //ADLPC = 0, ADIV = 0, ADLSMP = 0, MODE = 0b00, ADICLK = 00 (16-bit single-ended)

    
    // It is necessary not to have hardware trigger for calbiration
    ADC0->CFG2 = 0x00; // MUXSEL = 0, ADACKEN = 0, ADHSC = 0, ADLSTS = 0 (does not matter - short sample time)
    ADC1->CFG2 = 0x00; // MUXSEL = 0, ADACKEN = 0, ADHSC = 0, ADLSTS = 0 (does not matter - short sample time)

    // Use averaging to make calibration better
    ADC0->SC3  = 0x07; // CAL = 0, CALF = 0, res[5:4], ADCO = 0 (continuous conversion), AVGE = 1, AVGS = 11
    ADC1->SC3  = 0x07; // CAL = 0, CALF = 0, res[5:4], ADCO = 0 (continuous conversion), AVGE = 1, AVGS = 11         
    
    
    // calibrate the ADC (following Joey's code example)
    ADC0->SC3 |= ADC_SC3_CAL_MASK; // start calibration
    while(ADC0->SC3&ADC_SC3_CALF_MASK) {} // wait for calibration to complete
    ADC1->SC3 |= ADC_SC3_CAL_MASK; // start calibration
    while(ADC1->SC3&ADC_SC3_CALF_MASK) {} // wait for calibration to complete

    debug.printf("ADC0_CLP0:%d\r\n", ADC0->CLP0);
    debug.printf("ADC0_CLP1:%d\r\n", ADC0->CLP1);
    debug.printf("ADC0_CLP2:%d\r\n", ADC0->CLP2);
    debug.printf("ADC0_CLP3:%d\r\n", ADC0->CLP3);
    debug.printf("ADC0_CLPS:%d\r\n", ADC0->CLPS);
       
    // calculate the gains (see user manual page 864)
    int16_t gain = (ADC0->CLP0+ADC0->CLP1+ADC0->CLP2+ADC0->CLP3+ADC0->CLP4+ADC0->CLPS);
    gain = gain / 2; // divide by 2
    gain |= 0x8000;  // set the MSB
    ADC0->PG = gain;
    
    gain = (ADC1->CLP0+ADC1->CLP1+ADC1->CLP2+ADC1->CLP3+ADC1->CLP4+ADC1->CLPS);
    gain = gain / 2; // divide by 2
    gain |= 0x8000;  // set the MSB
    ADC1->PG = gain;
    
    gain = (ADC0->CLM0+ADC0->CLM1+ADC0->CLM2+ADC0->CLM3+ADC0->CLM4+ADC0->CLMS);
    gain = gain / 2; // divide by 2
    gain |= 0x8000;  // set the MSB
    ADC0->MG = gain;
    
    gain = (ADC1->CLM0+ADC1->CLM1+ADC1->CLM2+ADC1->CLM3+ADC1->CLM4+ADC1->CLMS);
    gain = gain / 2; // divide by 2
    gain |= 0x8000;  // set the MSB
    ADC1->MG = gain;
    
//    ADC0_SC3 &= ~ADC_SC3_CAL_MASK; // stop calibration
//    ADC1_SC3 &= ~ADC_SC3_CAL_MASK; // stop calibration
    

    // Now set up for use in the rest of the program - software trigger
    ADC0->SC2  = 0x04; // ADACT = 0, ADTRG = 0 (HW trigger), ACFE = 0, ACFGT = 0, ACREN = 0, DMAEN = 1, REFSEL = 00 (DMAEN needs to be asserted)
    ADC1->SC2  = 0x04; // ADACT = 0, ADTRG = 0 (HW trigger), ACFE = 0, ACFGT = 0, ACREN = 0, DMAEN = 1, REFSEL = 00 (DMAEN needs to be asserted)    
   
   
//    ADC0_SC3  = 0x08; // CAL = 0, CALF = 0, res[5:4], ADCO = 1 (continuous conversion), AVGE = 0, AVGS = 00
//    ADC1_SC3  = 0x08; // CAL = 0, CALF = 0, res[5:4], ADCO = 1 (continuous conversion), AVGE = 0, AVGS = 00      

    ADC0->SC3  = 0x00; // CAL = 0, CALF = 0, res[5:4], ADCO = 0 (continuous conversion), AVGE = 0, AVGS = 00
    ADC1->SC3  = 0x00; // CAL = 0, CALF = 0, res[5:4], ADCO = 0 (continuous conversion), AVGE = 0, AVGS = 00      


    
    // A write to SC1[0] is necessary as a software trigger
    ADC0->SC1[0] = 0x0C; //AIEN = 0, DIFF = 0, Channel = AD12 (PTB2)
    ADC1->SC1[0] = 0x0E; //AIEN = 0, DIFF = 0, Channel = AD14 (PTB10)  

    while( (ADC1->SC1[0]&ADC_SC1_COCO_MASK)) {}
    //gain = ADC0_R[0]; // read the register to clear SC1[0][COCO]
    debug.printf("ADC0_R[0]:%i\r\n", ADC0->R[0]);
    debug.printf("ADC0_R[1]:%i\r\n", ADC0->R[1]);
    debug.printf("ADC1_R[0]:%i\r\n", ADC1->R[0]);
    debug.printf("ADC1_R[1]:%i\r\n", ADC1->R[1]);

/*

    ADC0_SC1[0] = 0x0C; //AIEN = 0, DIFF = 0, Channel = AD12 (PTB2)
    ADC1_SC1[0] = 0x0E; //AIEN = 0, DIFF = 0, Channel = AD14 (PTB10)  

    while( (ADC1_SC1[0]&ADC_SC1_COCO_MASK)) {}
    debug.printf("ADC1_R[0]:%i\r\n", ADC1_R[0]);

    ADC0_SC1[0] = 0x0C; //AIEN = 0, DIFF = 0, Channel = AD12 (PTB2)
    ADC1_SC1[0] = 0x0E; //AIEN = 0, DIFF = 0, Channel = AD14 (PTB10)  


    while( (ADC1_SC1[0]&ADC_SC1_COCO_MASK)) {}
    debug.printf("ADC1_R[0]:%i\r\n", ADC1_R[0]);
 */

    // Now set up for use in the rest of the program - HARDWARE trigger
    ADC0->SC2  = 0x44; // ADACT = 0, ADTRG = 1 (HW trigger), ACFE = 0, ACFGT = 0, ACREN = 0, DMAEN = 1, REFSEL = 00 (DMAEN needs to be asserted)
    ADC1->SC2  = 0x44; // ADACT = 0, ADTRG = 1 (HW trigger), ACFE = 0, ACFGT = 0, ACREN = 0, DMAEN = 1, REFSEL = 00 (DMAEN needs to be asserted)    

    
    // adebug.printf("Calbiration complete. Hardware continuous conversion running.\r\n");
    // The ADCs are now just continuously converting and generating DMA signals after each conversion
}