K64F internal ADC channels: bandgap, VREF, temperature sensor derived from teensy 3.1 firmware analog.c
K64F internal ADC channels: bandgap, VREF, temperature sensor derived from teensy 3.1 firmware analog.c
main.cpp@2:71d82e4b3777, 2015-11-19 (annotated)
- Committer:
- manitou
- Date:
- Thu Nov 19 17:44:52 2015 +0000
- Revision:
- 2:71d82e4b3777
- Parent:
- 1:9a99de9cc5d5
does temp sensor need internal analog reference?
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
manitou | 0:e1a2b02c8441 | 1 | // k64f internal ADC channels 3.7.1.3.1 |
manitou | 0:e1a2b02c8441 | 2 | // temp sensor ADC0 26 slope 1.62mv/C 716mv @25C |
manitou | 0:e1a2b02c8441 | 3 | // bandgap ADC0 27 1.0v |
manitou | 0:e1a2b02c8441 | 4 | // VREFout ADC1 18 1.195v |
manitou | 1:9a99de9cc5d5 | 5 | // DAC0 ADC1 23 |
manitou | 0:e1a2b02c8441 | 6 | // ADC1 SIM_SCGC3 ADC0 SIM_SCGC6 |
manitou | 0:e1a2b02c8441 | 7 | // A0 PTB2 ADC0 channel 12 |
manitou | 0:e1a2b02c8441 | 8 | #include "mbed.h" |
manitou | 0:e1a2b02c8441 | 9 | |
manitou | 0:e1a2b02c8441 | 10 | #define PRREG(z) printf(#z" 0x%x\n",z) |
manitou | 0:e1a2b02c8441 | 11 | //AnalogIn adc(A0); |
manitou | 2:71d82e4b3777 | 12 | AnalogOut dac(DAC0_OUT); |
manitou | 0:e1a2b02c8441 | 13 | Timer tmr; |
manitou | 0:e1a2b02c8441 | 14 | static uint32_t t; |
manitou | 0:e1a2b02c8441 | 15 | |
manitou | 0:e1a2b02c8441 | 16 | // based on teensy3.1 firmware analog.c |
manitou | 0:e1a2b02c8441 | 17 | // 60mhz bus |
manitou | 0:e1a2b02c8441 | 18 | #define ADC_CFG1_16BIT BF_ADC_CFG1_ADIV(2) + BF_ADC_CFG1_ADICLK(1) // 7.5 MHz |
manitou | 0:e1a2b02c8441 | 19 | #define ADC_CFG1_12BIT BF_ADC_CFG1_ADIV(1) + BF_ADC_CFG1_ADICLK(1) // 15 MHz |
manitou | 0:e1a2b02c8441 | 20 | #define ADC_CFG1_10BIT BF_ADC_CFG1_ADIV(1) + BF_ADC_CFG1_ADICLK(1) // 15 MHz |
manitou | 0:e1a2b02c8441 | 21 | #define ADC_CFG1_8BIT BF_ADC_CFG1_ADIV(1) + BF_ADC_CFG1_ADICLK(1) // 15 MHz |
manitou | 0:e1a2b02c8441 | 22 | |
manitou | 0:e1a2b02c8441 | 23 | static uint8_t analog_config_bits = 12; // 8 10 12 16 bit ADC |
manitou | 1:9a99de9cc5d5 | 24 | static uint8_t analog_num_average = 4; // 0 4 8 16 32 |
manitou | 0:e1a2b02c8441 | 25 | static uint8_t analog_reference_internal = 0; |
manitou | 0:e1a2b02c8441 | 26 | |
manitou | 0:e1a2b02c8441 | 27 | static void adc_init() { |
manitou | 0:e1a2b02c8441 | 28 | SIM_SCGC6 |= SIM_SCGC6_ADC0_MASK; // start ADC peripherals |
manitou | 0:e1a2b02c8441 | 29 | SIM_SCGC3 |= SIM_SCGC3_ADC1_MASK; |
manitou | 0:e1a2b02c8441 | 30 | VREF_TRM = 0x60; |
manitou | 0:e1a2b02c8441 | 31 | VREF_SC = 0xE1; // enable 1.2 volt ref |
manitou | 0:e1a2b02c8441 | 32 | PMC_REGSC |= PMC_REGSC_BGBE_MASK; // enable bandgap |
manitou | 1:9a99de9cc5d5 | 33 | |
manitou | 1:9a99de9cc5d5 | 34 | // would need to do GPIO init for external pins |
manitou | 0:e1a2b02c8441 | 35 | |
manitou | 0:e1a2b02c8441 | 36 | if (analog_config_bits == 8) { |
manitou | 0:e1a2b02c8441 | 37 | ADC0_CFG1 = ADC_CFG1_8BIT + BF_ADC_CFG1_MODE(0); |
manitou | 0:e1a2b02c8441 | 38 | ADC0_CFG2 = ADC_CFG2_MUXSEL_MASK + BF_ADC_CFG2_ADLSTS(3); |
manitou | 0:e1a2b02c8441 | 39 | ADC1_CFG1 = ADC_CFG1_8BIT + BF_ADC_CFG1_MODE(0); |
manitou | 0:e1a2b02c8441 | 40 | ADC1_CFG2 = ADC_CFG2_MUXSEL_MASK + BF_ADC_CFG2_ADLSTS(3); |
manitou | 0:e1a2b02c8441 | 41 | } else if (analog_config_bits == 10) { |
manitou | 0:e1a2b02c8441 | 42 | ADC0_CFG1 = ADC_CFG1_10BIT + BF_ADC_CFG1_MODE(2) + ADC_CFG1_ADLSMP_MASK; |
manitou | 0:e1a2b02c8441 | 43 | ADC0_CFG2 = ADC_CFG2_MUXSEL_MASK + BF_ADC_CFG2_ADLSTS(3); |
manitou | 0:e1a2b02c8441 | 44 | ADC1_CFG1 = ADC_CFG1_10BIT + BF_ADC_CFG1_MODE(2) + ADC_CFG1_ADLSMP_MASK; |
manitou | 0:e1a2b02c8441 | 45 | ADC1_CFG2 = ADC_CFG2_MUXSEL_MASK + BF_ADC_CFG2_ADLSTS(3); |
manitou | 0:e1a2b02c8441 | 46 | } else if (analog_config_bits == 12) { |
manitou | 0:e1a2b02c8441 | 47 | ADC0_CFG1 = ADC_CFG1_12BIT + BF_ADC_CFG1_MODE(1) + ADC_CFG1_ADLSMP_MASK; |
manitou | 0:e1a2b02c8441 | 48 | ADC0_CFG2 = ADC_CFG2_MUXSEL_MASK + BF_ADC_CFG2_ADLSTS(2); |
manitou | 0:e1a2b02c8441 | 49 | ADC1_CFG1 = ADC_CFG1_12BIT + BF_ADC_CFG1_MODE(1) + ADC_CFG1_ADLSMP_MASK; |
manitou | 0:e1a2b02c8441 | 50 | ADC1_CFG2 = ADC_CFG2_MUXSEL_MASK + BF_ADC_CFG2_ADLSTS(2); |
manitou | 0:e1a2b02c8441 | 51 | } else { |
manitou | 0:e1a2b02c8441 | 52 | ADC0_CFG1 = ADC_CFG1_16BIT + BF_ADC_CFG1_MODE(3) + ADC_CFG1_ADLSMP_MASK; |
manitou | 0:e1a2b02c8441 | 53 | ADC0_CFG2 = ADC_CFG2_MUXSEL_MASK + BF_ADC_CFG2_ADLSTS(2); |
manitou | 0:e1a2b02c8441 | 54 | ADC1_CFG1 = ADC_CFG1_16BIT + BF_ADC_CFG1_MODE(3) + ADC_CFG1_ADLSMP_MASK; |
manitou | 0:e1a2b02c8441 | 55 | ADC1_CFG2 = ADC_CFG2_MUXSEL_MASK + BF_ADC_CFG2_ADLSTS(2); |
manitou | 0:e1a2b02c8441 | 56 | } |
manitou | 0:e1a2b02c8441 | 57 | |
manitou | 0:e1a2b02c8441 | 58 | if (analog_reference_internal) { |
manitou | 0:e1a2b02c8441 | 59 | ADC0_SC2 = BF_ADC_SC2_REFSEL(1); // 1.2V ref |
manitou | 0:e1a2b02c8441 | 60 | ADC1_SC2 = BF_ADC_SC2_REFSEL(1); // 1.2V ref |
manitou | 0:e1a2b02c8441 | 61 | } else { |
manitou | 0:e1a2b02c8441 | 62 | ADC0_SC2 = BF_ADC_SC2_REFSEL(0); // vcc/ext ref |
manitou | 0:e1a2b02c8441 | 63 | ADC1_SC2 = BF_ADC_SC2_REFSEL(0); // vcc/ext ref |
manitou | 0:e1a2b02c8441 | 64 | } |
manitou | 0:e1a2b02c8441 | 65 | // calibrate ADCs |
manitou | 0:e1a2b02c8441 | 66 | t=tmr.read_us(); |
manitou | 1:9a99de9cc5d5 | 67 | if (analog_num_average <=1) { |
manitou | 1:9a99de9cc5d5 | 68 | ADC0_SC3 = ADC_SC3_CAL_MASK; // no averaging |
manitou | 1:9a99de9cc5d5 | 69 | ADC1_SC3 = ADC_SC3_CAL_MASK; |
manitou | 1:9a99de9cc5d5 | 70 | } else if (analog_num_average <=4) { |
manitou | 1:9a99de9cc5d5 | 71 | ADC0_SC3 = ADC_SC3_CAL_MASK + ADC_SC3_AVGE_MASK + BF_ADC_SC3_AVGS(0); // average 4 |
manitou | 1:9a99de9cc5d5 | 72 | ADC1_SC3 = ADC_SC3_CAL_MASK + ADC_SC3_AVGE_MASK + BF_ADC_SC3_AVGS(0); |
manitou | 1:9a99de9cc5d5 | 73 | } else if (analog_num_average <=8) { |
manitou | 1:9a99de9cc5d5 | 74 | ADC0_SC3 = ADC_SC3_CAL_MASK + ADC_SC3_AVGE_MASK + BF_ADC_SC3_AVGS(1); |
manitou | 1:9a99de9cc5d5 | 75 | ADC1_SC3 = ADC_SC3_CAL_MASK + ADC_SC3_AVGE_MASK + BF_ADC_SC3_AVGS(1); |
manitou | 1:9a99de9cc5d5 | 76 | } else if (analog_num_average <=16) { |
manitou | 1:9a99de9cc5d5 | 77 | ADC0_SC3 = ADC_SC3_CAL_MASK + ADC_SC3_AVGE_MASK + BF_ADC_SC3_AVGS(2); |
manitou | 1:9a99de9cc5d5 | 78 | ADC1_SC3 = ADC_SC3_CAL_MASK + ADC_SC3_AVGE_MASK + BF_ADC_SC3_AVGS(2); |
manitou | 1:9a99de9cc5d5 | 79 | } else { |
manitou | 1:9a99de9cc5d5 | 80 | ADC0_SC3 = ADC_SC3_CAL_MASK + ADC_SC3_AVGE_MASK + BF_ADC_SC3_AVGS(3); |
manitou | 1:9a99de9cc5d5 | 81 | ADC1_SC3 = ADC_SC3_CAL_MASK + ADC_SC3_AVGE_MASK + BF_ADC_SC3_AVGS(3); |
manitou | 1:9a99de9cc5d5 | 82 | } |
manitou | 0:e1a2b02c8441 | 83 | uint16_t sum; |
manitou | 0:e1a2b02c8441 | 84 | |
manitou | 0:e1a2b02c8441 | 85 | while ((ADC0_SC3 & ADC_SC3_CAL_MASK) || (ADC1_SC3 & ADC_SC3_CAL_MASK)) ; // wait |
manitou | 0:e1a2b02c8441 | 86 | |
manitou | 0:e1a2b02c8441 | 87 | __disable_irq(); |
manitou | 0:e1a2b02c8441 | 88 | |
manitou | 0:e1a2b02c8441 | 89 | sum = ADC0_CLPS + ADC0_CLP4 + ADC0_CLP3 + ADC0_CLP2 + ADC0_CLP1 + ADC0_CLP0; |
manitou | 0:e1a2b02c8441 | 90 | sum = (sum / 2) | 0x8000; |
manitou | 0:e1a2b02c8441 | 91 | ADC0_PG = sum; |
manitou | 0:e1a2b02c8441 | 92 | sum = ADC0_CLMS + ADC0_CLM4 + ADC0_CLM3 + ADC0_CLM2 + ADC0_CLM1 + ADC0_CLM0; |
manitou | 0:e1a2b02c8441 | 93 | sum = (sum / 2) | 0x8000; |
manitou | 0:e1a2b02c8441 | 94 | ADC0_MG = sum; |
manitou | 0:e1a2b02c8441 | 95 | sum = ADC1_CLPS + ADC1_CLP4 + ADC1_CLP3 + ADC1_CLP2 + ADC1_CLP1 + ADC1_CLP0; |
manitou | 0:e1a2b02c8441 | 96 | sum = (sum / 2) | 0x8000; |
manitou | 0:e1a2b02c8441 | 97 | ADC1_PG = sum; |
manitou | 0:e1a2b02c8441 | 98 | sum = ADC1_CLMS + ADC1_CLM4 + ADC1_CLM3 + ADC1_CLM2 + ADC1_CLM1 + ADC1_CLM0; |
manitou | 0:e1a2b02c8441 | 99 | sum = (sum / 2) | 0x8000; |
manitou | 0:e1a2b02c8441 | 100 | ADC1_MG = sum; |
manitou | 0:e1a2b02c8441 | 101 | |
manitou | 0:e1a2b02c8441 | 102 | __enable_irq(); |
manitou | 0:e1a2b02c8441 | 103 | t=tmr.read_us()-t; |
manitou | 0:e1a2b02c8441 | 104 | } |
manitou | 0:e1a2b02c8441 | 105 | |
manitou | 0:e1a2b02c8441 | 106 | static uint16_t adc_read(ADC_Type * ADCx, int channel) { |
manitou | 0:e1a2b02c8441 | 107 | ADCx->SC1[0] = channel; |
manitou | 0:e1a2b02c8441 | 108 | while(!(ADCx->SC1[0] & ADC_SC1_COCO_MASK)); // wait |
manitou | 0:e1a2b02c8441 | 109 | return ADCx->R[0]; |
manitou | 0:e1a2b02c8441 | 110 | } |
manitou | 0:e1a2b02c8441 | 111 | |
manitou | 0:e1a2b02c8441 | 112 | int main() |
manitou | 0:e1a2b02c8441 | 113 | { |
manitou | 0:e1a2b02c8441 | 114 | int ADCmax = 1 << analog_config_bits; |
manitou | 0:e1a2b02c8441 | 115 | int val, i; |
manitou | 0:e1a2b02c8441 | 116 | float Vcc, tempc, slope=ADCmax*0.76/3.3, val25=ADCmax*.0025/3.3; |
manitou | 0:e1a2b02c8441 | 117 | |
manitou | 0:e1a2b02c8441 | 118 | printf("\nSystemCoreClock %d %s %s\n",SystemCoreClock,__TIME__,__DATE__); |
manitou | 0:e1a2b02c8441 | 119 | tmr.start(); |
manitou | 0:e1a2b02c8441 | 120 | adc_init(); |
manitou | 2:71d82e4b3777 | 121 | dac.write(0.5); // 3.3/2 jumper to A0 and read internal |
manitou | 1:9a99de9cc5d5 | 122 | |
manitou | 0:e1a2b02c8441 | 123 | PRREG(SIM_SCGC6); |
manitou | 0:e1a2b02c8441 | 124 | PRREG(SIM_SCGC3); |
manitou | 0:e1a2b02c8441 | 125 | PRREG(VREF->TRM); |
manitou | 0:e1a2b02c8441 | 126 | PRREG(VREF_SC); |
manitou | 0:e1a2b02c8441 | 127 | PRREG(PMC_REGSC); |
manitou | 0:e1a2b02c8441 | 128 | PRREG(ADC0->SC1[0]); // or ADC0_SCA |
manitou | 0:e1a2b02c8441 | 129 | PRREG(ADC0->SC1[1]); |
manitou | 0:e1a2b02c8441 | 130 | PRREG(ADC0->CFG1); |
manitou | 0:e1a2b02c8441 | 131 | PRREG(ADC0_CFG2); |
manitou | 0:e1a2b02c8441 | 132 | PRREG(ADC0->SC2); |
manitou | 0:e1a2b02c8441 | 133 | PRREG(ADC0->SC3); |
manitou | 2:71d82e4b3777 | 134 | PRREG(ADC1->SC1[0]); // ADC1 |
manitou | 2:71d82e4b3777 | 135 | PRREG(ADC1->SC1[1]); |
manitou | 2:71d82e4b3777 | 136 | PRREG(ADC1->CFG1); |
manitou | 2:71d82e4b3777 | 137 | PRREG(ADC1_CFG2); |
manitou | 2:71d82e4b3777 | 138 | PRREG(ADC1->SC2); |
manitou | 2:71d82e4b3777 | 139 | PRREG(ADC1->SC3); |
manitou | 2:71d82e4b3777 | 140 | |
manitou | 1:9a99de9cc5d5 | 141 | printf("res %d average %d calibration %d us\n",analog_config_bits,analog_num_average,t); |
manitou | 0:e1a2b02c8441 | 142 | val = adc_read(ADC1,18); // VREF OUT |
manitou | 0:e1a2b02c8441 | 143 | Vcc = ADCmax*1.195/val; |
manitou | 0:e1a2b02c8441 | 144 | printf("VREF val %d %.2f v\n",val,Vcc); |
manitou | 0:e1a2b02c8441 | 145 | val = adc_read(ADC0,27); // bandgap |
manitou | 0:e1a2b02c8441 | 146 | Vcc = ADCmax*1.0/val; |
manitou | 0:e1a2b02c8441 | 147 | printf("bandgap val %d %.2f v\n",val,Vcc); |
manitou | 2:71d82e4b3777 | 148 | val = adc_read(ADC0,12); // didn't do GPIO init for A0 |
manitou | 2:71d82e4b3777 | 149 | printf("A0 val %d %.2f v\n",val,3.3*val/ADCmax); |
manitou | 2:71d82e4b3777 | 150 | val = adc_read(ADC1,23); // DAC to internal ADC |
manitou | 2:71d82e4b3777 | 151 | printf("DAC val %d %.2f v\n",val,3.3*val/ADCmax); |
manitou | 0:e1a2b02c8441 | 152 | t=tmr.read_us(); |
manitou | 0:e1a2b02c8441 | 153 | for(i=0;i<1000;i++) adc_read(ADC0,12); |
manitou | 0:e1a2b02c8441 | 154 | t=tmr.read_us()-t; |
manitou | 0:e1a2b02c8441 | 155 | printf("avrg A0 read %d us\n",t/1000); |
manitou | 2:71d82e4b3777 | 156 | // need internal VREF for temp sensor ?? TODO |
manitou | 2:71d82e4b3777 | 157 | analog_reference_internal = 1; |
manitou | 2:71d82e4b3777 | 158 | adc_init(); // re init and calibrate |
manitou | 2:71d82e4b3777 | 159 | val = adc_read(ADC0,26); // temp sensor |
manitou | 2:71d82e4b3777 | 160 | tempc = ((val-val25)/slope) + 25.f; |
manitou | 2:71d82e4b3777 | 161 | printf("temp val %d %.1f C\n",val,tempc); |
manitou | 0:e1a2b02c8441 | 162 | } |