Jared's DAC Code

Dependencies:   mbed

Dependents:   DCS_FINAL_CODE

Fork of Chemical_Sensor_DMA by Jared Baxter

Revision:
2:3771b3195c7b
Child:
4:9fd291254686
diff -r f0a5690db73f -r 3771b3195c7b Sample/adc.cpp
--- /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