K64F internal ADC channels: bandgap, VREF, temperature sensor derived from teensy 3.1 firmware analog.c

Dependencies:   mbed

K64F internal ADC channels: bandgap, VREF, temperature sensor derived from teensy 3.1 firmware analog.c

main.cpp

Committer:
manitou
Date:
2015-11-19
Revision:
2:71d82e4b3777
Parent:
1:9a99de9cc5d5

File content as of revision 2:71d82e4b3777:

// k64f internal ADC channels 3.7.1.3.1
//  temp sensor  ADC0 26  slope 1.62mv/C  716mv @25C
//   bandgap ADC0 27  1.0v
//   VREFout  ADC1 18  1.195v
//   DAC0 ADC1 23
// ADC1 SIM_SCGC3  ADC0 SIM_SCGC6
// A0 PTB2   ADC0 channel 12
#include "mbed.h"

#define PRREG(z) printf(#z" 0x%x\n",z)
//AnalogIn adc(A0);
AnalogOut dac(DAC0_OUT);
Timer tmr;
static uint32_t t;

// based on teensy3.1 firmware analog.c
// 60mhz bus
#define ADC_CFG1_16BIT  BF_ADC_CFG1_ADIV(2) + BF_ADC_CFG1_ADICLK(1) // 7.5 MHz
#define ADC_CFG1_12BIT  BF_ADC_CFG1_ADIV(1) + BF_ADC_CFG1_ADICLK(1) // 15 MHz
#define ADC_CFG1_10BIT  BF_ADC_CFG1_ADIV(1) + BF_ADC_CFG1_ADICLK(1) // 15 MHz
#define ADC_CFG1_8BIT   BF_ADC_CFG1_ADIV(1) + BF_ADC_CFG1_ADICLK(1) // 15 MHz

static uint8_t analog_config_bits = 12;  // 8 10 12 16 bit ADC
static uint8_t analog_num_average = 4;    // 0 4 8 16 32
static uint8_t analog_reference_internal = 0;

static void adc_init() {
    SIM_SCGC6 |= SIM_SCGC6_ADC0_MASK;  // start ADC  peripherals
    SIM_SCGC3 |= SIM_SCGC3_ADC1_MASK;
    VREF_TRM = 0x60;
    VREF_SC = 0xE1;     // enable 1.2 volt ref
    PMC_REGSC |= PMC_REGSC_BGBE_MASK;  // enable bandgap
    
    // would need to do GPIO init for external pins

    if (analog_config_bits == 8) {
        ADC0_CFG1 = ADC_CFG1_8BIT + BF_ADC_CFG1_MODE(0);
        ADC0_CFG2 = ADC_CFG2_MUXSEL_MASK + BF_ADC_CFG2_ADLSTS(3);
        ADC1_CFG1 = ADC_CFG1_8BIT + BF_ADC_CFG1_MODE(0);
        ADC1_CFG2 = ADC_CFG2_MUXSEL_MASK + BF_ADC_CFG2_ADLSTS(3);
    } else if (analog_config_bits == 10) {
        ADC0_CFG1 = ADC_CFG1_10BIT + BF_ADC_CFG1_MODE(2) + ADC_CFG1_ADLSMP_MASK;
        ADC0_CFG2 = ADC_CFG2_MUXSEL_MASK + BF_ADC_CFG2_ADLSTS(3);
        ADC1_CFG1 = ADC_CFG1_10BIT + BF_ADC_CFG1_MODE(2) + ADC_CFG1_ADLSMP_MASK;
        ADC1_CFG2 = ADC_CFG2_MUXSEL_MASK + BF_ADC_CFG2_ADLSTS(3);
    } else if (analog_config_bits == 12) {
        ADC0_CFG1 = ADC_CFG1_12BIT + BF_ADC_CFG1_MODE(1) + ADC_CFG1_ADLSMP_MASK;
        ADC0_CFG2 = ADC_CFG2_MUXSEL_MASK + BF_ADC_CFG2_ADLSTS(2);
        ADC1_CFG1 = ADC_CFG1_12BIT + BF_ADC_CFG1_MODE(1) + ADC_CFG1_ADLSMP_MASK;
        ADC1_CFG2 = ADC_CFG2_MUXSEL_MASK + BF_ADC_CFG2_ADLSTS(2);
    } else {
        ADC0_CFG1 = ADC_CFG1_16BIT + BF_ADC_CFG1_MODE(3) + ADC_CFG1_ADLSMP_MASK;
        ADC0_CFG2 = ADC_CFG2_MUXSEL_MASK + BF_ADC_CFG2_ADLSTS(2);
        ADC1_CFG1 = ADC_CFG1_16BIT + BF_ADC_CFG1_MODE(3) + ADC_CFG1_ADLSMP_MASK;
        ADC1_CFG2 = ADC_CFG2_MUXSEL_MASK + BF_ADC_CFG2_ADLSTS(2);
    }
    
    if (analog_reference_internal) {
        ADC0_SC2 = BF_ADC_SC2_REFSEL(1); // 1.2V ref
        ADC1_SC2 = BF_ADC_SC2_REFSEL(1); // 1.2V ref
    } else {
        ADC0_SC2 = BF_ADC_SC2_REFSEL(0); // vcc/ext ref
        ADC1_SC2 = BF_ADC_SC2_REFSEL(0); // vcc/ext ref
    }
    // calibrate ADCs
    t=tmr.read_us();
    if (analog_num_average <=1) {
        ADC0_SC3 = ADC_SC3_CAL_MASK;  // no averaging
        ADC1_SC3 = ADC_SC3_CAL_MASK;
    } else if (analog_num_average <=4) {
        ADC0_SC3 = ADC_SC3_CAL_MASK + ADC_SC3_AVGE_MASK + BF_ADC_SC3_AVGS(0);  // average 4
        ADC1_SC3 = ADC_SC3_CAL_MASK + ADC_SC3_AVGE_MASK + BF_ADC_SC3_AVGS(0);
    } else if (analog_num_average <=8) {
        ADC0_SC3 = ADC_SC3_CAL_MASK + ADC_SC3_AVGE_MASK + BF_ADC_SC3_AVGS(1); 
        ADC1_SC3 = ADC_SC3_CAL_MASK + ADC_SC3_AVGE_MASK + BF_ADC_SC3_AVGS(1);
    } else if (analog_num_average <=16) {
        ADC0_SC3 = ADC_SC3_CAL_MASK + ADC_SC3_AVGE_MASK + BF_ADC_SC3_AVGS(2);  
        ADC1_SC3 = ADC_SC3_CAL_MASK + ADC_SC3_AVGE_MASK + BF_ADC_SC3_AVGS(2);
    } else {
        ADC0_SC3 = ADC_SC3_CAL_MASK + ADC_SC3_AVGE_MASK + BF_ADC_SC3_AVGS(3);  
        ADC1_SC3 = ADC_SC3_CAL_MASK + ADC_SC3_AVGE_MASK + BF_ADC_SC3_AVGS(3);
    }
    uint16_t sum;

    while ((ADC0_SC3 & ADC_SC3_CAL_MASK) || (ADC1_SC3 & ADC_SC3_CAL_MASK)) ; // wait

    __disable_irq();

        sum = ADC0_CLPS + ADC0_CLP4 + ADC0_CLP3 + ADC0_CLP2 + ADC0_CLP1 + ADC0_CLP0;
        sum = (sum / 2) | 0x8000;
        ADC0_PG = sum;
        sum = ADC0_CLMS + ADC0_CLM4 + ADC0_CLM3 + ADC0_CLM2 + ADC0_CLM1 + ADC0_CLM0;
        sum = (sum / 2) | 0x8000;
        ADC0_MG = sum;
        sum = ADC1_CLPS + ADC1_CLP4 + ADC1_CLP3 + ADC1_CLP2 + ADC1_CLP1 + ADC1_CLP0;
        sum = (sum / 2) | 0x8000;
        ADC1_PG = sum;
        sum = ADC1_CLMS + ADC1_CLM4 + ADC1_CLM3 + ADC1_CLM2 + ADC1_CLM1 + ADC1_CLM0;
        sum = (sum / 2) | 0x8000;
        ADC1_MG = sum;

    __enable_irq();
    t=tmr.read_us()-t;
}

