Jared's DAC Code
Dependencies: mbed
Fork of Chemical_Sensor_DMA by
Sample/adc.cpp
- Committer:
- DeWayneDennis
- Date:
- 2015-12-19
- Revision:
- 7:af255a90505e
- Parent:
- 4:9fd291254686
File content as of revision 7:af255a90505e:
#include "adc.h" /* TODO: calibration is done, i think change clock speed and hw averaging */ DigitalOut green(LED_GREEN); DigitalOut red(LED_RED); /* The ADCs are setup so that ADC0 and ADC1 are triggered by the PDB. * When the conversions are complete, ADC0 and ADC1 then trigger DMA0 * and DMA1, respectively. ADC0 is using channel B and ADC1 is uing * channel A. If they are on the same channel, then weird things * happen. I think they interfere with each other so they have to be * on separate channels if they're going to be triggered at the same * time by the PDB. */ void adc_init() { // red, indicating not ready red = 0; green = 1; // 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 // calibrate the ADC //__disable_irq(); //if(adc_cal()) {red = 0; green = 0;} // if calibration fails, display yellow //if(adc_cal1()) {red = 0; green = 0;} // if calibration fails, display yellow //__enable_irq(); // Setup Configuration Register 1 ADC0_CFG1 = 0; // clear register ADC0_CFG1 |= ADC_CFG1_ADICLK(0); // select bus clock ADC0_CFG1 |= ADC_CFG1_MODE(3); // select 16-bit 2's complement output ADC0_CFG1 |= ADC_CFG1_ADIV(0); // select short sample time ADC0_CFG1 &= ~ADC_CFG1_ADLSMP_MASK; // select short sample time ADC0_CFG1 &= ~ADC_CFG1_ADLPC_MASK; // select normal power configuration ADC1_CFG1 = 0; // clear register ADC1_CFG1 |= ADC_CFG1_ADICLK(0); // select bus clock ADC1_CFG1 |= ADC_CFG1_MODE(3); // select 16-bit 2's complement output ADC1_CFG1 |= ADC_CFG1_ADIV(0); // select short sample time ADC1_CFG1 &= ~ADC_CFG1_ADLSMP_MASK; // select short sample time ADC1_CFG1 &= ~ADC_CFG1_ADLPC_MASK; // select normal power configuration // Setup Configuration Register 2 ADC0_CFG2 = 0; // clear register //ADC0_CFG2 |= ADC_CFG2_ADHSC_MASK ; // select high-speed conversion ADC0_CFG2 &= ~ADC_CFG2_MUXSEL_MASK; // select a channels ADC1_CFG2 = 0; // clear register //ADC1_CFG2 |= ADC_CFG2_ADHSC_MASK ; // select high-speed conversion ADC1_CFG2 &= ~ADC_CFG2_MUXSEL_MASK; // select a channels // Setup Status and Control Register 2 ADC0_SC2 = 0; // clear register ADC0_SC2 |= ADC_SC2_REFSEL(0); // select external voltage reference ADC0_SC2 |= ADC_SC2_DMAEN_MASK; // enable DMA ADC0_SC2 |= ADC_SC2_ADTRG_MASK; // select hardware trigger ADC1_SC2 = 0; // clear register ADC1_SC2 |= ADC_SC2_REFSEL(0); // select external voltage reference ADC1_SC2 |= ADC_SC2_DMAEN_MASK; // enable DMA ADC1_SC2 |= ADC_SC2_ADTRG_MASK; // select hardware trigger // Setup Status and Control Register 3 now that calibration is complete ADC0_SC3 = 0; // Hardware Average set to 4 samples averaged // Hardware Average Disabled // select single conversion mode ADC1_SC3 = 0; // Hardware Average set to 4 samples averaged // Hardware Average Disabled // select single conversion mode // Setup Status and Control Register 3 now that calibration is complete //ADC0_SC3 = ADC_SC3_AVGS(0) | ADC_SC3_AVGE_MASK; // Hardware Average set to 16 samples averaged // select single conversion mode //ADC1_SC3 = ADC_SC3_AVGS(0) | ADC_SC3_AVGE_MASK; // Hardware Average set to 16 samples averaged // Setup Status and Control Register 1A ADC0_SC1B = 0; // clear register ADC0_SC1B &= ~ADC_SC1_DIFF_MASK; // select single-ended mode ADC0_SC1B |= ADC_SC1_AIEN_MASK; // enable interrupt (for debugging) ADC0_SC1B |= ADC_SC1_ADCH(12); // select channel 13 ADC1_SC1A = 0; // clear register ADC1_SC1A &= ~ADC_SC1_DIFF_MASK; // select single-ended mode ADC1_SC1A |= ADC_SC1_AIEN_MASK; // enable interrupt (for debugging) ADC1_SC1A |= ADC_SC1_ADCH(14); // select channel 14 // Check if ADC is finished initializing TODO: This part doesn't seem right, but I did it according to 871 while( (ADC0_SC1B&ADC_SC1_COCO_MASK)) {} int gain = ADC0_RA; // read the register to clear SC1A[COCO] while( (ADC1_SC1A&ADC_SC1_COCO_MASK)) {} gain = ADC1_RA; // read the register to clear SC1A[COCO] red = 1; green = 1; } /* adc_cal * Calibrates the adc * Returns 0 if successful calibration * Returns 1 otherwise * */ int adc_cal(void) { ADC0_CFG1 |= (ADC_CFG1_MODE(3) | // 16 bits mode ADC_CFG1_ADICLK(1)| // Input Bus Clock divided by 2 (20-25 MHz out of reset (FEI mode) / 2) ADC_CFG1_ADIV(2)) ; // Clock divide by 4 (2.5-3 MHz) ADC0_SC3 |= ADC_SC3_AVGE_MASK | // Enable HW average ADC_SC3_AVGS(3) | // Set HW average of 32 samples ADC_SC3_CAL_MASK; // Start calibration process while(ADC0_SC3 & ADC_SC3_CAL_MASK); // Wait for calibration to end if(ADC0_SC3 & ADC_SC3_CALF_MASK) return 1; // Check for successful calibration uint16_t calib = 0; // calibration variable calib += ADC0->CLPS + ADC0_CLP4 + ADC0_CLP3 + ADC0_CLP2 + ADC0_CLP1 + ADC0_CLP0; calib /= 2; calib |= 0x8000; // Set MSB ADC0_PG = calib; calib = 0; calib += ADC0_CLMS + ADC0_CLM4 + ADC0_CLM3 + ADC0_CLM2 + ADC0_CLM1 + ADC0_CLM0; calib /= 2; calib |= 0x8000; // Set MSB ADC0_MG = calib; return 0; } int adc_cal1(void) { ADC1_CFG1 |= (ADC_CFG1_MODE(3) | // 16 bits mode ADC_CFG1_ADICLK(1)| // Input Bus Clock divided by 2 (20-25 MHz out of reset (FEI mode) / 2) ADC_CFG1_ADIV(2)) ; // Clock divide by 4 (2.5-3 MHz) ADC1_SC3 |= ADC_SC3_AVGE_MASK | // Enable HW average ADC_SC3_AVGS(3) | // Set HW average of 32 samples ADC_SC3_CAL_MASK; // Start calibration process while(ADC1_SC3 & ADC_SC3_CAL_MASK); // Wait for calibration to end if(ADC1_SC3 & ADC_SC3_CALF_MASK) return 1; // Check for successful calibration uint16_t calib = 0; // calibration variable calib += ADC1->CLPS + ADC1_CLP4 + ADC1_CLP3 + ADC1_CLP2 + ADC1_CLP1 + ADC1_CLP0; calib /= 2; calib |= 0x8000; // Set MSB ADC1_PG = calib; calib = 0; calib += ADC1_CLMS + ADC1_CLM4 + ADC1_CLM3 + ADC1_CLM2 + ADC1_CLM1 + ADC1_CLM0; calib /= 2; calib |= 0x8000; // Set MSB ADC1_MG = calib; return 0; } /* * * * * * * * * * * * * * For Debugging Purposes * * * * * * * * * * * * * * * * * * * * */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * DEBUG: This is supposed to put the ADC in continuous * * mode so it samples without the PCB. But for * * some reason it isn't working. I haven't deleted * * it just in case it is needed for debug purposes * * in the future. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void adc_start() { // reset DMA dma_reset(); // set ADC to continuous mode ADC0_SC3 |= ADC_SC3_ADCO_MASK; ADC1_SC3 |= ADC_SC3_ADCO_MASK; // set ADC to software trigger ADC0_SC2 &= ~ADC_SC2_ADTRG_MASK; ADC1_SC2 &= ~ADC_SC2_ADTRG_MASK; // start ADC conversion (SW trigger) ADC0_SC1B |= ADC_SC1_ADCH(13); // write to SC1A causing a trigger ADC1_SC1A |= ADC_SC1_ADCH(14); // write to SC1A causing a trigger } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * DEBUG: This is supposed to revert back from adc_start() * * but because adc_start() isn't working, this * * function is good for nothing. I held on to * * it just in case it is needed for debug purposes * * in the future. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void adc_stop() { // set ADC to hardware trigger ADC0_SC2 |= ADC_SC2_ADTRG_MASK; ADC1_SC2 |= ADC_SC2_ADTRG_MASK; // set to single conversion mode effectively stopping the ADC unless a timer triggers the ADC ADC0_SC3 &= ~ADC_SC3_ADCO_MASK; ADC1_SC3 &= ~ADC_SC3_ADCO_MASK; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * DEBUG: This is supposed to trigger a software conversion * * and take a single sample. However, it only * * worked for ADC1 for some reason. It is here for * * possible debug purposes in the future. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void adc_single_sample() { ADC0_SC3 &= ~ADC_SC3_ADCO_MASK; // single conversion mode ADC1_SC3 &= ~ADC_SC3_ADCO_MASK; // single conversion mode ADC0_SC2 &= ~ADC_SC2_ADTRG_MASK; // set ADC to software trigger ADC1_SC2 &= ~ADC_SC2_ADTRG_MASK; // set ADC to software trigger ADC0_SC1B |= ADC_SC1_ADCH(13); // write to SC1B causing a trigger ADC1_SC1A |= ADC_SC1_ADCH(14); // write to SC1A causing a trigger // Set back to hardware trigger ADC0_SC2 |= ADC_SC2_ADTRG_MASK; // set ADC to software trigger ADC1_SC2 |= ADC_SC2_ADTRG_MASK; // set ADC to software trigger } void adc_print_registers() { Serial debug(USBTX,USBRX); debug.printf("ADC0_SC1a: %08x\r\n",ADC0_SC1A); //(0x0000004d) debug.printf("ADC0_SC1b: %08x\r\n",ADC0_SC1B); //(0x0000001f) debug.printf("ADC0_CFG1: %08x\r\n",ADC0_CFG1); //(0x0000000c) debug.printf("ADC0_CFG2: %08x\r\n",ADC0_CFG2); //(0x00000004) debug.printf("ADC0_RA: %08x\r\n",ADC0_RA); //(0x00000000) debug.printf("ADC0_RB: %08x\r\n",ADC0_RB); //(0x00000000) debug.printf("ADC0_SC2: %08x\r\n",ADC0_SC2); //(0x00000044) debug.printf("ADC0_SC3: %08x\r\n\n",ADC0_SC3); //(0x00000000) }