/* Set the number of averages: 0, 4, 8, 16 or 32. * */ void ADC_Module::setAveraging(uint8_t num) { if (calibrating) wait_for_cal(); if (num <= 1) { num = 0; //*ADC_SC3 &= ~ADC_SC3_AVGE; *ADC_SC3_avge = 0; } else { *ADC_SC3_avge = 1; if (num <= 4) { num = 4; //*ADC_SC3 |= ADC_SC3_AVGE + ADC_SC3_AVGS(0); *ADC_SC3_avgs0 = 0; *ADC_SC3_avgs1 = 0; } else if (num <= 8) { num = 8; //*ADC_SC3 |= ADC_SC3_AVGE + ADC_SC3_AVGS(1); *ADC_SC3_avgs0 = 1; *ADC_SC3_avgs1 = 0; } else if (num <= 16) { num = 16; //*ADC_SC3 |= ADC_SC3_AVGE + ADC_SC3_AVGS(2); *ADC_SC3_avgs0 = 0; *ADC_SC3_avgs1 = 1; } else { num = 32; //*ADC_SC3 |= ADC_SC3_AVGE + ADC_SC3_AVGS(3); *ADC_SC3_avgs0 = 1; *ADC_SC3_avgs1 = 1; } } analog_num_average = num; }
/* Enable the compare function: A conversion will be completed only when the ADC value * is inside (insideRange=1) or outside (=0) the range given by (lowerLimit, upperLimit), * including (inclusive=1) the limits or not (inclusive=0). * See Table 31-78, p. 617 of the freescale manual. * Call it after changing the resolution */ void ADC_Module::enableCompareRange(int16_t lowerLimit, int16_t upperLimit, bool insideRange, bool inclusive) { if (calibrating) wait_for_cal(); // if we modify the adc's registers when calibrating, it will fail *ADC_SC2_cfe = 1; // enable compare *ADC_SC2_cren = 1; // enable compare range if(insideRange && inclusive) { // True if value is inside the range, including the limits. CV1 <= CV2 and ACFGT=1 //*ADC_SC2 |= ADC_SC2_ACFE | ADC_SC2_ACFGT | ADC_SC2_ACREN; *ADC_SC2_cfgt = 1; *ADC_CV1 = (int16_t)lowerLimit; *ADC_CV2 = (int16_t)upperLimit; } else if(insideRange && !inclusive) {// True if value is inside the range, excluding the limits. CV1 > CV2 and ACFGT=0 //*ADC_SC2 |= ADC_SC2_ACFE | ADC_SC2_ACREN; *ADC_SC2_cfgt = 0; *ADC_CV2 = (int16_t)lowerLimit; *ADC_CV1 = (int16_t)upperLimit; } else if(!insideRange && inclusive) { // True if value is outside of range or is equal to either limit. CV1 > CV2 and ACFGT=1 //*ADC_SC2 |= ADC_SC2_ACFE | ADC_SC2_ACFGT | ADC_SC2_ACREN; *ADC_SC2_cfgt = 1; *ADC_CV2 = (int16_t)lowerLimit; *ADC_CV1 = (int16_t)upperLimit; } else if(!insideRange && !inclusive) { // True if value is outside of range and not equal to either limit. CV1 > CV2 and ACFGT=0 //*ADC_SC2 |= ADC_SC2_ACFE | ADC_SC2_ACREN; *ADC_SC2_cfgt = 0; *ADC_CV1 = (int16_t)lowerLimit; *ADC_CV2 = (int16_t)upperLimit; } }
/* Enable DMA request: An ADC DMA request will be raised when the conversion is completed * (including hardware averages and if the comparison (if any) is true). */ void ADC_Module::enableDMA() { if (calibrating) wait_for_cal(); //*ADC_SC2 |= ADC_SC2_DMAEN; *ADC_SC2_dma = 1; }
/* Starts continuous and differential conversion between the pins (pinP-pinN) * It returns as soon as the ADC is set, use analogReadContinuous() to read the value * Set the resolution, number of averages and voltage reference using the appropriate functions BEFORE calling this function */ bool ADC_Module::startContinuousDifferential(uint8_t pinP, uint8_t pinN) { if(!checkDifferentialPins(pinP, pinN)) { fail_flag |= ADC_ERROR_WRONG_PIN; return false; // all others are invalid } // increase the counter of measurements num_measurements++; // check for calibration before setting channels, // because conversion will start as soon as we write to *ADC_SC1A if (calibrating) wait_for_cal(); // save the current state of the ADC in case it's in use uint8_t wasADCInUse = isConverting(); // is the ADC running now? if(wasADCInUse) { // this means we're interrupting a conversion // save the current conversion config, we don't want any other interrupts messing up the configs __disable_irq(); saveConfig(&adc_config); __enable_irq(); } // set continuous mode continuousMode(); // start conversions startDifferentialFast(pinP, pinN); return true; }
/* Enables the PGA and sets the gain * Use only for signals lower than 1.2 V * \param gain can be 1, 2, 4, 8, 16 32 or 64 * */ void ADC_Module::enablePGA(uint8_t gain) { #if defined(__MK20DX256__) if (calibrating) wait_for_cal(); uint8_t setting; if(gain <= 1) { setting = 0; } else if(gain<=2){ setting = 1; } else if(gain<=4){ setting = 2; } else if(gain<=8){ setting = 3; } else if(gain<=16){ setting = 4; } else if(gain<=32){ setting = 5; } else { // 64 setting = 6; } *ADC_PGA = ADC_PGA_PGAEN | ADC_PGA_PGAG(setting); pga_value=1<<setting; #endif }
/* Starts an analog measurement on the pin. * It returns inmediately, read value with readSingle(). * If the pin is incorrect it returns ADC_ERROR_VALUE. */ bool ADC_Module::startSingleRead(uint8_t pin) { // check whether the pin is correct if(!checkPin(pin)) { fail_flag |= ADC_ERROR_WRONG_PIN; return false; } if (calibrating) wait_for_cal(); // save the current state of the ADC in case it's in use adcWasInUse = isConverting(); // is the ADC running now? if(adcWasInUse) { // this means we're interrupting a conversion // save the current conversion config, the adc isr will restore the adc __disable_irq(); saveConfig(&adc_config); __enable_irq(); } // no continuous mode singleMode(); // start measurement startReadFast(pin); return true; }
/* Reads the differential analog value of two pins (pinP - pinN) * It waits until the value is read and then returns the result * If a comparison has been set up and fails, it will return ADC_ERROR_DIFF_VALUE * Set the resolution, number of averages and voltage reference using the appropriate functions */ int ADC_Module::analogReadDifferential(uint8_t pinP, uint8_t pinN) { int32_t result; if( ((pinP != A10) && (pinP != A12)) || ((pinN != A11) && (pinN != A13)) ) { fail_flag |= ADC_ERROR_WRONG_PIN; return ADC_ERROR_DIFF_VALUE; // all others are invalid } // increase the counter of measurements num_measurements++; // check for calibration before setting channels, // because conversion will start as soon as we write to *ADC_SC1A if (calibrating) wait_for_cal(); uint8_t res = getResolution(); // vars to saved the current state of the ADC in case it's in use ADC_Config old_config = {0}; uint8_t wasADCInUse = isConverting(); // is the ADC running now? if(wasADCInUse) { // this means we're interrupting a conversion // save the current conversion config, we don't want any other interrupts messing up the configs __disable_irq(); //digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN) ); old_config.savedSC1A = *ADC_SC1A; old_config.savedCFG1 = *ADC_CFG1; old_config.savedCFG2 = *ADC_CFG2; old_config.savedSC2 = *ADC_SC2; old_config.savedSC3 = *ADC_SC3; __enable_irq(); } // no continuous mode *ADC_SC3_adco = 0; // once *ADC_SC1A is set, conversion will start, enable interrupts if requested if ( (pinP == A10) && (pinN == A11) ) { // pins 34 and 35 __disable_irq(); #if defined(__MK20DX256__) if ( *ADC_PGA & ADC_PGA_PGAEN ) { // PGA is enabled if(ADC_num == 0) { // PGA0 connects to A10-A11 *ADC_SC1A = ADC_SC1_DIFF + 0x2 + var_enableInterrupts*ADC_SC1_AIEN; __enable_irq(); } else { // If this is ADC1 we can't connect to PGA0 __enable_irq(); fail_flag |= ADC_ERROR_WRONG_ADC; num_measurements--; return ADC_ERROR_DIFF_VALUE; } } else { // no pga if(ADC_num == 0) { *ADC_SC1A = ADC_SC1_DIFF + 0x0 + var_enableInterrupts*ADC_SC1_AIEN; // In ADC0, A10-A11 is DAD0 __enable_irq(); } else if(ADC_num == 1) { *ADC_SC1A = ADC_SC1_DIFF + 0x3 + var_enableInterrupts*ADC_SC1_AIEN; // In ADC1, A10-A11 is DAD3 __enable_irq() } }
int analogRead(uint8_t pin) { int result; if (pin >= 14) { if (pin <= 23) { pin -= 14; // 14-23 are A0-A9 } else if (pin >= 34 && pin <= 39) { pin -= 24; // 34-37 are A10-A13, 38 is temp sensor, 39 is vref } else { return 0; // all others are invalid } } //serial_print("analogRead"); //return 0; if (calibrating) wait_for_cal(); //pin = 5; // PTD1/SE5b, pin 14, analog 0 ADC0_SC1A = channel2sc1a[pin]; while ((ADC0_SC1A & ADC_SC1_COCO) == 0) { // wait //serial_print("."); } //serial_print("\n"); result = ADC0_RA >> analog_right_shift; //serial_phex16(result >> 3); //serial_print("\n"); return result; }
void analogReadAveraging(unsigned int num) { if (calibrating) wait_for_cal(); if (num <= 1) { num = 0; ADC0_SC3 = 0; } else if (num <= 4) { num = 4; ADC0_SC3 = ADC_SC3_AVGE + ADC_SC3_AVGS(0); #ifdef HAS_KINETIS_ADC1 ADC1_SC3 = ADC_SC3_AVGE + ADC_SC3_AVGS(0); #endif } else if (num <= 8) { num = 8; ADC0_SC3 = ADC_SC3_AVGE + ADC_SC3_AVGS(1); #ifdef HAS_KINETIS_ADC1 ADC1_SC3 = ADC_SC3_AVGE + ADC_SC3_AVGS(1); #endif } else if (num <= 16) { num = 16; ADC0_SC3 = ADC_SC3_AVGE + ADC_SC3_AVGS(2); #ifdef HAS_KINETIS_ADC1 ADC1_SC3 = ADC_SC3_AVGE + ADC_SC3_AVGS(2); #endif } else { num = 32; ADC0_SC3 = ADC_SC3_AVGE + ADC_SC3_AVGS(3); #ifdef HAS_KINETIS_ADC1 ADC1_SC3 = ADC_SC3_AVGE + ADC_SC3_AVGS(3); #endif } analog_num_average = num; }
/* Enable DMA request: An ADC DMA request will be raised when the conversion is completed * (including hardware averages and if the comparison (if any) is true). */ void ADC_Module::enableDMA() { if (calibrating) wait_for_cal(); // *ADC_SC2_dma = 1; setBit(ADC_SC2, ADC_SC2_DMAEN_BIT); }
/* Enable the compare function: A conversion will be completed only when the ADC value * is >= compValue (greaterThan=1) or < compValue (greaterThan=0) * Call it after changing the resolution * Use with interrupts or poll conversion completion with isADC_Complete() */ void ADC_Module::enableCompare(int16_t compValue, bool greaterThan) { if (calibrating) wait_for_cal(); // if we modify the adc's registers when calibrating, it will fail //*ADC_SC2 |= ADC_SC2_ACFE | greaterThan*ADC_SC2_ACFGT; *ADC_SC2_cfe = 1; // enable compare *ADC_SC2_cfgt = (int32_t)greaterThan; // greater or less than? *ADC_CV1 = (int16_t)compValue; // comp value }
/* Enable interrupts: An ADC Interrupt will be raised when the conversion is completed * (including hardware averages and if the comparison (if any) is true). */ void ADC_Module::enableInterrupts() { if (calibrating) wait_for_cal(); var_enableInterrupts = 1; // *ADC_SC1A_aien = 1; setBit(ADC_SC1A, ADC_SC1A_AIEN_BIT); NVIC_ENABLE_IRQ(IRQ_ADC); }
/* Increase the sampling speed for low impedance sources, decrease it for higher impedance ones. * \param speed can be ADC_VERY_LOW_SPEED, ADC_LOW_SPEED, ADC_MED_SPEED, ADC_HIGH_SPEED or ADC_VERY_HIGH_SPEED ADC_VERY_LOW_SPEED is the lowest possible sampling speed (+24 ADCK). ADC_LOW_SPEED adds +16 ADCK. ADC_MED_SPEED adds +10 ADCK. ADC_HIGH_SPEED (or ADC_HIGH_SPEED_16BITS) adds +6 ADCK. ADC_VERY_HIGH_SPEED is the highest possible sampling speed (0 ADCK added). * It doesn't recalibrate at the end. */ void ADC_Module::setSamplingSpeed(uint8_t speed) { if(speed==sampling_speed) { // no change return; } if (calibrating) wait_for_cal(); // Select between the settings if(speed == ADC_VERY_LOW_SPEED) { // *ADC_CFG1_adlsmp = 1; // long sampling time enable // *ADC_CFG2_adlsts1 = 0; // maximum sampling time (+24 ADCK) // *ADC_CFG2_adlsts0 = 0; setBit(ADC_CFG1, ADC_CFG1_ADLSMP_BIT); clearBit(ADC_CFG2, ADC_CFG2_ADLSTS1_BIT); clearBit(ADC_CFG2, ADC_CFG2_ADLSTS0_BIT); } else if(speed == ADC_LOW_SPEED) { // *ADC_CFG1_adlsmp = 1; // long sampling time enable // *ADC_CFG2_adlsts1 = 0;// high sampling time (+16 ADCK) // *ADC_CFG2_adlsts0 = 1; setBit(ADC_CFG1, ADC_CFG1_ADLSMP_BIT); clearBit(ADC_CFG2, ADC_CFG2_ADLSTS1_BIT); setBit(ADC_CFG2, ADC_CFG2_ADLSTS0_BIT); } else if(speed == ADC_MED_SPEED) { // *ADC_CFG1_adlsmp = 1; // long sampling time enable // *ADC_CFG2_adlsts1 = 1;// medium sampling time (+10 ADCK) // *ADC_CFG2_adlsts0 = 0; setBit(ADC_CFG1, ADC_CFG1_ADLSMP_BIT); setBit(ADC_CFG2, ADC_CFG2_ADLSTS1_BIT); clearBit(ADC_CFG2, ADC_CFG2_ADLSTS0_BIT); } else if( (speed == ADC_HIGH_SPEED) || (speed == ADC_HIGH_SPEED_16BITS) ) { // *ADC_CFG1_adlsmp = 1; // long sampling time enable // *ADC_CFG2_adlsts1 = 1;// low sampling time (+6 ADCK) // *ADC_CFG2_adlsts0 = 1; setBit(ADC_CFG1, ADC_CFG1_ADLSMP_BIT); setBit(ADC_CFG2, ADC_CFG2_ADLSTS1_BIT); setBit(ADC_CFG2, ADC_CFG2_ADLSTS0_BIT); } else if(speed == ADC_VERY_HIGH_SPEED) { // *ADC_CFG1_adlsmp = 0; // shortest sampling time clearBit(ADC_CFG1, ADC_CFG1_ADLSMP_BIT); } else { // incorrect speeds have no effect. return; } sampling_speed = speed; }
/* Change the resolution of the measurement * For single-ended measurements: 8, 10, 12 or 16 bits. * For differential measurements: 9, 11, 13 or 16 bits. * If you want something in between (11 bits single-ended for example) select the inmediate higher * and shift the result one to the right. * * It doesn't recalibrate */ void ADC_Module::setResolution(uint8_t bits) { if(analog_res_bits==bits) { return; } uint8_t config; if (calibrating) wait_for_cal(); if (bits <8) { config = 8; } else if (bits >= 14) { config = 16; } else { config = bits; } // conversion resolution // single-ended 8 bits is the same as differential 9 bits, etc. if ( (config == 8) || (config == 9) ) { // *ADC_CFG1_mode1 = 0; // *ADC_CFG1_mode0 = 0; clearBit(ADC_CFG1, ADC_CFG1_MODE1_BIT); clearBit(ADC_CFG1, ADC_CFG1_MODE0_BIT); analog_max_val = 255; // diff mode 9 bits has 1 bit for sign, so max value is the same as single 8 bits } else if ( (config == 10 )|| (config == 11) ) { // *ADC_CFG1_mode1 = 1; // *ADC_CFG1_mode0 = 0; setBit(ADC_CFG1, ADC_CFG1_MODE1_BIT); clearBit(ADC_CFG1, ADC_CFG1_MODE0_BIT); analog_max_val = 1023; } else if ( (config == 12 )|| (config == 13) ) { // *ADC_CFG1_mode1 = 0; // *ADC_CFG1_mode0 = 1; clearBit(ADC_CFG1, ADC_CFG1_MODE1_BIT); setBit(ADC_CFG1, ADC_CFG1_MODE0_BIT); analog_max_val = 4095; } else { // *ADC_CFG1_mode1 = 1; // *ADC_CFG1_mode0 = 1; setBit(ADC_CFG1, ADC_CFG1_MODE1_BIT); setBit(ADC_CFG1, ADC_CFG1_MODE0_BIT); analog_max_val = 65535; } analog_res_bits = config; // no recalibration is needed when changing the resolution, p. 619 }
int analogRead(uint8_t pin) { int result; uint8_t channel; //serial_phex(pin); //serial_print(" "); if (pin >= sizeof(pin2sc1a)) return 0; channel = pin2sc1a[pin]; if (channel == 255) return 0; if (calibrating) wait_for_cal(); #ifdef HAS_KINETIS_ADC1 if (channel & 0x80) goto beginADC1; #endif __disable_irq(); startADC0: //serial_print("startADC0\n"); #if defined(__MKL26Z64__) if (channel & 0x40) { ADC0_CFG2 &= ~ADC_CFG2_MUXSEL; channel &= 0x3F; } else { ADC0_CFG2 |= ADC_CFG2_MUXSEL; } #endif ADC0_SC1A = channel; analogReadBusyADC0 = 1; __enable_irq(); while (1) { __disable_irq(); if ((ADC0_SC1A & ADC_SC1_COCO)) { result = ADC0_RA; analogReadBusyADC0 = 0; __enable_irq(); result >>= analog_right_shift; return result; } // detect if analogRead was used from an interrupt // if so, our analogRead got canceled, so it must // be restarted. if (!analogReadBusyADC0) goto startADC0; __enable_irq(); yield(); }
/* Enable interrupts: An ADC Interrupt will be raised when the conversion is completed * (including hardware averages and if the comparison (if any) is true). */ void ADC_Module::enableInterrupts() { if (calibrating) wait_for_cal(); var_enableInterrupts = 1; *ADC_SC1A_aien = 1; #if defined(__MK20DX128__) NVIC_ENABLE_IRQ(IRQ_ADC0); #elif defined(__MK20DX256__) if(ADC_num==1) { // enable correct interrupt NVIC_ENABLE_IRQ(IRQ_ADC1); } else { NVIC_ENABLE_IRQ(IRQ_ADC0); } #endif // defined }
/* Starts continuous conversion on the pin * It returns as soon as the ADC is set, use analogReadContinuous() to read the values * Set the resolution, number of averages and voltage reference using the appropriate functions BEFORE calling this function */ bool ADC_Module::startContinuous(uint8_t pin) { // check whether the pin is correct if(!checkPin(pin)) { fail_flag |= ADC_ERROR_WRONG_PIN; return false; } // check for calibration before setting channels, if (calibrating) wait_for_cal(); // increase the counter of measurements num_measurements++; // set continuous conversion flag continuousMode(); startReadFast(pin); return true; }
/* Set the number of averages: 0, 4, 8, 16 or 32. * */ void ADC_Module::setAveraging(uint8_t num) { if (calibrating) wait_for_cal(); if (num <= 1) { num = 0; // *ADC_SC3_avge = 0; clearBit(ADC_SC3, ADC_SC3_AVGE_BIT); } else { // *ADC_SC3_avge = 1; setBit(ADC_SC3, ADC_SC3_AVGE_BIT); if (num <= 4) { num = 4; // *ADC_SC3_avgs0 = 0; // *ADC_SC3_avgs1 = 0; clearBit(ADC_SC3, ADC_SC3_AVGS0_BIT); clearBit(ADC_SC3, ADC_SC3_AVGS1_BIT); } else if (num <= 8) { num = 8; // *ADC_SC3_avgs0 = 1; // *ADC_SC3_avgs1 = 0; setBit(ADC_SC3, ADC_SC3_AVGS0_BIT); clearBit(ADC_SC3, ADC_SC3_AVGS1_BIT); } else if (num <= 16) { num = 16; // *ADC_SC3_avgs0 = 0; // *ADC_SC3_avgs1 = 1; clearBit(ADC_SC3, ADC_SC3_AVGS0_BIT); setBit(ADC_SC3, ADC_SC3_AVGS1_BIT); } else { num = 32; // *ADC_SC3_avgs0 = 1; // *ADC_SC3_avgs1 = 1; setBit(ADC_SC3, ADC_SC3_AVGS0_BIT); setBit(ADC_SC3, ADC_SC3_AVGS1_BIT); } } analog_num_average = num; }
/* Set the number of averages: 0, 4, 8, 16 or 32. * */ void ADC::setAveraging(uint8_t num) { if (calibrating) wait_for_cal(); if (num <= 1) { num = 0; ADC0_SC3 &= !ADC_SC3_AVGE; } else if (num <= 4) { num = 4; ADC0_SC3 |= ADC_SC3_AVGE + ADC_SC3_AVGS(0); } else if (num <= 8) { num = 8; ADC0_SC3 |= ADC_SC3_AVGE + ADC_SC3_AVGS(1); } else if (num <= 16) { num = 16; ADC0_SC3 |= ADC_SC3_AVGE + ADC_SC3_AVGS(2); } else { num = 32; ADC0_SC3 |= ADC_SC3_AVGE + ADC_SC3_AVGS(3); } analog_num_average = num; }
/* Increase the sampling speed for low impedance sources, decrease it for higher impedance ones. * \param speed can be ADC_VERY_LOW_SPEED, ADC_LOW_SPEED, ADC_MED_SPEED, ADC_HIGH_SPEED or ADC_VERY_HIGH_SPEED ADC_VERY_LOW_SPEED is the lowest possible sampling speed (+24 ADCK). ADC_LOW_SPEED adds +16 ADCK. ADC_MED_SPEED adds +10 ADCK. ADC_HIGH_SPEED (or ADC_HIGH_SPEED_16BITS) adds +6 ADCK. ADC_VERY_HIGH_SPEED is the highest possible sampling speed (0 ADCK added). * It doesn't recalibrate at the end. */ void ADC_Module::setSamplingSpeed(uint8_t speed) { if(speed==sampling_speed) { // no change return; } if (calibrating) wait_for_cal(); // Select between the settings if(speed == ADC_VERY_LOW_SPEED) { *ADC_CFG1_adlsmp = 1; // long sampling time enable *ADC_CFG2_adlsts1 = 0; // maximum sampling time (+24 ADCK) *ADC_CFG2_adlsts0 = 0; } else if(speed == ADC_LOW_SPEED) { *ADC_CFG1_adlsmp = 1; // long sampling time enable *ADC_CFG2_adlsts1 = 0;// high sampling time (+16 ADCK) *ADC_CFG2_adlsts0 = 1; } else if(speed == ADC_MED_SPEED) { *ADC_CFG1_adlsmp = 1; // long sampling time enable *ADC_CFG2_adlsts1 = 1;// medium sampling time (+10 ADCK) *ADC_CFG2_adlsts0 = 0; } else if( (speed == ADC_HIGH_SPEED) || (speed == ADC_HIGH_SPEED_16BITS) ) { *ADC_CFG1_adlsmp = 1; // long sampling time enable *ADC_CFG2_adlsts1 = 1;// low sampling time (+6 ADCK) *ADC_CFG2_adlsts0 = 1; } else if(speed == ADC_VERY_HIGH_SPEED) { *ADC_CFG1_adlsmp = 0; // shortest sampling time } sampling_speed = speed; }
/* Reads the analog value of the pin. * It waits until the value is read and then returns the result. * If a comparison has been set up and fails, it will return ADC_ERROR_VALUE. * Set the resolution, number of averages and voltage reference using the appropriate functions. */ int ADC_Module::analogRead(uint8_t pin) { //digitalWriteFast(LED_BUILTIN, HIGH); // check whether the pin is correct if(!checkPin(pin)) { fail_flag |= ADC_ERROR_WRONG_PIN; return ADC_ERROR_VALUE; } // increase the counter of measurements num_measurements++; //digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN)); if (calibrating) wait_for_cal(); //digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN)); // check if we are interrupting a measurement, store setting if so. // vars to save the current state of the ADC in case it's in use ADC_Config old_config = {0}; uint8_t wasADCInUse = isConverting(); // is the ADC running now? if(wasADCInUse) { // this means we're interrupting a conversion // save the current conversion config, we don't want any other interrupts messing up the configs __disable_irq(); //digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN) ); saveConfig(&old_config); __enable_irq(); } // no continuous mode singleMode(); startReadFast(pin); // start single read // wait for the ADC to finish while(isConverting()) { yield(); } // it's done, check if the comparison (if any) was true int32_t result; __disable_irq(); // make sure nothing interrupts this part if (isComplete()) { // conversion succeded result = (uint16_t)*ADC_RA; } else { // comparison was false fail_flag |= ADC_ERROR_COMPARISON; result = ADC_ERROR_VALUE; } __enable_irq(); // if we interrupted a conversion, set it again if (wasADCInUse) { //digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN) ); __disable_irq(); loadConfig(&old_config); __enable_irq(); } num_measurements--; return result; } // analogRead
void analogReference(uint8_t type) { if (calibrating) wait_for_cal(); // TODO: implement this }
int analogRead(uint8_t pin) { int result; uint8_t index, channel; //serial_phex(pin); //serial_print(" "); if (pin <= 13) { index = pin; // 0-13 refer to A0-A13 } else if (pin <= 23) { index = pin - 14; // 14-23 are A0-A9 #if defined(__MK20DX256__) } else if (pin >= 26 && pin <= 31) { index = pin - 9; // 26-31 are A15-A20 #endif } else if (pin >= 34 && pin <= 40) { index = pin - 24; // 34-37 are A10-A13, 38 is temp sensor, // 39 is vref, 40 is unused (A14 on Teensy 3.1) } else { return 0; // all others are invalid } //serial_phex(index); //serial_print(" "); channel = channel2sc1a[index]; //serial_phex(channel); //serial_print(" "); //serial_print("analogRead"); //return 0; if (calibrating) wait_for_cal(); //pin = 5; // PTD1/SE5b, pin 14, analog 0 #if defined(__MK20DX256__) if (channel & 0x80) goto beginADC1; #endif __disable_irq(); startADC0: //serial_print("startADC0\n"); ADC0_SC1A = channel; analogReadBusyADC0 = 1; __enable_irq(); while (1) { __disable_irq(); if ((ADC0_SC1A & ADC_SC1_COCO)) { result = ADC0_RA; analogReadBusyADC0 = 0; __enable_irq(); result >>= analog_right_shift; return result; } // detect if analogRead was used from an interrupt // if so, our analogRead got canceled, so it must // be restarted. if (!analogReadBusyADC0) goto startADC0; __enable_irq(); //yield(); }
/* Reads the analog value of the pin. * It waits until the value is read and then returns the result. * If a comparison has been set up and fails, it will return ADC_ERROR_VALUE. * Set the resolution, number of averages and voltage reference using the appropriate functions. */ int ADC_Module::analogRead(uint8_t pin) { int32_t result; if ( (pin < 0) || (pin > 43) ) { fail_flag |= ADC_ERROR_WRONG_PIN; return ADC_ERROR_VALUE; // all others are invalid } // increase the counter of measurements num_measurements++; if (calibrating) wait_for_cal(); // check if we are interrupting a measurement, store setting if so. // vars to save the current state of the ADC in case it's in use ADC_Config old_config = {0}; uint8_t wasADCInUse = isConverting(); // is the ADC running now? if(wasADCInUse) { // this means we're interrupting a conversion // save the current conversion config, we don't want any other interrupts messing up the configs __disable_irq(); //digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN) ); old_config.savedSC1A = *ADC_SC1A; old_config.savedCFG1 = *ADC_CFG1; old_config.savedCFG2 = *ADC_CFG2; old_config.savedSC2 = *ADC_SC2; old_config.savedSC3 = *ADC_SC3; __enable_irq(); } #if defined(__MK20DX256__) // ADC1 has A15=5a and A20=4a so we have to change the mux to read the "a" channels if( (ADC_num==1) && ( (pin==26) || (pin==31) ) ) { // mux a //*ADC_CFG2 &= ~ADC_CFG2_MUXSEL; *ADC_CFG2_muxsel = 0; } else { // mux b //*ADC_CFG2 |= ADC_CFG2_MUXSEL; *ADC_CFG2_muxsel = 1; } #endif // no continuous mode *ADC_SC3_adco = 0; __disable_irq(); *ADC_SC1A = channel2sc1a[pin] + var_enableInterrupts*ADC_SC1_AIEN; // start conversion on pin and with interrupts enabled if requested __enable_irq(); // wait for the ADC to finish while(isConverting()) { yield(); //digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN) ); } // it's done, check if the comparison (if any) was true __disable_irq(); // make sure nothing interrupts this part if (isComplete()) { // conversion succeded result = (uint16_t)*ADC_RA; } else { // comparison was false fail_flag |= ADC_ERROR_COMPARISON; result = ADC_ERROR_VALUE; } __enable_irq(); // if we interrupted a conversion, set it again if (wasADCInUse) { //digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN) ); *ADC_CFG1 = old_config.savedCFG1; *ADC_CFG2 = old_config.savedCFG2; *ADC_SC2 = old_config.savedSC2; *ADC_SC3 = old_config.savedSC3; *ADC_SC1A = old_config.savedSC1A; } num_measurements--; return result; } // analogRead
/* Reads the differential analog value of two pins (pinP - pinN) * It waits until the value is read and then returns the result * If a comparison has been set up and fails, it will return ADC_ERROR_DIFF_VALUE * Set the resolution, number of averages and voltage reference using the appropriate functions */ int ADC_Module::analogReadDifferential(uint8_t pinP, uint8_t pinN) { if(!checkDifferentialPins(pinP, pinN)) { fail_flag |= ADC_ERROR_WRONG_PIN; return ADC_ERROR_VALUE; // all others are invalid } // increase the counter of measurements num_measurements++; // check for calibration before setting channels, // because conversion will start as soon as we write to *ADC_SC1A if (calibrating) wait_for_cal(); uint8_t res = getResolution(); // vars to saved the current state of the ADC in case it's in use ADC_Config old_config = {0}; uint8_t wasADCInUse = isConverting(); // is the ADC running now? if(wasADCInUse) { // this means we're interrupting a conversion // save the current conversion config, we don't want any other interrupts messing up the configs __disable_irq(); saveConfig(&old_config); __enable_irq(); } // no continuous mode singleMode(); startDifferentialFast(pinP, pinN); // start conversion // wait for the ADC to finish while( isConverting() ) { yield(); //digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN) ); } // it's done, check if the comparison (if any) was true int32_t result; __disable_irq(); // make sure nothing interrupts this part if (isComplete()) { // conversion succeded result = (int16_t)(int32_t)(*ADC_RA); // cast to 32 bits if(res==16) { // 16 bit differential is actually 15 bit + 1 bit sign result *= 2; // multiply by 2 as if it were really 16 bits, so that getMaxValue gives a correct value. } } else { // comparison was false result = ADC_ERROR_VALUE; fail_flag |= ADC_ERROR_COMPARISON; } __enable_irq(); // if we interrupted a conversion, set it again if (wasADCInUse) { __disable_irq(); loadConfig(&old_config); __enable_irq(); } num_measurements--; return result; } // analogReadDifferential
/* * \param speed can be ADC_VERY_LOW_SPEED, ADC_LOW_SPEED, ADC_MED_SPEED, ADC_HIGH_SPEED_16BITS, ADC_HIGH_SPEED or ADC_VERY_HIGH_SPEED ADC_VERY_LOW_SPEED is guaranteed to be the lowest possible speed within specs for resolutions less than 16 bits (higher than 1 MHz), it's different from ADC_LOW_SPEED only for 24, 4 or 2 MHz. ADC_LOW_SPEED is guaranteed to be the lowest possible speed within specs for all resolutions (higher than 2 MHz). ADC_MED_SPEED is always >= ADC_LOW_SPEED and <= ADC_HIGH_SPEED. ADC_HIGH_SPEED_16BITS is guaranteed to be the highest possible speed within specs for all resolutions (lower or eq than 12 MHz). ADC_HIGH_SPEED is guaranteed to be the highest possible speed within specs for resolutions less than 16 bits (lower or eq than 18 MHz). ADC_VERY_HIGH_SPEED may be out of specs, it's different from ADC_HIGH_SPEED only for 48, 40 or 24 MHz. * It doesn't recalibrate at the end. */ void ADC_Module::setConversionSpeed(uint8_t speed) { if(speed==conversion_speed) { // no change return; } if (calibrating) wait_for_cal(); // internal asynchronous clock settings: fADK = 2.4, 4.0, 5.2 or 6.2 MHz if(speed >= ADC_ADACK_2_4) { setBit(ADC_CFG2, ADC_CFG2_ADACKEN_BIT); // enable ADACK (takes max 5us to be ready) setBit(ADC_CFG1, ADC_CFG1_ADICLK1_BIT); // select ADACK as clock source setBit(ADC_CFG1, ADC_CFG1_ADICLK0_BIT); clearBit(ADC_CFG1, ADC_CFG1_ADIV0_BIT); // select divider 1 clearBit(ADC_CFG1, ADC_CFG1_ADIV1_BIT); // we could divide this clk, but it would be too small for ADC use. if(speed == ADC_ADACK_2_4) { clearBit(ADC_CFG2, ADC_CFG2_ADHSC_BIT); setBit(ADC_CFG1, ADC_CFG1_ADLPC_BIT); } else if(speed == ADC_ADACK_4_0) { setBit(ADC_CFG2, ADC_CFG2_ADHSC_BIT); setBit(ADC_CFG1, ADC_CFG1_ADLPC_BIT); } else if(speed == ADC_ADACK_5_2) { clearBit(ADC_CFG2, ADC_CFG2_ADHSC_BIT); clearBit(ADC_CFG1, ADC_CFG1_ADLPC_BIT); } else if(speed == ADC_ADACK_6_2) { setBit(ADC_CFG2, ADC_CFG2_ADHSC_BIT); clearBit(ADC_CFG1, ADC_CFG1_ADLPC_BIT); } conversion_speed = speed; return; } // normal bus clock used // *ADC_CFG2_adacken = 0; // disable the internal asynchronous clock clearBit(ADC_CFG2, ADC_CFG2_ADACKEN_BIT); uint32_t ADC_CFG1_speed; // store the clock and divisor if(speed == ADC_VERY_LOW_SPEED) { // *ADC_CFG2_adhsc = 0; // no high-speed config // *ADC_CFG1_adlpc = 1; // use low power conf. clearBit(ADC_CFG2, ADC_CFG2_ADHSC_BIT); setBit(ADC_CFG1, ADC_CFG1_ADLPC_BIT); ADC_CFG1_speed = ADC_CFG1_VERY_LOW_SPEED; } else if(speed == ADC_LOW_SPEED) { // *ADC_CFG2_adhsc = 0; // no high-speed config // *ADC_CFG1_adlpc = 1; // use low power conf. clearBit(ADC_CFG2, ADC_CFG2_ADHSC_BIT); setBit(ADC_CFG1, ADC_CFG1_ADLPC_BIT); ADC_CFG1_speed = ADC_CFG1_LOW_SPEED; } else if(speed == ADC_MED_SPEED) { // *ADC_CFG2_adhsc = 0; // no high-speed config // *ADC_CFG1_adlpc = 0; // no low power conf. clearBit(ADC_CFG2, ADC_CFG2_ADHSC_BIT); clearBit(ADC_CFG1, ADC_CFG1_ADLPC_BIT); ADC_CFG1_speed = ADC_CFG1_MED_SPEED; } else if(speed == ADC_HIGH_SPEED_16BITS) { // *ADC_CFG2_adhsc = 1; // high-speed config: add 2 ADCK // *ADC_CFG1_adlpc = 0; // no low power conf. setBit(ADC_CFG2, ADC_CFG2_ADHSC_BIT); clearBit(ADC_CFG1, ADC_CFG1_ADLPC_BIT); ADC_CFG1_speed = ADC_CFG1_HI_SPEED_16_BITS; } else if(speed == ADC_HIGH_SPEED) { // *ADC_CFG2_adhsc = 1; // high-speed config: add 2 ADCK // *ADC_CFG1_adlpc = 0; // no low power conf. setBit(ADC_CFG2, ADC_CFG2_ADHSC_BIT); clearBit(ADC_CFG1, ADC_CFG1_ADLPC_BIT); ADC_CFG1_speed = ADC_CFG1_HI_SPEED; } else if(speed == ADC_VERY_HIGH_SPEED) { // this speed is most likely out of specs, so accurancy can be bad // *ADC_CFG2_adhsc = 1; // high-speed config: add 2 ADCK // *ADC_CFG1_adlpc = 0; // no low power conf. setBit(ADC_CFG2, ADC_CFG2_ADHSC_BIT); clearBit(ADC_CFG1, ADC_CFG1_ADLPC_BIT); ADC_CFG1_speed = ADC_CFG1_VERY_HIGH_SPEED; } else { fail_flag |= ADC_ERROR_OTHER; return; } // clock source is bus or bus/2 // *ADC_CFG1_adiclk1 = !!(ADC_CFG1_speed & ADC_CFG1_ADICLK_MASK_1); // !!x converts the number x to either 0 or 1. // *ADC_CFG1_adiclk0 = !!(ADC_CFG1_speed & ADC_CFG1_ADICLK_MASK_0); changeBit(ADC_CFG1, ADC_CFG1_ADICLK1_BIT, !!(ADC_CFG1_speed & ADC_CFG1_ADICLK_MASK_1)); changeBit(ADC_CFG1, ADC_CFG1_ADICLK0_BIT, !!(ADC_CFG1_speed & ADC_CFG1_ADICLK_MASK_0)); // divisor for the clock source: 1, 2, 4 or 8. // so total speed can be: bus, bus/2, bus/4, bus/8 or bus/16. // *ADC_CFG1_adiv1 = !!(ADC_CFG1_speed & ADC_CFG1_ADIV_MASK_1); // *ADC_CFG1_adiv0 = !!(ADC_CFG1_speed & ADC_CFG1_ADIV_MASK_0); changeBit(ADC_CFG1, ADC_CFG1_ADIV1_BIT, !!(ADC_CFG1_speed & ADC_CFG1_ADIV_MASK_1)); changeBit(ADC_CFG1, ADC_CFG1_ADIV0_BIT, !!(ADC_CFG1_speed & ADC_CFG1_ADIV_MASK_0)); conversion_speed = speed; }
/* Reads the analog value of the pin. * It waits until the value is read and then returns the result. * If a comparison has been set up and fails, it will return -1. * Set the resolution, number of averages and voltage reference using the appropriate functions. */ int ADC::analogRead(uint8_t pin) { uint16_t result; if (pin >= 14 && pin <= 39) { if (pin <= 23) { pin -= 14; // 14-23 are A0-A9 } else if (pin >= 34) { pin -= 24; // 34-37 are A10-A13, 38 is temp sensor, 39 is vref } } else { return ADC_ERROR_VALUE; // all others are invalid } if (calibrating) wait_for_cal(); uint8_t res = getResolution(); uint8_t diffRes = 0; // is the new resolution different from the old one? // vars to save the current state of the ADC in case it's in use uint32_t savedSC1A, savedSC2, savedSC3, savedCFG1, savedCFG2, savedRes; uint8_t wasADCInUse = isConverting(); // is the ADC running now? if(wasADCInUse) { // this means we're interrupting a conversion // save the current conversion config, we don't want any other interrupts messing up the configs __disable_irq(); //GPIOC_PSOR = 1<<5; savedRes = res; savedSC1A = ADC0_SC1A; savedCFG1 = ADC0_CFG1; savedSC2 = ADC0_SC2; savedSC3 = ADC0_SC3; // change the comparison values if interrupting a 16 bits and diff mode if(res==16 && isDifferential()) { ADC0_CV1 /= 2; ADC0_CV2 /= 2; } // disable continuous mode in case analogRead is interrupting a continuous mode ADC0_SC3 &= !ADC_SC3_ADCO; __enable_irq(); ////keep irq disabled until we start our conversion } // if the resolution is incorrect (i.e. 9, 11 or 13) silently correct it if( (res==9) || (res==11) || (res==13) ) { setResolution(res-1); diffRes = 1; // resolution changed } __disable_irq(); ADC0_SC1A = channel2sc1a[pin] + var_enableInterrupts*ADC_SC1_AIEN; // start conversion on pin and with interrupts enabled if requested __enable_irq(); while (1) { __disable_irq(); if ((ADC0_SC1A & ADC_SC1_COCO)) { // conversion completed result = ADC0_RA; // if we interrupted a conversion, set it again if (wasADCInUse) { //GPIOC_PCOR = 1<<5; // restore ADC config, and restart conversion if(diffRes) setResolution(savedRes); // don't change res if isn't necessary if(res==16 && ((savedSC1A & ADC_SC1_DIFF) >> 5) ) { // change back the comparison values if interrupting a 16 bits and diff mode ADC0_CV1 *= 2; ADC0_CV2 *= 2; } ADC0_CFG1 = savedCFG1; ADC0_SC2 = savedSC2 & 0x7F; // restore first 8 bits ADC0_SC3 = savedSC3 & 0xF; // restore first 4 bits ADC0_SC1A = savedSC1A & 0x7F; // restore first 8 bits } __enable_irq(); return result; } else if( ((ADC0_SC2 & ADC_SC2_ADACT) == 0) && ((ADC0_SC1A & ADC_SC1_COCO) == 0) ) { // comparison was false
int analogRead(uint8_t pin) { int result; uint8_t index, channel; //serial_phex(pin); //serial_print(" "); #if defined(__MK20DX128__) if (pin <= 13) { index = pin; // 0-13 refer to A0-A13 } else if (pin <= 23) { index = pin - 14; // 14-23 are A0-A9 } else if (pin >= 34 && pin <= 40) { index = pin - 24; // 34-37 are A10-A13, 38 is temp sensor, // 39 is vref, 40 is unused analog pin } else { return 0; } #elif defined(__MK20DX256__) if (pin <= 13) { index = pin; // 0-13 refer to A0-A13 } else if (pin <= 23) { index = pin - 14; // 14-23 are A0-A9 } else if (pin >= 26 && pin <= 31) { index = pin - 9; // 26-31 are A15-A20 } else if (pin >= 34 && pin <= 40) { index = pin - 24; // 34-37 are A10-A13, 38 is temp sensor, // 39 is vref, 40 is A14 } else { return 0; } #elif defined(__MK64FX512__) || defined(__MK66FX1M0__) if (pin <= 13) { index = pin; // 0-13 refer to A0-A13 } else if (pin <= 23) { index = pin - 14; // 14-23 are A0-A9 } else if (pin >= 31 && pin <= 39) { index = pin - 19; // 31-39 are A12-A20 } else if (pin >= 40 && pin <= 41) { index = pin - 30; // 40-41 are A10-A11 } else if (pin >= 42 && pin <= 45) { index = pin - 21; // 42-43 are A21-A22, 44 is temp sensor, 45 is vref } else { return 0; } #elif defined(__MKL26Z64__) if (pin <= 12) { index = pin; // 0-12 refer to A0-A12 } else if (pin >= 14 && pin <= 26) { index = pin - 14; // 14-26 are A0-A12 } else if (pin >= 38 && pin <= 39) { index = pin - 25; // 38=temperature // 39=bandgap ref (PMC_REGSC |= PMC_REGSC_BGBE) } else { return 0; } #endif //serial_phex(index); //serial_print(" "); channel = channel2sc1a[index]; //serial_phex(channel); //serial_print(" "); //serial_print("analogRead"); //return 0; if (calibrating) wait_for_cal(); //pin = 5; // PTD1/SE5b, pin 14, analog 0 #ifdef HAS_KINETIS_ADC1 if (channel & 0x80) goto beginADC1; #endif __disable_irq(); startADC0: //serial_print("startADC0\n"); #if defined(__MKL26Z64__) if (channel & 0x40) { ADC0_CFG2 &= ~ADC_CFG2_MUXSEL; channel &= 0x3F; } else { ADC0_CFG2 |= ADC_CFG2_MUXSEL; } #endif ADC0_SC1A = channel; analogReadBusyADC0 = 1; __enable_irq(); while (1) { __disable_irq(); if ((ADC0_SC1A & ADC_SC1_COCO)) { result = ADC0_RA; analogReadBusyADC0 = 0; __enable_irq(); result >>= analog_right_shift; return result; } // detect if analogRead was used from an interrupt // if so, our analogRead got canceled, so it must // be restarted. if (!analogReadBusyADC0) goto startADC0; __enable_irq(); yield(); }
/** Usually it's not necessary to call this function directly, but do it if the "enviroment" changed * significantly since the program was started. */ void ADC_Module::recalibrate() { calibrate(); wait_for_cal(); }
/* * \param speed can be ADC_VERY_LOW_SPEED, ADC_LOW_SPEED, ADC_MED_SPEED, ADC_HIGH_SPEED_16BITS, ADC_HIGH_SPEED or ADC_VERY_HIGH_SPEED ADC_VERY_LOW_SPEED is guaranteed to be the lowest possible speed within specs for resolutions less than 16 bits (higher than 1 MHz), it's different from ADC_LOW_SPEED only for 24, 4 or 2 MHz. ADC_LOW_SPEED is guaranteed to be the lowest possible speed within specs for all resolutions (higher than 2 MHz). ADC_MED_SPEED is always >= ADC_LOW_SPEED and <= ADC_HIGH_SPEED. ADC_HIGH_SPEED_16BITS is guaranteed to be the highest possible speed within specs for all resolutions (lower or eq than 12 MHz). ADC_HIGH_SPEED is guaranteed to be the highest possible speed within specs for resolutions less than 16 bits (lower or eq than 18 MHz). ADC_VERY_HIGH_SPEED may be out of specs, it's different from ADC_HIGH_SPEED only for 48, 40 or 24 MHz. * It doesn't recalibrate at the end. */ void ADC_Module::setConversionSpeed(uint8_t speed) { if(speed==conversion_speed) { // no change return; } if (calibrating) wait_for_cal(); // in the future allow the user to select this clock source *ADC_CFG2_adacken = 0; // disable the internal asynchronous clock uint32_t ADC_CFG1_speed; // store the clock and divisor if(speed == ADC_VERY_LOW_SPEED) { *ADC_CFG2_adhsc = 0; // no high-speed config *ADC_CFG1_adlpc = 1; // use low power conf. ADC_CFG1_speed = ADC_CFG1_VERY_LOW_SPEED; } else if(speed == ADC_LOW_SPEED) { *ADC_CFG2_adhsc = 0; // no high-speed config *ADC_CFG1_adlpc = 1; // use low power conf. ADC_CFG1_speed = ADC_CFG1_LOW_SPEED; } else if(speed == ADC_MED_SPEED) { *ADC_CFG2_adhsc = 0; // no high-speed config *ADC_CFG1_adlpc = 0; // no low power conf. ADC_CFG1_speed = ADC_CFG1_MED_SPEED; } else if(speed == ADC_HIGH_SPEED_16BITS) { *ADC_CFG2_adhsc = 1; // high-speed config: add 2 ADCK *ADC_CFG1_adlpc = 0; // no low power conf. ADC_CFG1_speed = ADC_CFG1_HI_SPEED_16_BITS; } else if(speed == ADC_HIGH_SPEED) { *ADC_CFG2_adhsc = 1; // high-speed config: add 2 ADCK *ADC_CFG1_adlpc = 0; // no low power conf. ADC_CFG1_speed = ADC_CFG1_HI_SPEED; } else if(speed == ADC_VERY_HIGH_SPEED) { // this speed is most likely out of specs, so accurancy can be bad *ADC_CFG2_adhsc = 1; // high-speed config: add 2 ADCK *ADC_CFG1_adlpc = 0; // no low power conf. ADC_CFG1_speed = ADC_CFG1_VERY_HIGH_SPEED; } else { fail_flag |= ADC_ERROR_OTHER; return; } // clock source is bus or bus/2 *ADC_CFG1_adiclk1 = !!(ADC_CFG1_speed & ADC_CFG1_ADICLK_MASK_1); // !!x converts the number x to either 0 or 1. *ADC_CFG1_adiclk0 = !!(ADC_CFG1_speed & ADC_CFG1_ADICLK_MASK_0); // divisor for the clock source: 1, 2, 4 or 8. // so total speed can be: bus, bus/2, bus/4, bus/8 or bus/16. *ADC_CFG1_adiv1 = !!(ADC_CFG1_speed & ADC_CFG1_ADIV_MASK_1); *ADC_CFG1_adiv0 = !!(ADC_CFG1_speed & ADC_CFG1_ADIV_MASK_0); conversion_speed = speed; }