Dependencies:   mbed-dsp mbed

Fork of DSP_200kHz by Mazzeo Research Group

DMA_sampling/adc.cpp

Committer:
bmazzeo
Date:
2016-02-17
Revision:
55:2526b3317bc8
Parent:
54:1697dc574b96
Child:
74:ebc9f09fda11

File content as of revision 55:2526b3317bc8:

#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_SC1A = 0x0C; //AIEN = 0, DIFF = 0, Channel = AD12 (PTB2)
    ADC1_SC1A = 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 SC1A is necessary as a software trigger
    ADC0_SC1A = 0x0C; //AIEN = 0, DIFF = 0, Channel = AD12 (PTB2)
    ADC1_SC1A = 0x0E; //AIEN = 0, DIFF = 0, Channel = AD14 (PTB10)  

    while( (ADC1_SC1A&ADC_SC1_COCO_MASK)) {}
    //gain = ADC0_RA; // read the register to clear SC1A[COCO]
    debug.printf("ADC0_RA:%i\r\n", ADC0_RA);
    debug.printf("ADC0_RB:%i\r\n", ADC0_RB);
    debug.printf("ADC1_RA:%i\r\n", ADC1_RA);
    debug.printf("ADC1_RB:%i\r\n", ADC1_RB);

/*

    ADC0_SC1A = 0x0C; //AIEN = 0, DIFF = 0, Channel = AD12 (PTB2)
    ADC1_SC1A = 0x0E; //AIEN = 0, DIFF = 0, Channel = AD14 (PTB10)  

    while( (ADC1_SC1A&ADC_SC1_COCO_MASK)) {}
    debug.printf("ADC1_RA:%i\r\n", ADC1_RA);

    ADC0_SC1A = 0x0C; //AIEN = 0, DIFF = 0, Channel = AD12 (PTB2)
    ADC1_SC1A = 0x0E; //AIEN = 0, DIFF = 0, Channel = AD14 (PTB10)  


    while( (ADC1_SC1A&ADC_SC1_COCO_MASK)) {}
    debug.printf("ADC1_RA:%i\r\n", ADC1_RA);
 */

    // 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
}