static uint16_t adc_read(ADC_Type * ADCx, int channel) {
    ADCx->SC1[0] = channel;
    while(!(ADCx->SC1[0] & ADC_SC1_COCO_MASK)); // wait
    return ADCx->R[0];
}

int main()
{
    int ADCmax = 1 << analog_config_bits;
    int val, i;
    float Vcc,  tempc, slope=ADCmax*0.76/3.3, val25=ADCmax*.0025/3.3;
    
    printf("\nSystemCoreClock %d  %s %s\n",SystemCoreClock,__TIME__,__DATE__);
    tmr.start();
    adc_init();
    dac.write(0.5);   // 3.3/2 jumper to A0 and read internal

    PRREG(SIM_SCGC6);
    PRREG(SIM_SCGC3);
    PRREG(VREF->TRM);
    PRREG(VREF_SC);
    PRREG(PMC_REGSC);
    PRREG(ADC0->SC1[0]);      // or ADC0_SCA
    PRREG(ADC0->SC1[1]);
    PRREG(ADC0->CFG1);
    PRREG(ADC0_CFG2);
    PRREG(ADC0->SC2);
    PRREG(ADC0->SC3);
    PRREG(ADC1->SC1[0]);      // ADC1
    PRREG(ADC1->SC1[1]);
    PRREG(ADC1->CFG1);
    PRREG(ADC1_CFG2);
    PRREG(ADC1->SC2);
    PRREG(ADC1->SC3);

    printf("res %d average %d calibration %d us\n",analog_config_bits,analog_num_average,t);
    val = adc_read(ADC1,18);    // VREF OUT
    Vcc = ADCmax*1.195/val;
    printf("VREF val %d %.2f v\n",val,Vcc);
    val = adc_read(ADC0,27);     // bandgap
    Vcc = ADCmax*1.0/val;
    printf("bandgap val %d %.2f v\n",val,Vcc);
    val = adc_read(ADC0,12);   // didn't do GPIO init for A0
    printf("A0 val %d  %.2f v\n",val,3.3*val/ADCmax);  
    val = adc_read(ADC1,23);   // DAC to internal ADC
    printf("DAC val %d  %.2f v\n",val,3.3*val/ADCmax);  
    t=tmr.read_us();
    for(i=0;i<1000;i++) adc_read(ADC0,12);
    t=tmr.read_us()-t;
    printf("avrg A0 read %d us\n",t/1000);
    //  need internal VREF for temp sensor ??  TODO
    analog_reference_internal = 1;
    adc_init();  // re init and calibrate
    val = adc_read(ADC0,26);    // temp sensor
    tempc = ((val-val25)/slope) + 25.f;
    printf("temp val %d %.1f C\n",val,tempc); 
}