Jared's DAC Code
Dependencies: mbed
Fork of Chemical_Sensor_DMA by
Diff: Sample/adc.cpp
- Revision:
- 2:3771b3195c7b
- Child:
- 4:9fd291254686
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Sample/adc.cpp Thu Oct 29 17:15:20 2015 +0000 @@ -0,0 +1,221 @@ +#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 + __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 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(13); // 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; +} + + + + + + + + + + + + +/* * * * * * * * * * * * * * 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) +} \ No newline at end of file