Jared Baxter
/
Impedance_Fast_Circuitry
Fork of DSP_200kHz by
Sample/adc.cpp@52:5a40cc58c4c2, 2015-01-31 (annotated)
- Committer:
- timmey9
- Date:
- Sat Jan 31 20:56:04 2015 +0000
- Revision:
- 52:5a40cc58c4c2
- Parent:
- adc.cpp@51:43143a3fc2d7
Made minor cosmetic and comment changes.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
timmey9 | 39:82dc3daecf32 | 1 | #include "adc.h" |
timmey9 | 45:d591d138cdeb | 2 | |
timmey9 | 44:41c262caf898 | 3 | /* |
timmey9 | 44:41c262caf898 | 4 | TODO: remove interrupt handlers |
timmey9 | 48:29f14bc30ba6 | 5 | finish calibration |
timmey9 | 45:d591d138cdeb | 6 | change clock speed |
timmey9 | 44:41c262caf898 | 7 | */ |
timmey9 | 51:43143a3fc2d7 | 8 | DigitalOut toggle1(PTA0); |
timmey9 | 45:d591d138cdeb | 9 | DigitalOut green(LED_GREEN); |
timmey9 | 45:d591d138cdeb | 10 | DigitalOut red(LED_RED); |
timmey9 | 51:43143a3fc2d7 | 11 | //Serial debug(USBTX,USBRX); |
timmey9 | 51:43143a3fc2d7 | 12 | |
timmey9 | 51:43143a3fc2d7 | 13 | |
timmey9 | 39:82dc3daecf32 | 14 | |
timmey9 | 51:43143a3fc2d7 | 15 | /* The ADCs are setup so that ADC0 and ADC1 are triggered by the PDB. |
timmey9 | 51:43143a3fc2d7 | 16 | * When the conversions are complete, ADC0 and ADC1 then trigger DMA0 |
timmey9 | 52:5a40cc58c4c2 | 17 | * and DMA1, respectively. ADC0 is using channel B and ADC1 is uing |
timmey9 | 52:5a40cc58c4c2 | 18 | * channel A. If they are on the same channel, then weird things |
timmey9 | 52:5a40cc58c4c2 | 19 | * happen. I think they interfere with each other so they have to be |
timmey9 | 52:5a40cc58c4c2 | 20 | * on separate channels if they're going to be triggered at the same |
timmey9 | 52:5a40cc58c4c2 | 21 | * time by the PDB. */ |
timmey9 | 45:d591d138cdeb | 22 | void adc_init() |
timmey9 | 39:82dc3daecf32 | 23 | { |
timmey9 | 45:d591d138cdeb | 24 | // red, indicating now ready |
timmey9 | 45:d591d138cdeb | 25 | red = 0; |
timmey9 | 45:d591d138cdeb | 26 | green = 1; |
timmey9 | 45:d591d138cdeb | 27 | |
timmey9 | 39:82dc3daecf32 | 28 | // Turn on the ADC0 and ADC1 clocks |
timmey9 | 39:82dc3daecf32 | 29 | SIM_SCGC6 |= SIM_SCGC6_ADC0_MASK; |
timmey9 | 39:82dc3daecf32 | 30 | SIM_SCGC3 |= SIM_SCGC3_ADC1_MASK; |
timmey9 | 40:bd6d8c35e822 | 31 | |
timmey9 | 45:d591d138cdeb | 32 | // Set ADC hardware trigger to PDB0 |
timmey9 | 48:29f14bc30ba6 | 33 | SIM_SOPT7 = SIM_SOPT7_ADC0TRGSEL(0); // Select triggering by PDB and select pre-trigger A |
timmey9 | 48:29f14bc30ba6 | 34 | SIM_SOPT7 = SIM_SOPT7_ADC1TRGSEL(0); // Select triggering by PDB and select pre-trigger A |
timmey9 | 39:82dc3daecf32 | 35 | |
timmey9 | 45:d591d138cdeb | 36 | // Setup Configuration Register 1 |
timmey9 | 45:d591d138cdeb | 37 | ADC0_CFG1 = 0; // clear register |
timmey9 | 45:d591d138cdeb | 38 | ADC0_CFG1 |= ADC_CFG1_ADICLK(0); // select bus clock |
timmey9 | 45:d591d138cdeb | 39 | ADC0_CFG1 |= ADC_CFG1_MODE(3); // select 16-bit 2's complement output |
timmey9 | 45:d591d138cdeb | 40 | ADC0_CFG1 |= ADC_CFG1_ADIV(0); // select short sample time |
timmey9 | 45:d591d138cdeb | 41 | ADC0_CFG1 &= ~ADC_CFG1_ADLSMP_MASK; // select short sample time |
timmey9 | 45:d591d138cdeb | 42 | ADC0_CFG1 &= ~ADC_CFG1_ADLPC_MASK; // select normal power configuration |
timmey9 | 46:a015ebf4663b | 43 | ADC1_CFG1 = 0; // clear register |
timmey9 | 46:a015ebf4663b | 44 | ADC1_CFG1 |= ADC_CFG1_ADICLK(0); // select bus clock |
timmey9 | 46:a015ebf4663b | 45 | ADC1_CFG1 |= ADC_CFG1_MODE(3); // select 16-bit 2's complement output |
timmey9 | 46:a015ebf4663b | 46 | ADC1_CFG1 |= ADC_CFG1_ADIV(0); // select short sample time |
timmey9 | 46:a015ebf4663b | 47 | ADC1_CFG1 &= ~ADC_CFG1_ADLSMP_MASK; // select short sample time |
timmey9 | 46:a015ebf4663b | 48 | ADC1_CFG1 &= ~ADC_CFG1_ADLPC_MASK; // select normal power configuration |
timmey9 | 45:d591d138cdeb | 49 | |
timmey9 | 45:d591d138cdeb | 50 | // Setup Configuration Register 2 |
timmey9 | 45:d591d138cdeb | 51 | ADC0_CFG2 = 0; // clear register |
timmey9 | 47:54fafe151669 | 52 | ADC0_CFG2 |= ADC_CFG2_ADHSC_MASK ; // select high-speed conversion |
timmey9 | 45:d591d138cdeb | 53 | ADC0_CFG2 &= ~ADC_CFG2_MUXSEL_MASK; // select a channels |
timmey9 | 49:4dcf4717a8bb | 54 | ADC1_CFG2 = 0; // clear register |
timmey9 | 49:4dcf4717a8bb | 55 | ADC1_CFG2 |= ADC_CFG2_ADHSC_MASK ; // select high-speed conversion |
timmey9 | 50:33524a27e08c | 56 | ADC1_CFG2 &= ~ADC_CFG2_MUXSEL_MASK; // select a channels |
timmey9 | 50:33524a27e08c | 57 | |
timmey9 | 39:82dc3daecf32 | 58 | |
timmey9 | 45:d591d138cdeb | 59 | // Setup Status and Control Register 2 |
timmey9 | 47:54fafe151669 | 60 | ADC0_SC2 = 0; // clear register |
timmey9 | 47:54fafe151669 | 61 | ADC0_SC2 |= ADC_SC2_REFSEL(0); // select external voltage reference |
timmey9 | 47:54fafe151669 | 62 | ADC0_SC2 |= ADC_SC2_DMAEN_MASK; // enable DMA |
timmey9 | 45:d591d138cdeb | 63 | ADC0_SC2 &= ~ADC_SC2_ADTRG_MASK; // select software trigger until calibration is complete |
timmey9 | 47:54fafe151669 | 64 | ADC1_SC2 = 0; // clear register |
timmey9 | 47:54fafe151669 | 65 | ADC1_SC2 |= ADC_SC2_REFSEL(0); // select external voltage reference |
timmey9 | 47:54fafe151669 | 66 | ADC1_SC2 |= ADC_SC2_DMAEN_MASK; // enable DMA |
timmey9 | 46:a015ebf4663b | 67 | ADC1_SC2 &= ~ADC_SC2_ADTRG_MASK; // select software trigger until calibration is complete |
timmey9 | 45:d591d138cdeb | 68 | |
timmey9 | 45:d591d138cdeb | 69 | // Setup Status and Control Register 3 |
timmey9 | 45:d591d138cdeb | 70 | ADC0_SC3 = 0; // Hardware Average set to 4 samples averaged |
timmey9 | 45:d591d138cdeb | 71 | // Hardware Average Disabled |
timmey9 | 45:d591d138cdeb | 72 | // select single conversion mode |
timmey9 | 46:a015ebf4663b | 73 | ADC1_SC3 = 0; // Hardware Average set to 4 samples averaged |
timmey9 | 46:a015ebf4663b | 74 | // Hardware Average Disabled |
timmey9 | 46:a015ebf4663b | 75 | // select single conversion mode |
timmey9 | 39:82dc3daecf32 | 76 | |
timmey9 | 45:d591d138cdeb | 77 | // calibrate the ADC |
timmey9 | 45:d591d138cdeb | 78 | ADC0_SC3 |= ADC_SC3_CAL_MASK; // start calibration |
timmey9 | 45:d591d138cdeb | 79 | while(ADC0_SC3&ADC_SC3_CALF_MASK) {} // wait for calibration to complete |
timmey9 | 46:a015ebf4663b | 80 | ADC1_SC3 |= ADC_SC3_CAL_MASK; // start calibration |
timmey9 | 46:a015ebf4663b | 81 | while(ADC1_SC3&ADC_SC3_CALF_MASK) {} // wait for calibration to complete |
timmey9 | 46:a015ebf4663b | 82 | |
timmey9 | 45:d591d138cdeb | 83 | |
timmey9 | 45:d591d138cdeb | 84 | // calculate the gains (see user manual page 864) |
timmey9 | 45:d591d138cdeb | 85 | int16_t gain = (ADC0_CLP0+ADC0_CLP1+ADC0_CLP2+ADC0_CLP3+ADC0_CLP4+ADC0_CLPS); |
timmey9 | 45:d591d138cdeb | 86 | gain = (gain>>1); // divide by 2 |
timmey9 | 45:d591d138cdeb | 87 | gain |= 0x8000; // set the MSB |
timmey9 | 45:d591d138cdeb | 88 | ADC0_PG = gain; |
timmey9 | 45:d591d138cdeb | 89 | |
timmey9 | 46:a015ebf4663b | 90 | gain = (ADC1_CLP0+ADC1_CLP1+ADC1_CLP2+ADC1_CLP3+ADC1_CLP4+ADC1_CLPS); |
timmey9 | 46:a015ebf4663b | 91 | gain = (gain>>1); // divide by 2 |
timmey9 | 46:a015ebf4663b | 92 | gain |= 0x8000; // set the MSB |
timmey9 | 46:a015ebf4663b | 93 | ADC1_PG = gain; |
timmey9 | 46:a015ebf4663b | 94 | |
timmey9 | 45:d591d138cdeb | 95 | gain = (ADC0_CLM0+ADC0_CLM1+ADC0_CLM2+ADC0_CLM3+ADC0_CLM4+ADC0_CLMS); |
timmey9 | 45:d591d138cdeb | 96 | gain = (gain>>1); // divide by 2 |
timmey9 | 45:d591d138cdeb | 97 | gain |= 0x8000; // set the MSB |
timmey9 | 45:d591d138cdeb | 98 | ADC0_MG = gain; |
timmey9 | 39:82dc3daecf32 | 99 | |
timmey9 | 46:a015ebf4663b | 100 | gain = (ADC1_CLM0+ADC1_CLM1+ADC1_CLM2+ADC1_CLM3+ADC1_CLM4+ADC1_CLMS); |
timmey9 | 46:a015ebf4663b | 101 | gain = (gain>>1); // divide by 2 |
timmey9 | 46:a015ebf4663b | 102 | gain |= 0x8000; // set the MSB |
timmey9 | 46:a015ebf4663b | 103 | ADC1_MG = gain; |
timmey9 | 46:a015ebf4663b | 104 | |
timmey9 | 45:d591d138cdeb | 105 | ADC0_SC3 &= ~ADC_SC3_CAL_MASK; // stop calibration |
timmey9 | 46:a015ebf4663b | 106 | ADC1_SC3 &= ~ADC_SC3_CAL_MASK; // stop calibration |
timmey9 | 45:d591d138cdeb | 107 | |
timmey9 | 45:d591d138cdeb | 108 | |
timmey9 | 45:d591d138cdeb | 109 | |
timmey9 | 45:d591d138cdeb | 110 | // yellow indicating calibration complete |
timmey9 | 45:d591d138cdeb | 111 | red = 0; |
timmey9 | 45:d591d138cdeb | 112 | green = 0; |
timmey9 | 45:d591d138cdeb | 113 | |
timmey9 | 45:d591d138cdeb | 114 | ADC0_SC2 |= ADC_SC2_ADTRG_MASK; // select hardware trigger now that calibration is complete |
timmey9 | 46:a015ebf4663b | 115 | ADC1_SC2 |= ADC_SC2_ADTRG_MASK; // select hardware trigger now that calibration is complete |
timmey9 | 45:d591d138cdeb | 116 | |
timmey9 | 50:33524a27e08c | 117 | // Setup Status and Control Register 1A |
timmey9 | 48:29f14bc30ba6 | 118 | ADC0_SC1B = 0; // clear register |
timmey9 | 48:29f14bc30ba6 | 119 | ADC0_SC1B &= ~ADC_SC1_DIFF_MASK; // select single-ended mode |
timmey9 | 48:29f14bc30ba6 | 120 | ADC0_SC1B |= ADC_SC1_AIEN_MASK; // enable interrupt (for debugging) |
timmey9 | 48:29f14bc30ba6 | 121 | ADC0_SC1B |= ADC_SC1_ADCH(13); // select channel 13 |
timmey9 | 50:33524a27e08c | 122 | ADC1_SC1A = 0; // clear register |
timmey9 | 50:33524a27e08c | 123 | ADC1_SC1A &= ~ADC_SC1_DIFF_MASK; // select single-ended mode |
timmey9 | 50:33524a27e08c | 124 | ADC1_SC1A |= ADC_SC1_AIEN_MASK; // enable interrupt (for debugging) |
timmey9 | 51:43143a3fc2d7 | 125 | ADC1_SC1A |= ADC_SC1_ADCH(14); // select channel 14 |
timmey9 | 51:43143a3fc2d7 | 126 | |
timmey9 | 45:d591d138cdeb | 127 | |
timmey9 | 45:d591d138cdeb | 128 | // Check if ADC is finished initializing TODO: This part doesn't seem right, but I did it according to 871 |
timmey9 | 48:29f14bc30ba6 | 129 | while( (ADC0_SC1B&ADC_SC1_COCO_MASK)) {} |
timmey9 | 50:33524a27e08c | 130 | gain = ADC0_RA; // read the register to clear SC1A[COCO] |
timmey9 | 50:33524a27e08c | 131 | while( (ADC1_SC1A&ADC_SC1_COCO_MASK)) {} |
timmey9 | 50:33524a27e08c | 132 | gain = ADC1_RA; // read the register to clear SC1A[COCO] |
timmey9 | 45:d591d138cdeb | 133 | |
timmey9 | 45:d591d138cdeb | 134 | |
timmey9 | 45:d591d138cdeb | 135 | // green indicating calibration and initialization complete |
timmey9 | 45:d591d138cdeb | 136 | red = 1; |
timmey9 | 45:d591d138cdeb | 137 | green = 0; |
timmey9 | 45:d591d138cdeb | 138 | |
timmey9 | 40:bd6d8c35e822 | 139 | // Enable the ISR vector |
timmey9 | 47:54fafe151669 | 140 | //NVIC_SetVector(ADC0_IRQn, (uint32_t)&ADC0_IRQHandler); |
timmey9 | 47:54fafe151669 | 141 | //NVIC_EnableIRQ(ADC0_IRQn); |
timmey9 | 40:bd6d8c35e822 | 142 | } |
timmey9 | 40:bd6d8c35e822 | 143 | |
timmey9 | 51:43143a3fc2d7 | 144 | |
timmey9 | 51:43143a3fc2d7 | 145 | void ADC0_IRQHandler() { |
timmey9 | 51:43143a3fc2d7 | 146 | |
timmey9 | 51:43143a3fc2d7 | 147 | toggle1 = !toggle1; |
timmey9 | 51:43143a3fc2d7 | 148 | } |
timmey9 | 51:43143a3fc2d7 | 149 | |
timmey9 | 51:43143a3fc2d7 | 150 | |
timmey9 | 51:43143a3fc2d7 | 151 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
timmey9 | 51:43143a3fc2d7 | 152 | * DEBUG: This is supposed to put the ADC in continuous * |
timmey9 | 51:43143a3fc2d7 | 153 | * mode so it samples without the PCB. But for * |
timmey9 | 51:43143a3fc2d7 | 154 | * some reason it isn't working. I haven't deleted * |
timmey9 | 51:43143a3fc2d7 | 155 | * it just in case it is needed for debug purposes * |
timmey9 | 51:43143a3fc2d7 | 156 | * in the future. * |
timmey9 | 51:43143a3fc2d7 | 157 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
timmey9 | 41:3e0623d81b9a | 158 | void adc_start() { |
timmey9 | 40:bd6d8c35e822 | 159 | // reset DMA |
timmey9 | 45:d591d138cdeb | 160 | dma_reset(); |
timmey9 | 40:bd6d8c35e822 | 161 | |
timmey9 | 40:bd6d8c35e822 | 162 | // set ADC to continuous mode |
timmey9 | 40:bd6d8c35e822 | 163 | ADC0_SC3 |= ADC_SC3_ADCO_MASK; |
timmey9 | 46:a015ebf4663b | 164 | ADC1_SC3 |= ADC_SC3_ADCO_MASK; |
timmey9 | 45:d591d138cdeb | 165 | |
timmey9 | 45:d591d138cdeb | 166 | // set ADC to software trigger |
timmey9 | 47:54fafe151669 | 167 | ADC0_SC2 &= ~ADC_SC2_ADTRG_MASK; |
timmey9 | 46:a015ebf4663b | 168 | ADC1_SC2 &= ~ADC_SC2_ADTRG_MASK; |
timmey9 | 40:bd6d8c35e822 | 169 | |
timmey9 | 40:bd6d8c35e822 | 170 | // start ADC conversion (SW trigger) |
timmey9 | 50:33524a27e08c | 171 | ADC0_SC1B |= ADC_SC1_ADCH(13); // write to SC1A causing a trigger |
timmey9 | 50:33524a27e08c | 172 | ADC1_SC1A |= ADC_SC1_ADCH(14); // write to SC1A causing a trigger |
timmey9 | 40:bd6d8c35e822 | 173 | } |
timmey9 | 40:bd6d8c35e822 | 174 | |
timmey9 | 51:43143a3fc2d7 | 175 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
timmey9 | 51:43143a3fc2d7 | 176 | * DEBUG: This is supposed to revert back from adc_start() * |
timmey9 | 51:43143a3fc2d7 | 177 | * but because adc_start() isn't working, this * |
timmey9 | 51:43143a3fc2d7 | 178 | * function is good for nothing. I held on to * |
timmey9 | 51:43143a3fc2d7 | 179 | * it just in case it is needed for debug purposes * |
timmey9 | 51:43143a3fc2d7 | 180 | * in the future. * |
timmey9 | 51:43143a3fc2d7 | 181 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
timmey9 | 41:3e0623d81b9a | 182 | void adc_stop() { |
timmey9 | 45:d591d138cdeb | 183 | // set ADC to hardware trigger |
timmey9 | 45:d591d138cdeb | 184 | ADC0_SC2 |= ADC_SC2_ADTRG_MASK; |
timmey9 | 46:a015ebf4663b | 185 | ADC1_SC2 |= ADC_SC2_ADTRG_MASK; |
timmey9 | 45:d591d138cdeb | 186 | |
timmey9 | 45:d591d138cdeb | 187 | // set to single conversion mode effectively stopping the ADC unless a timer triggers the ADC |
timmey9 | 45:d591d138cdeb | 188 | ADC0_SC3 &= ~ADC_SC3_ADCO_MASK; |
timmey9 | 46:a015ebf4663b | 189 | ADC1_SC3 &= ~ADC_SC3_ADCO_MASK; |
timmey9 | 45:d591d138cdeb | 190 | } |
timmey9 | 45:d591d138cdeb | 191 | |
timmey9 | 51:43143a3fc2d7 | 192 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
timmey9 | 51:43143a3fc2d7 | 193 | * DEBUG: This is supposed to trigger a software conversion * |
timmey9 | 51:43143a3fc2d7 | 194 | * and take a single sample. However, it only * |
timmey9 | 51:43143a3fc2d7 | 195 | * worked for ADC1 for some reason. It is here for * |
timmey9 | 51:43143a3fc2d7 | 196 | * possible debug purposes in the future. * |
timmey9 | 51:43143a3fc2d7 | 197 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
timmey9 | 45:d591d138cdeb | 198 | void adc_single_sample() { |
timmey9 | 45:d591d138cdeb | 199 | ADC0_SC3 &= ~ADC_SC3_ADCO_MASK; // single conversion mode |
timmey9 | 46:a015ebf4663b | 200 | ADC1_SC3 &= ~ADC_SC3_ADCO_MASK; // single conversion mode |
timmey9 | 45:d591d138cdeb | 201 | ADC0_SC2 &= ~ADC_SC2_ADTRG_MASK; // set ADC to software trigger |
timmey9 | 46:a015ebf4663b | 202 | ADC1_SC2 &= ~ADC_SC2_ADTRG_MASK; // set ADC to software trigger |
timmey9 | 50:33524a27e08c | 203 | ADC0_SC1B |= ADC_SC1_ADCH(13); // write to SC1B causing a trigger |
timmey9 | 50:33524a27e08c | 204 | ADC1_SC1A |= ADC_SC1_ADCH(14); // write to SC1A causing a trigger |
timmey9 | 50:33524a27e08c | 205 | |
timmey9 | 50:33524a27e08c | 206 | // Set back to hardware trigger |
timmey9 | 50:33524a27e08c | 207 | ADC0_SC2 |= ADC_SC2_ADTRG_MASK; // set ADC to software trigger |
timmey9 | 50:33524a27e08c | 208 | ADC1_SC2 |= ADC_SC2_ADTRG_MASK; // set ADC to software trigger |
timmey9 | 40:bd6d8c35e822 | 209 | } |
timmey9 | 40:bd6d8c35e822 | 210 | |
timmey9 | 51:43143a3fc2d7 | 211 | |
timmey9 | 51:43143a3fc2d7 | 212 | /* |
timmey9 | 51:43143a3fc2d7 | 213 | debug.printf("ADC0_SC1a: %08x\r\n",ADC0_SC1A); //(0x0000004d) |
timmey9 | 51:43143a3fc2d7 | 214 | debug.printf("ADC0_SC1b: %08x\r\n",ADC0_SC1B); //(0x0000001f) |
timmey9 | 51:43143a3fc2d7 | 215 | debug.printf("ADC0_CFG1: %08x\r\n",ADC0_CFG1); //(0x0000000c) |
timmey9 | 51:43143a3fc2d7 | 216 | debug.printf("ADC0_CFG2: %08x\r\n",ADC0_CFG2); //(0x00000004) |
timmey9 | 51:43143a3fc2d7 | 217 | debug.printf("ADC0_RA: %08x\r\n",ADC0_RA); //(0x00000000) |
timmey9 | 51:43143a3fc2d7 | 218 | debug.printf("ADC0_RB: %08x\r\n",ADC0_RB); //(0x00000000) |
timmey9 | 51:43143a3fc2d7 | 219 | debug.printf("ADC0_SC2: %08x\r\n",ADC0_SC2); //(0x00000044) |
timmey9 | 51:43143a3fc2d7 | 220 | debug.printf("ADC0_SC3: %08x\r\n\n",ADC0_SC3); //(0x00000000) |
timmey9 | 51:43143a3fc2d7 | 221 | */ |