diff --git a/adc/adc.ino b/adc/adc.ino index a7485445e5ff63e6ce4a914e4a9e8cc21ddb7823..f801821389a7952f89054a1d8967d4ade0034640 100644 --- a/adc/adc.ino +++ b/adc/adc.ino @@ -23,32 +23,74 @@ static inline uint32_t mapResolution(uint32_t value, uint32_t from, uint32_t to) return value << (to-from); } +/* ---------------------------------------------------------------------------------------------- + * Initialize Analog Controller + */ +void bm_initADC(void) { + // Load ADC factory calibration values + #if !defined(DISABLE_ADC_CALIBRATION) + // ADC Bias Calibration + uint32_t bias = (*((uint32_t *) ADC_FUSES_BIASCAL_ADDR) & ADC_FUSES_BIASCAL_Msk) >> ADC_FUSES_BIASCAL_Pos; + + // ADC Linearity bits 4:0 + uint32_t linearity = (*((uint32_t *) ADC_FUSES_LINEARITY_0_ADDR) & ADC_FUSES_LINEARITY_0_Msk) >> ADC_FUSES_LINEARITY_0_Pos; + + // ADC Linearity bits 7:5 + linearity |= ((*((uint32_t *) ADC_FUSES_LINEARITY_1_ADDR) & ADC_FUSES_LINEARITY_1_Msk) >> ADC_FUSES_LINEARITY_1_Pos) << 5; + + ADC->CALIB.reg = ADC_CALIB_BIAS_CAL(bias) | ADC_CALIB_LINEARITY_CAL(linearity); + + syncADC(); // Wait for synchronization of registers between the clock domains + #endif + + // Setting clock, prescaler and resolution + GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID( GCM_ADC ) | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_CLKEN ; + while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY ); + + ADC->CTRLB.reg = ADC_CTRLB_PRESCALER_DIV512 | // Divide Clock by 512. + ADC_CTRLB_RESSEL_10BIT; // 10 bits resolution as default + syncADC(); // Wait for synchronization of registers between the clock domains + + // Setting configuration + ADC->SAMPCTRL.reg = 0x3f; // Set max Sampling Time Length + syncADC(); // Wait for synchronization of registers between the clock domains + + ADC->INPUTCTRL.reg = ADC_INPUTCTRL_MUXNEG_GND; // No Negative input (Internal Ground) + syncADC(); // Wait for synchronization of registers between the clock domains + + // Averaging (see datasheet table in AVGCTRL register description) + ADC->AVGCTRL.reg = ADC_AVGCTRL_SAMPLENUM_1 | // 1 sample only (no oversampling nor averaging) + ADC_AVGCTRL_ADJRES(0x0ul); // Adjusting result by 0 + syncADC(); // Wait for synchronization of registers between the clock domains + + analogReference( VARIANT_AR_DEFAULT ) ; // Use default reference from variant.h +} + void init_pin_adc(uint32_t pin) { uint8_t const pinPort = GetPort(pin); uint8_t const pinNum = GetPin(pin); - // Preserve state of pullup/pulldown enable, clear the rest of the bits - uint8_t pinCfg = (PORT->Group[pinPort].PINCFG[pinNum].reg & PORT_PINCFG_PULLEN); - if ( pinNum & 1 ) // is pin odd? { // Get whole current setup for both odd and even pins and remove odd one, then set new muxing uint32_t temp = (PORT->Group[pinPort].PMUX[pinNum >> 1].reg) & PORT_PMUX_PMUXE( 0xF ) ; - PORT->Group[pinPort].PMUX[pinNum >> 1].reg = temp|PORT_PMUX_PMUXO(PER_ANALOG) ; + PORT->Group[pinPort].PMUX[pinNum >> 1].reg = temp | PORT_PMUX_PMUXO(PER_ANALOG) ; } else // even pin { // Get whole current setup for both odd and even pins and remove even one, then set new muxing uint32_t temp = (PORT->Group[pinPort].PMUX[pinNum >> 1].reg) & PORT_PMUX_PMUXO( 0xF ) ; - PORT->Group[pinPort].PMUX[pinNum >> 1].reg = temp|PORT_PMUX_PMUXE(PER_ANALOG) ; + PORT->Group[pinPort].PMUX[pinNum >> 1].reg = temp | PORT_PMUX_PMUXE(PER_ANALOG) ; } + // Set pin drive strength to normal, leave the input pullup setting alone, clear INEN, and + // enable peripheral mux. + uint8_t pinCfg = (PORT->Group[pinPort].PINCFG[pinNum].reg & PORT_PINCFG_PULLEN); pinCfg |= PORT_PINCFG_PMUXEN; // Enable peripheral mux - - // Set pin drive strength, enable/disable pull resistor, enable/disable INEN, and enable/disable the peripheral mux PORT->Group[pinPort].PINCFG[pinNum].reg = (uint8_t)pinCfg ; } + uint32_t bm_analogRead( uint32_t pin ) { uint32_t valueRead = 0; @@ -72,7 +114,7 @@ void setup() { digitalWrite(CHARGE_LINE_0, LOW); // Initialize the ADC - initADC(); + bm_initADC(); // Everything seems to function if I don't do this, but I'm leaving it in until I have a chance // to investigate what's happening.