diff --git a/firmware/Peripherals.md b/firmware/Peripherals.md index e622ae4..9c8de1c 100644 --- a/firmware/Peripherals.md +++ b/firmware/Peripherals.md @@ -36,7 +36,7 @@ |[GPS_SERCOM]_IRQn|gps usart rx|1|latency not so critical. rate <= 960Hz |EIC_IRQn|timepulse|2|latency not so critical. rate = 1 |TC2_IRQn|xosc measurement done|2|latency not critical - +|ADC_IRQn|adc measurement done|2|latency not critical diff --git a/firmware/inc/adc/adc.h b/firmware/inc/adc/adc.h index ace250c..76ae77e 100644 --- a/firmware/inc/adc/adc.h +++ b/firmware/inc/adc/adc.h @@ -45,16 +45,14 @@ #define ADC_H_INCLUDED /** - * \defgroup asfdoc_sam0_adc_group SAM D20/D21/R21 Analog to Digital Converter Driver (ADC) + * SAM D20/D21/R21 Analog to Digital Converter Driver (ADC) * * This driver for SAM D20/D21/R21 devices provides an interface for the configuration * and management of the device's Analog to Digital Converter functionality, for * the conversion of analog voltages into a corresponding digital form. * The following driver API modes are covered by this manual: * - Polled APIs - * \if ADC_CALLBACK_MODE * - Callback APIs - * \endif * * The following peripherals are used by this module: * @@ -397,10 +395,6 @@ #include "system/pinmux.h" #define Assert assert -#if !defined(__DOXYGEN__) -extern struct adc_module *_adc_instances[ADC_INST_NUM]; -#endif - enum adc_status_code { ADC_STATUS_OK, ADC_STATUS_BUSY, @@ -410,10 +404,10 @@ enum adc_status_code { }; /** Forward definition of the device instance */ -struct adc_module; +struct adc_module module_inst; /** Type of the callback functions */ -typedef void (*adc_callback_t)(const struct adc_module *const module); +typedef void (*adc_callback_t)(void); /** * \brief ADC Callback enum @@ -422,15 +416,15 @@ typedef void (*adc_callback_t)(const struct adc_module *const module); * */ enum adc_callback { - /** Callback for buffer received */ - ADC_CALLBACK_READ_BUFFER, - /** Callback when window is hit */ - ADC_CALLBACK_WINDOW, - /** Callback for error */ - ADC_CALLBACK_ERROR, + /** Callback for buffer received */ + ADC_CALLBACK_READ_BUFFER, + /** Callback when window is hit */ + ADC_CALLBACK_WINDOW, + /** Callback for error */ + ADC_CALLBACK_ERROR, # if !defined(__DOXYGEN__) - /** Number of available callbacks. */ - ADC_CALLBACK_N, + /** Number of available callbacks. */ + ADC_CALLBACK_N, # endif }; @@ -459,16 +453,16 @@ enum adc_callback { * */ enum adc_reference { - /** 1.0V voltage reference */ - ADC_REFERENCE_INT1V = ADC_REFCTRL_REFSEL_INT1V, - /** 1/1.48 VCC reference */ - ADC_REFERENCE_INTVCC0 = ADC_REFCTRL_REFSEL_INTVCC0, - /** 1/2 VCC (only for internal Vcc > 2.1v) */ - ADC_REFERENCE_INTVCC1 = ADC_REFCTRL_REFSEL_INTVCC1, - /** External reference A */ - ADC_REFERENCE_AREFA = ADC_REFCTRL_REFSEL_AREFA, - /** External reference B */ - ADC_REFERENCE_AREFB = ADC_REFCTRL_REFSEL_AREFB, + /** 1.0V voltage reference */ + ADC_REFERENCE_INT1V = ADC_REFCTRL_REFSEL_INT1V, + /** 1/1.48 VCC reference */ + ADC_REFERENCE_INTVCC0 = ADC_REFCTRL_REFSEL_INTVCC0, + /** 1/2 VCC (only for internal Vcc > 2.1v) */ + ADC_REFERENCE_INTVCC1 = ADC_REFCTRL_REFSEL_INTVCC1, + /** External reference A */ + ADC_REFERENCE_AREFA = ADC_REFCTRL_REFSEL_AREFA, + /** External reference B */ + ADC_REFERENCE_AREFB = ADC_REFCTRL_REFSEL_AREFB, }; /** @@ -478,22 +472,22 @@ enum adc_reference { * */ enum adc_clock_prescaler { - /** ADC clock division factor 4 */ - ADC_CLOCK_PRESCALER_DIV4 = ADC_CTRLB_PRESCALER_DIV4, - /** ADC clock division factor 8 */ - ADC_CLOCK_PRESCALER_DIV8 = ADC_CTRLB_PRESCALER_DIV8, - /** ADC clock division factor 16 */ - ADC_CLOCK_PRESCALER_DIV16 = ADC_CTRLB_PRESCALER_DIV16, - /** ADC clock division factor 32 */ - ADC_CLOCK_PRESCALER_DIV32 = ADC_CTRLB_PRESCALER_DIV32, - /** ADC clock division factor 64 */ - ADC_CLOCK_PRESCALER_DIV64 = ADC_CTRLB_PRESCALER_DIV64, - /** ADC clock division factor 128 */ - ADC_CLOCK_PRESCALER_DIV128 = ADC_CTRLB_PRESCALER_DIV128, - /** ADC clock division factor 256 */ - ADC_CLOCK_PRESCALER_DIV256 = ADC_CTRLB_PRESCALER_DIV256, - /** ADC clock division factor 512 */ - ADC_CLOCK_PRESCALER_DIV512 = ADC_CTRLB_PRESCALER_DIV512, + /** ADC clock division factor 4 */ + ADC_CLOCK_PRESCALER_DIV4 = ADC_CTRLB_PRESCALER_DIV4, + /** ADC clock division factor 8 */ + ADC_CLOCK_PRESCALER_DIV8 = ADC_CTRLB_PRESCALER_DIV8, + /** ADC clock division factor 16 */ + ADC_CLOCK_PRESCALER_DIV16 = ADC_CTRLB_PRESCALER_DIV16, + /** ADC clock division factor 32 */ + ADC_CLOCK_PRESCALER_DIV32 = ADC_CTRLB_PRESCALER_DIV32, + /** ADC clock division factor 64 */ + ADC_CLOCK_PRESCALER_DIV64 = ADC_CTRLB_PRESCALER_DIV64, + /** ADC clock division factor 128 */ + ADC_CLOCK_PRESCALER_DIV128 = ADC_CTRLB_PRESCALER_DIV128, + /** ADC clock division factor 256 */ + ADC_CLOCK_PRESCALER_DIV256 = ADC_CTRLB_PRESCALER_DIV256, + /** ADC clock division factor 512 */ + ADC_CLOCK_PRESCALER_DIV512 = ADC_CTRLB_PRESCALER_DIV512, }; /** @@ -503,27 +497,27 @@ enum adc_clock_prescaler { * */ enum adc_resolution { - /** ADC 12-bit resolution */ - ADC_RESOLUTION_12BIT = ADC_CTRLB_RESSEL_12BIT, - /** ADC 16-bit resolution using oversampling and decimation */ - ADC_RESOLUTION_16BIT = ADC_CTRLB_RESSEL_16BIT, - /** ADC 10-bit resolution */ - ADC_RESOLUTION_10BIT = ADC_CTRLB_RESSEL_10BIT, - /** ADC 8-bit resolution */ - ADC_RESOLUTION_8BIT = ADC_CTRLB_RESSEL_8BIT, - /** ADC 13-bit resolution using oversampling and decimation */ - ADC_RESOLUTION_13BIT, - /** ADC 14-bit resolution using oversampling and decimation */ - ADC_RESOLUTION_14BIT, - /** ADC 15-bit resolution using oversampling and decimation */ - ADC_RESOLUTION_15BIT, - /** ADC 16-bit result register for use with averaging. When using this mode - * the ADC result register will be set to 16-bit wide, and the number of - * samples to accumulate and the division factor is configured by the - * \ref adc_config.accumulate_samples and \ref adc_config.divide_result - * members in the configuration struct - */ - ADC_RESOLUTION_CUSTOM, + /** ADC 12-bit resolution */ + ADC_RESOLUTION_12BIT = ADC_CTRLB_RESSEL_12BIT, + /** ADC 16-bit resolution using oversampling and decimation */ + ADC_RESOLUTION_16BIT = ADC_CTRLB_RESSEL_16BIT, + /** ADC 10-bit resolution */ + ADC_RESOLUTION_10BIT = ADC_CTRLB_RESSEL_10BIT, + /** ADC 8-bit resolution */ + ADC_RESOLUTION_8BIT = ADC_CTRLB_RESSEL_8BIT, + /** ADC 13-bit resolution using oversampling and decimation */ + ADC_RESOLUTION_13BIT, + /** ADC 14-bit resolution using oversampling and decimation */ + ADC_RESOLUTION_14BIT, + /** ADC 15-bit resolution using oversampling and decimation */ + ADC_RESOLUTION_15BIT, + /** ADC 16-bit result register for use with averaging. When using this mode + * the ADC result register will be set to 16-bit wide, and the number of + * samples to accumulate and the division factor is configured by the + * \ref adc_config.accumulate_samples and \ref adc_config.divide_result + * members in the configuration struct + */ + ADC_RESOLUTION_CUSTOM, }; /** @@ -533,16 +527,16 @@ enum adc_resolution { * */ enum adc_window_mode { - /** No window mode */ - ADC_WINDOW_MODE_DISABLE = ADC_WINCTRL_WINMODE_DISABLE, - /** RESULT > WINLT */ - ADC_WINDOW_MODE_ABOVE_LOWER = ADC_WINCTRL_WINMODE_MODE1, - /** RESULT < WINUT */ - ADC_WINDOW_MODE_BELOW_UPPER = ADC_WINCTRL_WINMODE_MODE2, - /** WINLT < RESULT < WINUT */ - ADC_WINDOW_MODE_BETWEEN = ADC_WINCTRL_WINMODE_MODE3, - /** !(WINLT < RESULT < WINUT) */ - ADC_WINDOW_MODE_BETWEEN_INVERTED = ADC_WINCTRL_WINMODE_MODE4, + /** No window mode */ + ADC_WINDOW_MODE_DISABLE = ADC_WINCTRL_WINMODE_DISABLE, + /** RESULT > WINLT */ + ADC_WINDOW_MODE_ABOVE_LOWER = ADC_WINCTRL_WINMODE_MODE1, + /** RESULT < WINUT */ + ADC_WINDOW_MODE_BELOW_UPPER = ADC_WINCTRL_WINMODE_MODE2, + /** WINLT < RESULT < WINUT */ + ADC_WINDOW_MODE_BETWEEN = ADC_WINCTRL_WINMODE_MODE3, + /** !(WINLT < RESULT < WINUT) */ + ADC_WINDOW_MODE_BETWEEN_INVERTED = ADC_WINCTRL_WINMODE_MODE4, }; /** @@ -552,18 +546,18 @@ enum adc_window_mode { * */ enum adc_gain_factor { - /** 1x gain */ - ADC_GAIN_FACTOR_1X = ADC_INPUTCTRL_GAIN_1X, - /** 2x gain */ - ADC_GAIN_FACTOR_2X = ADC_INPUTCTRL_GAIN_2X, - /** 4x gain */ - ADC_GAIN_FACTOR_4X = ADC_INPUTCTRL_GAIN_4X, - /** 8x gain */ - ADC_GAIN_FACTOR_8X = ADC_INPUTCTRL_GAIN_8X, - /** 16x gain */ - ADC_GAIN_FACTOR_16X = ADC_INPUTCTRL_GAIN_16X, - /** 1/2x gain */ - ADC_GAIN_FACTOR_DIV2 = ADC_INPUTCTRL_GAIN_DIV2, + /** 1x gain */ + ADC_GAIN_FACTOR_1X = ADC_INPUTCTRL_GAIN_1X, + /** 2x gain */ + ADC_GAIN_FACTOR_2X = ADC_INPUTCTRL_GAIN_2X, + /** 4x gain */ + ADC_GAIN_FACTOR_4X = ADC_INPUTCTRL_GAIN_4X, + /** 8x gain */ + ADC_GAIN_FACTOR_8X = ADC_INPUTCTRL_GAIN_8X, + /** 16x gain */ + ADC_GAIN_FACTOR_16X = ADC_INPUTCTRL_GAIN_16X, + /** 1/2x gain */ + ADC_GAIN_FACTOR_DIV2 = ADC_INPUTCTRL_GAIN_DIV2, }; /** @@ -573,12 +567,12 @@ enum adc_gain_factor { * */ enum adc_event_action { - /** Event action disabled */ - ADC_EVENT_ACTION_DISABLED = 0, - /** Flush ADC and start conversion */ - ADC_EVENT_ACTION_FLUSH_START_CONV = ADC_EVCTRL_SYNCEI, - /** Start conversion */ - ADC_EVENT_ACTION_START_CONV = ADC_EVCTRL_STARTEI, + /** Event action disabled */ + ADC_EVENT_ACTION_DISABLED = 0, + /** Flush ADC and start conversion */ + ADC_EVENT_ACTION_FLUSH_START_CONV = ADC_EVCTRL_SYNCEI, + /** Start conversion */ + ADC_EVENT_ACTION_START_CONV = ADC_EVCTRL_STARTEI, }; /** @@ -588,56 +582,56 @@ enum adc_event_action { * */ enum adc_positive_input { - /** ADC0 pin */ - ADC_POSITIVE_INPUT_PIN0 = ADC_INPUTCTRL_MUXPOS_PIN0, - /** ADC1 pin */ - ADC_POSITIVE_INPUT_PIN1 = ADC_INPUTCTRL_MUXPOS_PIN1, - /** ADC2 pin */ - ADC_POSITIVE_INPUT_PIN2 = ADC_INPUTCTRL_MUXPOS_PIN2, - /** ADC3 pin */ - ADC_POSITIVE_INPUT_PIN3 = ADC_INPUTCTRL_MUXPOS_PIN3, - /** ADC4 pin */ - ADC_POSITIVE_INPUT_PIN4 = ADC_INPUTCTRL_MUXPOS_PIN4, - /** ADC5 pin */ - ADC_POSITIVE_INPUT_PIN5 = ADC_INPUTCTRL_MUXPOS_PIN5, - /** ADC6 pin */ - ADC_POSITIVE_INPUT_PIN6 = ADC_INPUTCTRL_MUXPOS_PIN6, - /** ADC7 pin */ - ADC_POSITIVE_INPUT_PIN7 = ADC_INPUTCTRL_MUXPOS_PIN7, - /** ADC8 pin */ - ADC_POSITIVE_INPUT_PIN8 = ADC_INPUTCTRL_MUXPOS_PIN8, - /** ADC9 pin */ - ADC_POSITIVE_INPUT_PIN9 = ADC_INPUTCTRL_MUXPOS_PIN9, - /** ADC10 pin */ - ADC_POSITIVE_INPUT_PIN10 = ADC_INPUTCTRL_MUXPOS_PIN10, - /** ADC11 pin */ - ADC_POSITIVE_INPUT_PIN11 = ADC_INPUTCTRL_MUXPOS_PIN11, - /** ADC12 pin */ - ADC_POSITIVE_INPUT_PIN12 = ADC_INPUTCTRL_MUXPOS_PIN12, - /** ADC13 pin */ - ADC_POSITIVE_INPUT_PIN13 = ADC_INPUTCTRL_MUXPOS_PIN13, - /** ADC14 pin */ - ADC_POSITIVE_INPUT_PIN14 = ADC_INPUTCTRL_MUXPOS_PIN14, - /** ADC15 pin */ - ADC_POSITIVE_INPUT_PIN15 = ADC_INPUTCTRL_MUXPOS_PIN15, - /** ADC16 pin */ - ADC_POSITIVE_INPUT_PIN16 = ADC_INPUTCTRL_MUXPOS_PIN16, - /** ADC17 pin */ - ADC_POSITIVE_INPUT_PIN17 = ADC_INPUTCTRL_MUXPOS_PIN17, - /** ADC18 pin */ - ADC_POSITIVE_INPUT_PIN18 = ADC_INPUTCTRL_MUXPOS_PIN18, - /** ADC19 pin */ - ADC_POSITIVE_INPUT_PIN19 = ADC_INPUTCTRL_MUXPOS_PIN19, - /** Temperature reference */ - ADC_POSITIVE_INPUT_TEMP = ADC_INPUTCTRL_MUXPOS_TEMP, - /** Bandgap voltage */ - ADC_POSITIVE_INPUT_BANDGAP = ADC_INPUTCTRL_MUXPOS_BANDGAP, - /** 1/4 scaled core supply */ - ADC_POSITIVE_INPUT_SCALEDCOREVCC = ADC_INPUTCTRL_MUXPOS_SCALEDCOREVCC, - /** 1/4 scaled I/O supply */ - ADC_POSITIVE_INPUT_SCALEDIOVCC = ADC_INPUTCTRL_MUXPOS_SCALEDIOVCC, - /** DAC input */ - ADC_POSITIVE_INPUT_DAC = ADC_INPUTCTRL_MUXPOS_DAC, + /** ADC0 pin */ + ADC_POSITIVE_INPUT_PIN0 = ADC_INPUTCTRL_MUXPOS_PIN0, + /** ADC1 pin */ + ADC_POSITIVE_INPUT_PIN1 = ADC_INPUTCTRL_MUXPOS_PIN1, + /** ADC2 pin */ + ADC_POSITIVE_INPUT_PIN2 = ADC_INPUTCTRL_MUXPOS_PIN2, + /** ADC3 pin */ + ADC_POSITIVE_INPUT_PIN3 = ADC_INPUTCTRL_MUXPOS_PIN3, + /** ADC4 pin */ + ADC_POSITIVE_INPUT_PIN4 = ADC_INPUTCTRL_MUXPOS_PIN4, + /** ADC5 pin */ + ADC_POSITIVE_INPUT_PIN5 = ADC_INPUTCTRL_MUXPOS_PIN5, + /** ADC6 pin */ + ADC_POSITIVE_INPUT_PIN6 = ADC_INPUTCTRL_MUXPOS_PIN6, + /** ADC7 pin */ + ADC_POSITIVE_INPUT_PIN7 = ADC_INPUTCTRL_MUXPOS_PIN7, + /** ADC8 pin */ + ADC_POSITIVE_INPUT_PIN8 = ADC_INPUTCTRL_MUXPOS_PIN8, + /** ADC9 pin */ + ADC_POSITIVE_INPUT_PIN9 = ADC_INPUTCTRL_MUXPOS_PIN9, + /** ADC10 pin */ + ADC_POSITIVE_INPUT_PIN10 = ADC_INPUTCTRL_MUXPOS_PIN10, + /** ADC11 pin */ + ADC_POSITIVE_INPUT_PIN11 = ADC_INPUTCTRL_MUXPOS_PIN11, + /** ADC12 pin */ + ADC_POSITIVE_INPUT_PIN12 = ADC_INPUTCTRL_MUXPOS_PIN12, + /** ADC13 pin */ + ADC_POSITIVE_INPUT_PIN13 = ADC_INPUTCTRL_MUXPOS_PIN13, + /** ADC14 pin */ + ADC_POSITIVE_INPUT_PIN14 = ADC_INPUTCTRL_MUXPOS_PIN14, + /** ADC15 pin */ + ADC_POSITIVE_INPUT_PIN15 = ADC_INPUTCTRL_MUXPOS_PIN15, + /** ADC16 pin */ + ADC_POSITIVE_INPUT_PIN16 = ADC_INPUTCTRL_MUXPOS_PIN16, + /** ADC17 pin */ + ADC_POSITIVE_INPUT_PIN17 = ADC_INPUTCTRL_MUXPOS_PIN17, + /** ADC18 pin */ + ADC_POSITIVE_INPUT_PIN18 = ADC_INPUTCTRL_MUXPOS_PIN18, + /** ADC19 pin */ + ADC_POSITIVE_INPUT_PIN19 = ADC_INPUTCTRL_MUXPOS_PIN19, + /** Temperature reference */ + ADC_POSITIVE_INPUT_TEMP = ADC_INPUTCTRL_MUXPOS_TEMP, + /** Bandgap voltage */ + ADC_POSITIVE_INPUT_BANDGAP = ADC_INPUTCTRL_MUXPOS_BANDGAP, + /** 1/4 scaled core supply */ + ADC_POSITIVE_INPUT_SCALEDCOREVCC = ADC_INPUTCTRL_MUXPOS_SCALEDCOREVCC, + /** 1/4 scaled I/O supply */ + ADC_POSITIVE_INPUT_SCALEDIOVCC = ADC_INPUTCTRL_MUXPOS_SCALEDIOVCC, + /** DAC input */ + ADC_POSITIVE_INPUT_DAC = ADC_INPUTCTRL_MUXPOS_DAC, }; /** @@ -647,26 +641,26 @@ enum adc_positive_input { * */ enum adc_negative_input { - /** ADC0 pin */ - ADC_NEGATIVE_INPUT_PIN0 = ADC_INPUTCTRL_MUXNEG_PIN0, - /** ADC1 pin */ - ADC_NEGATIVE_INPUT_PIN1 = ADC_INPUTCTRL_MUXNEG_PIN1, - /** ADC2 pin */ - ADC_NEGATIVE_INPUT_PIN2 = ADC_INPUTCTRL_MUXNEG_PIN2, - /** ADC3 pin */ - ADC_NEGATIVE_INPUT_PIN3 = ADC_INPUTCTRL_MUXNEG_PIN3, - /** ADC4 pin */ - ADC_NEGATIVE_INPUT_PIN4 = ADC_INPUTCTRL_MUXNEG_PIN4, - /** ADC5 pin */ - ADC_NEGATIVE_INPUT_PIN5 = ADC_INPUTCTRL_MUXNEG_PIN5, - /** ADC6 pin */ - ADC_NEGATIVE_INPUT_PIN6 = ADC_INPUTCTRL_MUXNEG_PIN6, - /** ADC7 pin */ - ADC_NEGATIVE_INPUT_PIN7 = ADC_INPUTCTRL_MUXNEG_PIN7, - /** Internal ground */ - ADC_NEGATIVE_INPUT_GND = ADC_INPUTCTRL_MUXNEG_GND, - /** I/O ground */ - ADC_NEGATIVE_INPUT_IOGND = ADC_INPUTCTRL_MUXNEG_IOGND, + /** ADC0 pin */ + ADC_NEGATIVE_INPUT_PIN0 = ADC_INPUTCTRL_MUXNEG_PIN0, + /** ADC1 pin */ + ADC_NEGATIVE_INPUT_PIN1 = ADC_INPUTCTRL_MUXNEG_PIN1, + /** ADC2 pin */ + ADC_NEGATIVE_INPUT_PIN2 = ADC_INPUTCTRL_MUXNEG_PIN2, + /** ADC3 pin */ + ADC_NEGATIVE_INPUT_PIN3 = ADC_INPUTCTRL_MUXNEG_PIN3, + /** ADC4 pin */ + ADC_NEGATIVE_INPUT_PIN4 = ADC_INPUTCTRL_MUXNEG_PIN4, + /** ADC5 pin */ + ADC_NEGATIVE_INPUT_PIN5 = ADC_INPUTCTRL_MUXNEG_PIN5, + /** ADC6 pin */ + ADC_NEGATIVE_INPUT_PIN6 = ADC_INPUTCTRL_MUXNEG_PIN6, + /** ADC7 pin */ + ADC_NEGATIVE_INPUT_PIN7 = ADC_INPUTCTRL_MUXNEG_PIN7, + /** Internal ground */ + ADC_NEGATIVE_INPUT_GND = ADC_INPUTCTRL_MUXNEG_GND, + /** I/O ground */ + ADC_NEGATIVE_INPUT_IOGND = ADC_INPUTCTRL_MUXNEG_IOGND, }; /** @@ -678,28 +672,28 @@ enum adc_negative_input { * */ enum adc_accumulate_samples { - /** No averaging */ - ADC_ACCUMULATE_DISABLE = ADC_AVGCTRL_SAMPLENUM_1, - /** Average 2 samples */ - ADC_ACCUMULATE_SAMPLES_2 = ADC_AVGCTRL_SAMPLENUM_2, - /** Average 4 samples */ - ADC_ACCUMULATE_SAMPLES_4 = ADC_AVGCTRL_SAMPLENUM_4, - /** Average 8 samples */ - ADC_ACCUMULATE_SAMPLES_8 = ADC_AVGCTRL_SAMPLENUM_8, - /** Average 16 samples */ - ADC_ACCUMULATE_SAMPLES_16 = ADC_AVGCTRL_SAMPLENUM_16, - /** Average 32 samples */ - ADC_ACCUMULATE_SAMPLES_32 = ADC_AVGCTRL_SAMPLENUM_32, - /** Average 64 samples */ - ADC_ACCUMULATE_SAMPLES_64 = ADC_AVGCTRL_SAMPLENUM_64, - /** Average 128 samples */ - ADC_ACCUMULATE_SAMPLES_128 = ADC_AVGCTRL_SAMPLENUM_128, - /** Average 265 samples */ - ADC_ACCUMULATE_SAMPLES_256 = ADC_AVGCTRL_SAMPLENUM_256, - /** Average 512 samples */ - ADC_ACCUMULATE_SAMPLES_512 = ADC_AVGCTRL_SAMPLENUM_512, - /** Average 1024 samples */ - ADC_ACCUMULATE_SAMPLES_1024 = ADC_AVGCTRL_SAMPLENUM_1024, + /** No averaging */ + ADC_ACCUMULATE_DISABLE = ADC_AVGCTRL_SAMPLENUM_1, + /** Average 2 samples */ + ADC_ACCUMULATE_SAMPLES_2 = ADC_AVGCTRL_SAMPLENUM_2, + /** Average 4 samples */ + ADC_ACCUMULATE_SAMPLES_4 = ADC_AVGCTRL_SAMPLENUM_4, + /** Average 8 samples */ + ADC_ACCUMULATE_SAMPLES_8 = ADC_AVGCTRL_SAMPLENUM_8, + /** Average 16 samples */ + ADC_ACCUMULATE_SAMPLES_16 = ADC_AVGCTRL_SAMPLENUM_16, + /** Average 32 samples */ + ADC_ACCUMULATE_SAMPLES_32 = ADC_AVGCTRL_SAMPLENUM_32, + /** Average 64 samples */ + ADC_ACCUMULATE_SAMPLES_64 = ADC_AVGCTRL_SAMPLENUM_64, + /** Average 128 samples */ + ADC_ACCUMULATE_SAMPLES_128 = ADC_AVGCTRL_SAMPLENUM_128, + /** Average 265 samples */ + ADC_ACCUMULATE_SAMPLES_256 = ADC_AVGCTRL_SAMPLENUM_256, + /** Average 512 samples */ + ADC_ACCUMULATE_SAMPLES_512 = ADC_AVGCTRL_SAMPLENUM_512, + /** Average 1024 samples */ + ADC_ACCUMULATE_SAMPLES_1024 = ADC_AVGCTRL_SAMPLENUM_1024, }; /** @@ -712,37 +706,35 @@ enum adc_accumulate_samples { * used when the \ref ADC_RESOLUTION_CUSTOM resolution setting is used. */ enum adc_divide_result { - /** Don't divide result register after accumulation */ - ADC_DIVIDE_RESULT_DISABLE = 0, - /** Divide result register by 2 after accumulation */ - ADC_DIVIDE_RESULT_2 = 1, - /** Divide result register by 4 after accumulation */ - ADC_DIVIDE_RESULT_4 = 2, - /** Divide result register by 8 after accumulation */ - ADC_DIVIDE_RESULT_8 = 3, - /** Divide result register by 16 after accumulation */ - ADC_DIVIDE_RESULT_16 = 4, - /** Divide result register by 32 after accumulation */ - ADC_DIVIDE_RESULT_32 = 5, - /** Divide result register by 64 after accumulation */ - ADC_DIVIDE_RESULT_64 = 6, - /** Divide result register by 128 after accumulation */ - ADC_DIVIDE_RESULT_128 = 7, + /** Don't divide result register after accumulation */ + ADC_DIVIDE_RESULT_DISABLE = 0, + /** Divide result register by 2 after accumulation */ + ADC_DIVIDE_RESULT_2 = 1, + /** Divide result register by 4 after accumulation */ + ADC_DIVIDE_RESULT_4 = 2, + /** Divide result register by 8 after accumulation */ + ADC_DIVIDE_RESULT_8 = 3, + /** Divide result register by 16 after accumulation */ + ADC_DIVIDE_RESULT_16 = 4, + /** Divide result register by 32 after accumulation */ + ADC_DIVIDE_RESULT_32 = 5, + /** Divide result register by 64 after accumulation */ + ADC_DIVIDE_RESULT_64 = 6, + /** Divide result register by 128 after accumulation */ + ADC_DIVIDE_RESULT_128 = 7, }; -#if ADC_CALLBACK_MODE == true /** * Enum for the possible ADC interrupt flags */ enum adc_interrupt_flag { - /** ADC result ready */ - ADC_INTERRUPT_RESULT_READY = ADC_INTFLAG_RESRDY, - /** Window monitor match */ - ADC_INTERRUPT_WINDOW = ADC_INTFLAG_WINMON, - /** ADC result overwritten before read */ - ADC_INTERRUPT_OVERRUN = ADC_INTFLAG_OVERRUN, + /** ADC result ready */ + ADC_INTERRUPT_RESULT_READY = ADC_INTFLAG_RESRDY, + /** Window monitor match */ + ADC_INTERRUPT_WINDOW = ADC_INTFLAG_WINMON, + /** ADC result overwritten before read */ + ADC_INTERRUPT_OVERRUN = ADC_INTFLAG_OVERRUN, }; -#endif /** * \brief ADC oversampling and decimation enum @@ -752,16 +744,16 @@ enum adc_interrupt_flag { * */ enum adc_oversampling_and_decimation { - /** Don't use oversampling and decimation mode */ - ADC_OVERSAMPLING_AND_DECIMATION_DISABLE = 0, - /** 1 bit resolution increase */ - ADC_OVERSAMPLING_AND_DECIMATION_1BIT, - /** 2 bits resolution increase */ - ADC_OVERSAMPLING_AND_DECIMATION_2BIT, - /** 3 bits resolution increase */ - ADC_OVERSAMPLING_AND_DECIMATION_3BIT, - /** 4 bits resolution increase */ - ADC_OVERSAMPLING_AND_DECIMATION_4BIT + /** Don't use oversampling and decimation mode */ + ADC_OVERSAMPLING_AND_DECIMATION_DISABLE = 0, + /** 1 bit resolution increase */ + ADC_OVERSAMPLING_AND_DECIMATION_1BIT, + /** 2 bits resolution increase */ + ADC_OVERSAMPLING_AND_DECIMATION_2BIT, + /** 3 bits resolution increase */ + ADC_OVERSAMPLING_AND_DECIMATION_3BIT, + /** 4 bits resolution increase */ + ADC_OVERSAMPLING_AND_DECIMATION_4BIT }; /** @@ -770,12 +762,12 @@ enum adc_oversampling_and_decimation { * Window monitor configuration structure. */ struct adc_window_config { - /** Selected window mode */ - enum adc_window_mode window_mode; - /** Lower window value */ - int32_t window_lower_value; - /** Upper window value */ - int32_t window_upper_value; + /** Selected window mode */ + enum adc_window_mode window_mode; + /** Lower window value */ + int32_t window_lower_value; + /** Upper window value */ + int32_t window_upper_value; }; /** @@ -785,10 +777,10 @@ struct adc_window_config { * disable events via \ref adc_enable_events() and \ref adc_disable_events(). */ struct adc_events { - /** Enable event generation on conversion done */ - bool generate_event_on_conversion_done; - /** Enable event generation on window monitor */ - bool generate_event_on_window_monitor; + /** Enable event generation on conversion done */ + bool generate_event_on_conversion_done; + /** Enable event generation on window monitor */ + bool generate_event_on_window_monitor; }; /** @@ -799,25 +791,25 @@ struct adc_events { * \ref adc_get_config_defaults . */ struct adc_correction_config { - /** - * Enables correction for gain and offset based on values of gain_correction and - * offset_correction if set to true. - */ - bool correction_enable; - /** - * This value defines how the ADC conversion result is compensated for gain - * error before written to the result register. This is a fractional value, - * 1-bit integer plus an 11-bit fraction, therefore - * 1/2 <= gain_correction < 2. Valid \c gain_correction values ranges from - * \c 0b010000000000 to \c 0b111111111111. - */ - uint16_t gain_correction; - /** - * This value defines how the ADC conversion result is compensated for - * offset error before written to the result register. This is a 12-bit - * value in two’s complement format. - */ - int16_t offset_correction; + /** + * Enables correction for gain and offset based on values of gain_correction and + * offset_correction if set to true. + */ + bool correction_enable; + /** + * This value defines how the ADC conversion result is compensated for gain + * error before written to the result register. This is a fractional value, + * 1-bit integer plus an 11-bit fraction, therefore + * 1/2 <= gain_correction < 2. Valid \c gain_correction values ranges from + * \c 0b010000000000 to \c 0b111111111111. + */ + uint16_t gain_correction; + /** + * This value defines how the ADC conversion result is compensated for + * offset error before written to the result register. This is a 12-bit + * value in two’s complement format. + */ + int16_t offset_correction; }; /** @@ -827,16 +819,16 @@ struct adc_correction_config { * be initialized by \ref adc_get_config_defaults . */ struct adc_pin_scan_config { - /** - * Offset (relative to selected positive input) of the first input pin to be - * used in pin scan mode. - */ - uint8_t offset_start_scan; - /** - * Number of input pins to scan in pin scan mode. A value below 2 will - * disable pin scan mode. - */ - uint8_t inputs_to_scan; + /** + * Offset (relative to selected positive input) of the first input pin to be + * used in pin scan mode. + */ + uint8_t offset_start_scan; + /** + * Number of input pins to scan in pin scan mode. A value below 2 will + * disable pin scan mode. + */ + uint8_t inputs_to_scan; }; /** @@ -847,56 +839,56 @@ struct adc_pin_scan_config { * function before being modified by the user application. */ struct adc_config { - /** GCLK generator used to clock the peripheral */ - enum gclk_generator clock_source; - /** Voltage reference */ - enum adc_reference reference; - /** Clock prescaler */ - enum adc_clock_prescaler clock_prescaler; - /** Result resolution */ - enum adc_resolution resolution; - /** Gain factor */ - enum adc_gain_factor gain_factor; - /** Positive MUX input */ - enum adc_positive_input positive_input; - /** Negative MUX input */ - enum adc_negative_input negative_input; - /** Number of ADC samples to accumulate when using the - * \c ADC_RESOLUTION_CUSTOM mode - */ - enum adc_accumulate_samples accumulate_samples; - /** Division ration when using the ADC_RESOLUTION_CUSTOM mode */ - enum adc_divide_result divide_result; - /** Left adjusted result */ - bool left_adjust; - /** Enables differential mode if true */ - bool differential_mode; - /** Enables free running mode if true */ - bool freerunning; - /** Enables ADC in standby sleep mode if true */ - bool run_in_standby; - /** - * Enables reference buffer offset compensation if true. - * This will increase the accuracy of the gain stage, but decreases the input - * impedance; therefore the startup time of the reference must be increased. - */ - bool reference_compensation_enable; - /** - * This value (0-63) control the ADC sampling time in number of half ADC - * prescaled clock cycles (depends of \c ADC_PRESCALER value), thus - * controlling the ADC input impedance. Sampling time is set according to - * the formula: - * Sample time = (sample_length+1) * (ADCclk / 2) - */ - uint8_t sample_length; - /** Window monitor configuration structure */ - struct adc_window_config window; - /** Gain and offset correction configuration structure */ - struct adc_correction_config correction; - /** Event action to take on incoming event */ - enum adc_event_action event_action; - /** Pin scan configuration structure */ - struct adc_pin_scan_config pin_scan; + /** GCLK generator used to clock the peripheral */ + enum gclk_generator clock_source; + /** Voltage reference */ + enum adc_reference reference; + /** Clock prescaler */ + enum adc_clock_prescaler clock_prescaler; + /** Result resolution */ + enum adc_resolution resolution; + /** Gain factor */ + enum adc_gain_factor gain_factor; + /** Positive MUX input */ + enum adc_positive_input positive_input; + /** Negative MUX input */ + enum adc_negative_input negative_input; + /** Number of ADC samples to accumulate when using the + * \c ADC_RESOLUTION_CUSTOM mode + */ + enum adc_accumulate_samples accumulate_samples; + /** Division ration when using the ADC_RESOLUTION_CUSTOM mode */ + enum adc_divide_result divide_result; + /** Left adjusted result */ + bool left_adjust; + /** Enables differential mode if true */ + bool differential_mode; + /** Enables free running mode if true */ + bool freerunning; + /** Enables ADC in standby sleep mode if true */ + bool run_in_standby; + /** + * Enables reference buffer offset compensation if true. + * This will increase the accuracy of the gain stage, but decreases the input + * impedance; therefore the startup time of the reference must be increased. + */ + bool reference_compensation_enable; + /** + * This value (0-63) control the ADC sampling time in number of half ADC + * prescaled clock cycles (depends of \c ADC_PRESCALER value), thus + * controlling the ADC input impedance. Sampling time is set according to + * the formula: + * Sample time = (sample_length+1) * (ADCclk / 2) + */ + uint8_t sample_length; + /** Window monitor configuration structure */ + struct adc_window_config window; + /** Gain and offset correction configuration structure */ + struct adc_correction_config correction; + /** Event action to take on incoming event */ + enum adc_event_action event_action; + /** Pin scan configuration structure */ + struct adc_pin_scan_config pin_scan; }; /** @@ -909,38 +901,31 @@ struct adc_config { * application; they are reserved for module-internal use only. */ struct adc_module { -#if !defined(__DOXYGEN__) - /** Pointer to ADC hardware module */ - Adc *hw; - /** Keep reference configuration so we know when enable is called */ - enum adc_reference reference; -# if ADC_CALLBACK_MODE == true - /** Array to store callback functions */ - adc_callback_t callback[ADC_CALLBACK_N]; - /** Pointer to buffer used for ADC results */ - volatile uint16_t *job_buffer; - /** Remaining number of conversions in current job */ - volatile uint16_t remaining_conversions; - /** Bit mask for callbacks registered */ - uint8_t registered_callback_mask; - /** Bit mask for callbacks enabled */ - uint8_t enabled_callback_mask; - /** Holds the status of the ongoing or last conversion job */ - volatile enum adc_status_code job_status; - /** If software triggering is needed */ - bool software_trigger; -# endif -#endif + /** Pointer to ADC hardware module */ + Adc *hw; + /** Keep reference configuration so we know when enable is called */ + enum adc_reference reference; + /** Array to store callback functions */ + adc_callback_t callback[ADC_CALLBACK_N]; + /** Pointer to buffer used for ADC results */ + volatile uint16_t *job_buffer; + /** Remaining number of conversions in current job */ + volatile uint16_t remaining_conversions; + /** Bit mask for callbacks registered */ + uint8_t registered_callback_mask; + /** Bit mask for callbacks enabled */ + uint8_t enabled_callback_mask; + /** Holds the status of the ongoing or last conversion job */ + volatile enum adc_status_code job_status; + /** If software triggering is needed */ + bool software_trigger; }; /** - * \name Driver initialization and configuration - * @{ + * Driver initialization and configuration */ -enum adc_status_code adc_init( - struct adc_module *const module_inst, - Adc *hw, - struct adc_config *config); +enum adc_status_code adc_init(Adc *hw, + struct adc_config *config); /** * \brief Initializes an ADC configuration structure to defaults @@ -975,42 +960,39 @@ enum adc_status_code adc_init( */ static inline void adc_get_config_defaults(struct adc_config *const config) { - Assert(config); - config->clock_source = GCLK_GENERATOR_0; - config->reference = ADC_REFERENCE_INT1V; - config->clock_prescaler = ADC_CLOCK_PRESCALER_DIV4; - config->resolution = ADC_RESOLUTION_12BIT; - config->window.window_mode = ADC_WINDOW_MODE_DISABLE; - config->window.window_upper_value = 0; - config->window.window_lower_value = 0; - config->gain_factor = ADC_GAIN_FACTOR_1X; + Assert(config); + config->clock_source = GCLK_GENERATOR_0; + config->reference = ADC_REFERENCE_INT1V; + config->clock_prescaler = ADC_CLOCK_PRESCALER_DIV4; + config->resolution = ADC_RESOLUTION_12BIT; + config->window.window_mode = ADC_WINDOW_MODE_DISABLE; + config->window.window_upper_value = 0; + config->window.window_lower_value = 0; + config->gain_factor = ADC_GAIN_FACTOR_1X; #if SAMR21 - config->positive_input = ADC_POSITIVE_INPUT_PIN6 ; + config->positive_input = ADC_POSITIVE_INPUT_PIN6 ; #else - config->positive_input = ADC_POSITIVE_INPUT_PIN0 ; + config->positive_input = ADC_POSITIVE_INPUT_PIN0 ; #endif - config->negative_input = ADC_NEGATIVE_INPUT_GND ; - config->accumulate_samples = ADC_ACCUMULATE_DISABLE; - config->divide_result = ADC_DIVIDE_RESULT_DISABLE; - config->left_adjust = false; - config->differential_mode = false; - config->freerunning = false; - config->event_action = ADC_EVENT_ACTION_DISABLED; - config->run_in_standby = false; - config->reference_compensation_enable = false; - config->correction.correction_enable = false; - config->correction.gain_correction = ADC_GAINCORR_RESETVALUE; - config->correction.offset_correction = ADC_OFFSETCORR_RESETVALUE; - config->sample_length = 0; - config->pin_scan.offset_start_scan = 0; - config->pin_scan.inputs_to_scan = 0; + config->negative_input = ADC_NEGATIVE_INPUT_GND ; + config->accumulate_samples = ADC_ACCUMULATE_DISABLE; + config->divide_result = ADC_DIVIDE_RESULT_DISABLE; + config->left_adjust = false; + config->differential_mode = false; + config->freerunning = false; + config->event_action = ADC_EVENT_ACTION_DISABLED; + config->run_in_standby = false; + config->reference_compensation_enable = false; + config->correction.correction_enable = false; + config->correction.gain_correction = ADC_GAINCORR_RESETVALUE; + config->correction.offset_correction = ADC_OFFSETCORR_RESETVALUE; + config->sample_length = 0; + config->pin_scan.offset_start_scan = 0; + config->pin_scan.inputs_to_scan = 0; } -/** @} */ - /** - * \name Status Management - * @{ + * Status Management */ /** @@ -1027,35 +1009,30 @@ static inline void adc_get_config_defaults(struct adc_config *const config) * window range * \retval ADC_STATUS_OVERRUN ADC result has overrun */ -static inline uint32_t adc_get_status( - struct adc_module *const module_inst) +static inline uint32_t adc_get_status(void) { - /* Sanity check arguments */ - Assert(module_inst); - Assert(module_inst->hw); + Adc *const adc_module = module_inst.hw; - Adc *const adc_module = module_inst->hw; + uint32_t int_flags = adc_module->INTFLAG.reg; - uint32_t int_flags = adc_module->INTFLAG.reg; + uint32_t status_flags = 0; - uint32_t status_flags = 0; + /* Check for ADC Result Ready */ + if (int_flags & ADC_INTFLAG_RESRDY) { + status_flags |= ADC_STATUS_RESULT_READY; + } - /* Check for ADC Result Ready */ - if (int_flags & ADC_INTFLAG_RESRDY) { - status_flags |= ADC_STATUS_RESULT_READY; - } + /* Check for ADC Window Match */ + if (int_flags & ADC_INTFLAG_WINMON) { + status_flags |= ADC_STATUS_WINDOW; + } - /* Check for ADC Window Match */ - if (int_flags & ADC_INTFLAG_WINMON) { - status_flags |= ADC_STATUS_WINDOW; - } + /* Check for ADC Overrun */ + if (int_flags & ADC_INTFLAG_OVERRUN) { + status_flags |= ADC_STATUS_OVERRUN; + } - /* Check for ADC Overrun */ - if (int_flags & ADC_INTFLAG_OVERRUN) { - status_flags |= ADC_STATUS_OVERRUN; - } - - return status_flags; + return status_flags; } /** @@ -1066,43 +1043,38 @@ static inline uint32_t adc_get_status( * \param[in] module_inst Pointer to the ADC software instance struct * \param[in] status_flags Bitmask of \c ADC_STATUS_* flags to clear */ -static inline void adc_clear_status( - struct adc_module *const module_inst, - const uint32_t status_flags) +static inline void adc_clear_status(const uint32_t status_flags) { - /* Sanity check arguments */ - Assert(module_inst); - Assert(module_inst->hw); + /* Sanity check arguments */ + Assert(module_inst.hw); - Adc *const adc_module = module_inst->hw; + Adc *const adc_module = module_inst.hw; - uint32_t int_flags = 0; + uint32_t int_flags = 0; - /* Check for ADC Result Ready */ - if (status_flags & ADC_STATUS_RESULT_READY) { - int_flags |= ADC_INTFLAG_RESRDY; - } + /* Check for ADC Result Ready */ + if (status_flags & ADC_STATUS_RESULT_READY) { + int_flags |= ADC_INTFLAG_RESRDY; + } - /* Check for ADC Window Match */ - if (status_flags & ADC_STATUS_WINDOW) { - int_flags |= ADC_INTFLAG_WINMON; - } + /* Check for ADC Window Match */ + if (status_flags & ADC_STATUS_WINDOW) { + int_flags |= ADC_INTFLAG_WINMON; + } - /* Check for ADC Overrun */ - if (status_flags & ADC_STATUS_OVERRUN) { - int_flags |= ADC_INTFLAG_OVERRUN; - } + /* Check for ADC Overrun */ + if (status_flags & ADC_STATUS_OVERRUN) { + int_flags |= ADC_INTFLAG_OVERRUN; + } - /* Clear interrupt flag */ - adc_module->INTFLAG.reg = int_flags; + /* Clear interrupt flag */ + adc_module->INTFLAG.reg = int_flags; } -/** @} */ + /** - * \name Enable, disable and reset ADC module, start conversion and read result - * @{ + * Enable, disable and reset ADC module, start conversion and read result */ - /** * \brief Determines if the hardware module(s) are currently synchronizing to the bus. * @@ -1119,19 +1091,15 @@ static inline void adc_clear_status( * \retval true if the module synchronization is ongoing * \retval false if the module has completed synchronization */ -static inline bool adc_is_syncing( - struct adc_module *const module_inst) +static inline bool adc_is_syncing(void) { - /* Sanity check arguments */ - Assert(module_inst); + Adc *const adc_module = module_inst.hw; - Adc *const adc_module = module_inst->hw; + if (adc_module->STATUS.reg & ADC_STATUS_SYNCBUSY) { + return true; + } - if (adc_module->STATUS.reg & ADC_STATUS_SYNCBUSY) { - return true; - } - - return false; + return false; } /** @@ -1142,29 +1110,24 @@ static inline bool adc_is_syncing( * * \param[in] module_inst Pointer to the ADC software instance struct */ -static inline enum adc_status_code adc_enable( - struct adc_module *const module_inst) +static inline enum adc_status_code adc_enable(void) { - Assert(module_inst); - Assert(module_inst->hw); - Adc *const adc_module = module_inst->hw; + Assert(module_inst.hw); - while (adc_is_syncing(module_inst)) { - /* Wait for synchronization */ - } + Adc *const adc_module = module_inst.hw; - /* Make sure bandgap is enabled if requested by the config */ - if (module_inst->reference == ADC_REFERENCE_INT1V) { - system_voltage_reference_enable(SYSTEM_VOLTAGE_REFERENCE_BANDGAP); - } + while (adc_is_syncing()) { + /* Wait for synchronization */ + } -#if ADC_CALLBACK_MODE == true - system_interrupt_enable(SYSTEM_INTERRUPT_MODULE_ADC); -#endif + /* Make sure bandgap is enabled if requested by the config */ + if (module_inst.reference == ADC_REFERENCE_INT1V) { + system_voltage_reference_enable(SYSTEM_VOLTAGE_REFERENCE_BANDGAP); + } - adc_module->CTRLA.reg |= ADC_CTRLA_ENABLE; - return ADC_STATUS_OK; + adc_module->CTRLA.reg |= ADC_CTRLA_ENABLE; + return ADC_STATUS_OK; } /** @@ -1174,24 +1137,18 @@ static inline enum adc_status_code adc_enable( * * \param[in] module_inst Pointer to the ADC software instance struct */ -static inline enum adc_status_code adc_disable( - struct adc_module *const module_inst) +static inline enum adc_status_code adc_disable(void) { - Assert(module_inst); - Assert(module_inst->hw); + Assert(module_inst.hw); - Adc *const adc_module = module_inst->hw; + Adc *const adc_module = module_inst.hw; -#if ADC_CALLBACK_MODE == true - system_interrupt_disable(SYSTEM_INTERRUPT_MODULE_ADC); -#endif + while (adc_is_syncing()) { + /* Wait for synchronization */ + } - while (adc_is_syncing(module_inst)) { - /* Wait for synchronization */ - } - - adc_module->CTRLA.reg &= ~ADC_CTRLA_ENABLE; - return ADC_STATUS_OK; + adc_module->CTRLA.reg &= ~ADC_CTRLA_ENABLE; + return ADC_STATUS_OK; } /** @@ -1202,25 +1159,24 @@ static inline enum adc_status_code adc_disable( * * \param[in] module_inst Pointer to the ADC software instance struct */ -static inline enum adc_status_code adc_reset( - struct adc_module *const module_inst) +static inline enum adc_status_code adc_reset(void) { - /* Sanity check arguments */ - Assert(module_inst); - Assert(module_inst->hw); + /* Sanity check arguments */ - Adc *const adc_module = module_inst->hw; + Assert(module_inst.hw); - /* Disable to make sure the pipeline is flushed before reset */ - adc_disable(module_inst); + Adc *const adc_module = module_inst.hw; - while (adc_is_syncing(module_inst)) { - /* Wait for synchronization */ - } + /* Disable to make sure the pipeline is flushed before reset */ + adc_disable(); - /* Software reset the module */ - adc_module->CTRLA.reg |= ADC_CTRLA_SWRST; - return ADC_STATUS_OK; + while (adc_is_syncing()) { + /* Wait for synchronization */ + } + + /* Software reset the module */ + adc_module->CTRLA.reg |= ADC_CTRLA_SWRST; + return ADC_STATUS_OK; } @@ -1235,30 +1191,28 @@ static inline enum adc_status_code adc_reset( * \param[in] module_inst Software instance for the ADC peripheral * \param[in] events Struct containing flags of events to enable */ -static inline void adc_enable_events( - struct adc_module *const module_inst, - struct adc_events *const events) +static inline void adc_enable_events(struct adc_events *const events) { - /* Sanity check arguments */ - Assert(module_inst); - Assert(module_inst->hw); - Assert(events); + /* Sanity check arguments */ - Adc *const adc_module = module_inst->hw; + Assert(module_inst.hw); + Assert(events); - uint32_t event_mask = 0; + Adc *const adc_module = module_inst.hw; - /* Configure Window Monitor event */ - if (events->generate_event_on_window_monitor) { - event_mask |= ADC_EVCTRL_WINMONEO; - } + uint32_t event_mask = 0; - /* Configure Result Ready event */ - if (events->generate_event_on_conversion_done) { - event_mask |= ADC_EVCTRL_RESRDYEO; - } + /* Configure Window Monitor event */ + if (events->generate_event_on_window_monitor) { + event_mask |= ADC_EVCTRL_WINMONEO; + } - adc_module->EVCTRL.reg |= event_mask; + /* Configure Result Ready event */ + if (events->generate_event_on_conversion_done) { + event_mask |= ADC_EVCTRL_RESRDYEO; + } + + adc_module->EVCTRL.reg |= event_mask; } /** @@ -1272,30 +1226,28 @@ static inline void adc_enable_events( * \param[in] module_inst Software instance for the ADC peripheral * \param[in] events Struct containing flags of events to disable */ -static inline void adc_disable_events( - struct adc_module *const module_inst, - struct adc_events *const events) +static inline void adc_disable_events(struct adc_events *const events) { - /* Sanity check arguments */ - Assert(module_inst); - Assert(module_inst->hw); - Assert(events); + /* Sanity check arguments */ - Adc *const adc_module = module_inst->hw; + Assert(module_inst.hw); + Assert(events); - uint32_t event_mask = 0; + Adc *const adc_module = module_inst.hw; - /* Configure Window Monitor event */ - if (events->generate_event_on_window_monitor) { - event_mask |= ADC_EVCTRL_WINMONEO; - } + uint32_t event_mask = 0; - /* Configure Result Ready event */ - if (events->generate_event_on_conversion_done) { - event_mask |= ADC_EVCTRL_RESRDYEO; - } + /* Configure Window Monitor event */ + if (events->generate_event_on_window_monitor) { + event_mask |= ADC_EVCTRL_WINMONEO; + } - adc_module->EVCTRL.reg &= ~event_mask; + /* Configure Result Ready event */ + if (events->generate_event_on_conversion_done) { + event_mask |= ADC_EVCTRL_RESRDYEO; + } + + adc_module->EVCTRL.reg &= ~event_mask; } /** @@ -1305,19 +1257,18 @@ static inline void adc_disable_events( * * \param[in] module_inst Pointer to the ADC software instance struct */ -static inline void adc_start_conversion( - struct adc_module *const module_inst) +static inline void adc_start_conversion(void) { - Assert(module_inst); - Assert(module_inst->hw); - Adc *const adc_module = module_inst->hw; + Assert(module_inst.hw); - while (adc_is_syncing(module_inst)) { - /* Wait for synchronization */ - } + Adc *const adc_module = module_inst.hw; - adc_module->SWTRIG.reg |= ADC_SWTRIG_START; + while (adc_is_syncing()) { + /* Wait for synchronization */ + } + + adc_module->SWTRIG.reg |= ADC_SWTRIG_START; } /** @@ -1334,37 +1285,35 @@ static inline void adc_start_conversion( * \retval ADC_STATUS_ERR_OVERFLOW The result register has been overwritten by the * ADC module before the result was read by the software */ -static inline enum adc_status_code adc_read( - struct adc_module *const module_inst, - uint16_t *result) +static inline enum adc_status_code adc_read(uint16_t *result) { - Assert(module_inst); - Assert(module_inst->hw); - Assert(result); - if (!(adc_get_status(module_inst) & ADC_STATUS_RESULT_READY)) { - /* Result not ready */ - return ADC_STATUS_BUSY; - } + Assert(module_inst.hw); + Assert(result); - Adc *const adc_module = module_inst->hw; + if (!(adc_get_status() & ADC_STATUS_RESULT_READY)) { + /* Result not ready */ + return ADC_STATUS_BUSY; + } - while (adc_is_syncing(module_inst)) { - /* Wait for synchronization */ - } + Adc *const adc_module = module_inst.hw; - /* Get ADC result */ - *result = adc_module->RESULT.reg; + while (adc_is_syncing()) { + /* Wait for synchronization */ + } - /* Reset ready flag */ - adc_clear_status(module_inst, ADC_STATUS_RESULT_READY); + /* Get ADC result */ + *result = adc_module->RESULT.reg; - if (adc_get_status(module_inst) & ADC_STATUS_OVERRUN) { - adc_clear_status(module_inst, ADC_STATUS_OVERRUN); - return ADC_STATUS_ERR_OVERFLOW; - } + /* Reset ready flag */ + adc_clear_status(ADC_STATUS_RESULT_READY); - return ADC_STATUS_OK; + if (adc_get_status() & ADC_STATUS_OVERRUN) { + adc_clear_status(ADC_STATUS_OVERRUN); + return ADC_STATUS_ERR_OVERFLOW; + } + + return ADC_STATUS_OK; } /** @} */ @@ -1383,19 +1332,18 @@ static inline enum adc_status_code adc_read( * * \param[in] module_inst Pointer to the ADC software instance struct */ -static inline void adc_flush( - struct adc_module *const module_inst) +static inline void adc_flush(void) { - Assert(module_inst); - Assert(module_inst->hw); - Adc *const adc_module = module_inst->hw; + Assert(module_inst.hw); - while (adc_is_syncing(module_inst)) { - /* Wait for synchronization */ - } + Adc *const adc_module = module_inst.hw; - adc_module->SWTRIG.reg |= ADC_SWTRIG_FLUSH; + while (adc_is_syncing()) { + /* Wait for synchronization */ + } + + adc_module->SWTRIG.reg |= ADC_SWTRIG_FLUSH; } /** @@ -1407,39 +1355,37 @@ static inline void adc_flush( * \param[in] window_mode Window monitor mode to set * \param[in] window_lower_value Lower window monitor threshold value * \param[in] window_upper_value Upper window monitor threshold value - */ -static inline void adc_set_window_mode( - struct adc_module *const module_inst, - const enum adc_window_mode window_mode, - const int16_t window_lower_value, - const int16_t window_upper_value) + */ +static inline void adc_set_window_mode(const enum adc_window_mode window_mode, + const int16_t window_lower_value, + const int16_t window_upper_value) { - /* Sanity check arguments */ - Assert(module_inst); - Assert(module_inst->hw); + /* Sanity check arguments */ - Adc *const adc_module = module_inst->hw; + Assert(module_inst.hw); - while (adc_is_syncing(module_inst)) { - /* Wait for synchronization */ - } + Adc *const adc_module = module_inst.hw; - /* Set window mode */ - adc_module->WINCTRL.reg = window_mode << ADC_WINCTRL_WINMODE_Pos; + while (adc_is_syncing()) { + /* Wait for synchronization */ + } - while (adc_is_syncing(module_inst)) { - /* Wait for synchronization */ - } + /* Set window mode */ + adc_module->WINCTRL.reg = window_mode << ADC_WINCTRL_WINMODE_Pos; - /* Set lower window monitor threshold value */ - adc_module->WINLT.reg = window_lower_value << ADC_WINLT_WINLT_Pos; + while (adc_is_syncing()) { + /* Wait for synchronization */ + } - while (adc_is_syncing(module_inst)) { - /* Wait for synchronization */ - } + /* Set lower window monitor threshold value */ + adc_module->WINLT.reg = window_lower_value << ADC_WINLT_WINLT_Pos; - /* Set upper window monitor threshold value */ - adc_module->WINUT.reg = window_upper_value << ADC_WINUT_WINUT_Pos; + while (adc_is_syncing()) { + /* Wait for synchronization */ + } + + /* Set upper window monitor threshold value */ + adc_module->WINUT.reg = window_upper_value << ADC_WINUT_WINUT_Pos; } @@ -1451,24 +1397,22 @@ static inline void adc_set_window_mode( * \param[in] module_inst Pointer to the ADC software instance struct * \param[in] gain_factor Gain factor value to set */ -static inline void adc_set_gain( - struct adc_module *const module_inst, - const enum adc_gain_factor gain_factor) +static inline void adc_set_gain(const enum adc_gain_factor gain_factor) { - /* Sanity check arguments */ - Assert(module_inst); - Assert(module_inst->hw); + /* Sanity check arguments */ - Adc *const adc_module = module_inst->hw; + Assert(module_inst.hw); - while (adc_is_syncing(module_inst)) { - /* Wait for synchronization */ - } + Adc *const adc_module = module_inst.hw; - /* Set new gain factor */ - adc_module->INPUTCTRL.reg = - (adc_module->INPUTCTRL.reg & ~ADC_INPUTCTRL_GAIN_Msk) | - (gain_factor << ADC_INPUTCTRL_GAIN_Pos); + while (adc_is_syncing()) { + /* Wait for synchronization */ + } + + /* Set new gain factor */ + adc_module->INPUTCTRL.reg = + (adc_module->INPUTCTRL.reg & ~ADC_INPUTCTRL_GAIN_Msk) | + (gain_factor << ADC_INPUTCTRL_GAIN_Pos); } /** @@ -1491,44 +1435,42 @@ static inline void adc_set_gain( * \retval ADC_STATUS_ERR_INVALID_ARG Number of input pins to scan or offset has * an invalid value */ -static inline enum adc_status_code adc_set_pin_scan_mode( - struct adc_module *const module_inst, - uint8_t inputs_to_scan, - const uint8_t start_offset) +static inline enum adc_status_code adc_set_pin_scan_mode(uint8_t inputs_to_scan, + const uint8_t start_offset) { - /* Sanity check arguments */ - Assert(module_inst); - Assert(module_inst->hw); + /* Sanity check arguments */ - Adc *const adc_module = module_inst->hw; + Assert(module_inst.hw); - if (inputs_to_scan > 0) { - /* - * Number of input sources included is the value written to INPUTSCAN - * plus 1. - */ - inputs_to_scan--; - } + Adc *const adc_module = module_inst.hw; - if (inputs_to_scan > (ADC_INPUTCTRL_INPUTSCAN_Msk >> ADC_INPUTCTRL_INPUTSCAN_Pos) || - start_offset > (ADC_INPUTCTRL_INPUTOFFSET_Msk >> ADC_INPUTCTRL_INPUTOFFSET_Pos)) { - /* Invalid number of input pins */ - return ADC_STATUS_ERR_INVALID_ARG; - } + if (inputs_to_scan > 0) { + /* + * Number of input sources included is the value written to INPUTSCAN + * plus 1. + */ + inputs_to_scan--; + } - while (adc_is_syncing(module_inst)) { - /* Wait for synchronization */ - } + if (inputs_to_scan > (ADC_INPUTCTRL_INPUTSCAN_Msk >> ADC_INPUTCTRL_INPUTSCAN_Pos) || + start_offset > (ADC_INPUTCTRL_INPUTOFFSET_Msk >> ADC_INPUTCTRL_INPUTOFFSET_Pos)) { + /* Invalid number of input pins */ + return ADC_STATUS_ERR_INVALID_ARG; + } - /* Set pin scan mode */ - adc_module->INPUTCTRL.reg = - (adc_module->INPUTCTRL.reg & - ~(ADC_INPUTCTRL_INPUTSCAN_Msk | ADC_INPUTCTRL_INPUTOFFSET_Msk)) | - (start_offset << ADC_INPUTCTRL_INPUTOFFSET_Pos) | - (inputs_to_scan << ADC_INPUTCTRL_INPUTSCAN_Pos); + while (adc_is_syncing()) { + /* Wait for synchronization */ + } - return ADC_STATUS_OK; + /* Set pin scan mode */ + adc_module->INPUTCTRL.reg = + (adc_module->INPUTCTRL.reg & + ~(ADC_INPUTCTRL_INPUTSCAN_Msk | ADC_INPUTCTRL_INPUTOFFSET_Msk)) | + (start_offset << ADC_INPUTCTRL_INPUTOFFSET_Pos) | + (inputs_to_scan << ADC_INPUTCTRL_INPUTSCAN_Pos); + + return ADC_STATUS_OK; } /** @@ -1539,11 +1481,10 @@ static inline enum adc_status_code adc_set_pin_scan_mode( * * \param[in] module_inst Pointer to the ADC software instance struct */ -static inline void adc_disable_pin_scan_mode( - struct adc_module *const module_inst) +static inline void adc_disable_pin_scan_mode(void) { - /* Disable pin scan mode */ - adc_set_pin_scan_mode(module_inst, 0, 0); + /* Disable pin scan mode */ + adc_set_pin_scan_mode(0, 0); } @@ -1555,24 +1496,22 @@ static inline void adc_disable_pin_scan_mode( * \param[in] module_inst Pointer to the ADC software instance struct * \param[in] positive_input Positive input pin */ -static inline void adc_set_positive_input( - struct adc_module *const module_inst, - const enum adc_positive_input positive_input) +static inline void adc_set_positive_input(const enum adc_positive_input positive_input) { - /* Sanity check arguments */ - Assert(module_inst); - Assert(module_inst->hw); + /* Sanity check arguments */ - Adc *const adc_module = module_inst->hw; + Assert(module_inst.hw); - while (adc_is_syncing(module_inst)) { - /* Wait for synchronization */ - } + Adc *const adc_module = module_inst.hw; - /* Set positive input pin */ - adc_module->INPUTCTRL.reg = - (adc_module->INPUTCTRL.reg & ~ADC_INPUTCTRL_MUXPOS_Msk) | - (positive_input << ADC_INPUTCTRL_MUXPOS_Pos); + while (adc_is_syncing()) { + /* Wait for synchronization */ + } + + /* Set positive input pin */ + adc_module->INPUTCTRL.reg = + (adc_module->INPUTCTRL.reg & ~ADC_INPUTCTRL_MUXPOS_Msk) | + (positive_input << ADC_INPUTCTRL_MUXPOS_Pos); } @@ -1585,34 +1524,24 @@ static inline void adc_set_positive_input( * \param[in] module_inst Pointer to the ADC software instance struct * \param[in] negative_input Negative input pin */ -static inline void adc_set_negative_input( - struct adc_module *const module_inst, - const enum adc_negative_input negative_input) +static inline void adc_set_negative_input(const enum adc_negative_input negative_input) { - /* Sanity check arguments */ - Assert(module_inst); - Assert(module_inst->hw); + /* Sanity check arguments */ - Adc *const adc_module = module_inst->hw; + Assert(module_inst.hw); - while (adc_is_syncing(module_inst)) { - /* Wait for synchronization */ - } + Adc *const adc_module = module_inst.hw; - /* Set negative input pin */ - adc_module->INPUTCTRL.reg = - (adc_module->INPUTCTRL.reg & ~ADC_INPUTCTRL_MUXNEG_Msk) | - (negative_input << ADC_INPUTCTRL_MUXNEG_Pos); + while (adc_is_syncing()) { + /* Wait for synchronization */ + } + + /* Set negative input pin */ + adc_module->INPUTCTRL.reg = + (adc_module->INPUTCTRL.reg & ~ADC_INPUTCTRL_MUXNEG_Msk) | + (negative_input << ADC_INPUTCTRL_MUXNEG_Pos); } -/** @} */ - -#if ADC_CALLBACK_MODE == true -/** - * \name Enable and disable interrupts - * @{ - */ - /** * \brief Enable interrupt * @@ -1621,16 +1550,15 @@ static inline void adc_set_negative_input( * \param[in] module_inst Pointer to the ADC software instance struct * \param[in] interrupt Interrupt to enable */ -static inline void adc_enable_interrupt(struct adc_module *const module_inst, - enum adc_interrupt_flag interrupt) +static inline void adc_enable_interrupt(enum adc_interrupt_flag interrupt) { - /* Sanity check arguments */ - Assert(module_inst); - Assert(module_inst->hw); + /* Sanity check arguments */ - Adc *const adc_module = module_inst->hw; - /* Enable interrupt */ - adc_module->INTENSET.reg = interrupt; + Assert(module_inst.hw); + + Adc *const adc_module = module_inst.hw; + /* Enable interrupt */ + adc_module->INTENSET.reg = interrupt; } /** @@ -1641,18 +1569,110 @@ static inline void adc_enable_interrupt(struct adc_module *const module_inst, * \param[in] module_inst Pointer to the ADC software instance struct * \param[in] interrupt Interrupt to disable */ -static inline void adc_disable_interrupt(struct adc_module *const module_inst, - enum adc_interrupt_flag interrupt) +static inline void adc_disable_interrupt(enum adc_interrupt_flag interrupt) { - /* Sanity check arguments */ - Assert(module_inst); - Assert(module_inst->hw); + /* Sanity check arguments */ - Adc *const adc_module = module_inst->hw; - /* Enable interrupt */ - adc_module->INTENCLR.reg = interrupt; + Assert(module_inst.hw); + + Adc *const adc_module = module_inst.hw; + /* Enable interrupt */ + adc_module->INTENCLR.reg = interrupt; } +/** + * Enum for the possible types of ADC asynchronous jobs that may be issued to + * the driver. + */ +enum adc_job_type { + /** Asynchronous ADC read into a user provided buffer */ + ADC_JOB_READ_BUFFER, +}; + +/** + * Callback Management + */ +void adc_register_callback(adc_callback_t callback_func, + enum adc_callback callback_type); + +void adc_unregister_callback(enum adc_callback callback_type); + +/** + * \brief Enables callback + * + * Enables the callback function registered by \ref + * adc_register_callback. The callback function will be called from the + * interrupt handler when the conditions for the callback type are met. + * + * \param[in] module Pointer to ADC software instance struct + * \param[in] callback_type Callback type given by an enum + * + * \returns Status of the operation + * \retval STATUS_OK If operation was completed + * \retval STATUS_ERR_INVALID If operation was not completed, + * due to invalid callback_type + * + */ +static inline void adc_enable_callback(enum adc_callback callback_type) +{ + /* Enable callback */ + module_inst.enabled_callback_mask |= (1 << callback_type); + + /* Enable window interrupt if this is a window callback */ + if (callback_type == ADC_CALLBACK_WINDOW) { + adc_enable_interrupt(ADC_INTERRUPT_WINDOW); + } + /* Enable overrun interrupt if error callback is registered */ + if (callback_type == ADC_CALLBACK_ERROR) { + adc_enable_interrupt(ADC_INTERRUPT_OVERRUN); + } +} + +/** + * \brief Disables callback + * + * Disables the callback function registered by the \ref + * adc_register_callback. + * + * \param[in] module Pointer to ADC software instance struct + * \param[in] callback_type Callback type given by an enum + * + * \returns Status of the operation + * \retval STATUS_OK If operation was completed + * \retval STATUS_ERR_INVALID If operation was not completed, + * due to invalid callback_type + * + */ +static inline void adc_disable_callback(enum adc_callback callback_type) +{ + /* Sanity check arguments */ + + + /* Disable callback */ + module_inst.enabled_callback_mask &= ~(1 << callback_type); + + /* Disable window interrupt if this is a window callback */ + if (callback_type == ADC_CALLBACK_WINDOW) { + adc_disable_interrupt(ADC_INTERRUPT_WINDOW); + } + /* Disable overrun interrupt if this is the error callback */ + if (callback_type == ADC_CALLBACK_ERROR) { + adc_disable_interrupt(ADC_INTERRUPT_OVERRUN); + } +} + +/** + * Job Management + */ +enum adc_status_code adc_read_buffer_job(uint16_t *buffer, + uint16_t samples); + +enum adc_status_code adc_get_job_status(enum adc_job_type type); + +void adc_abort_job(enum adc_job_type type); + + + /** * \page asfdoc_sam0_adc_extra Extra Information for ADC Driver * @@ -1771,6 +1791,4 @@ static inline void adc_disable_interrupt(struct adc_module *const module_inst, * */ -#endif - #endif /* ADC_H_INCLUDED */ diff --git a/firmware/inc/analogue.h b/firmware/inc/analogue.h index 6977a15..7e4c9f6 100644 --- a/firmware/inc/analogue.h +++ b/firmware/inc/analogue.h @@ -25,7 +25,10 @@ #ifndef ANALOGUE_H #define ANALOGUE_H + +void start_adc_conversion_sequence(void); +uint8_t is_adc_conversion_done(void); float get_battery(void); -float get_temperature(void); +float get_solar(void); #endif /* ANALOGUE_H */ diff --git a/firmware/inc/hw_config.h b/firmware/inc/hw_config.h index 2703566..67a24c9 100644 --- a/firmware/inc/hw_config.h +++ b/firmware/inc/hw_config.h @@ -193,5 +193,6 @@ #define TC2_INT_PRIO 2 /* XOSC Measure Timer */ +#define ADC_INT_PRIO 2 /* ADC */ #endif /* HW_CONFIG_H */ diff --git a/firmware/src/adc/adc.c b/firmware/src/adc/adc.c index f779669..7dcf7fc 100644 --- a/firmware/src/adc/adc.c +++ b/firmware/src/adc/adc.c @@ -57,31 +57,31 @@ #endif /** -* \internal Configure MUX settings for the analog pins -* -* This function will set the given ADC input pins -* to the analog function in the pin mux, giving -* the ADC access to the analog signal -* -* \param [in] pin AINxx pin to configure -*/ + * \internal Configure MUX settings for the analog pins + * + * This function will set the given ADC input pins + * to the analog function in the pin mux, giving + * the ADC access to the analog signal + * + * \param [in] pin AINxx pin to configure + */ static inline void _adc_configure_ain_pin(uint32_t pin) { #define PIN_INVALID_ADC_AIN 0xFFFFUL - /* Pinmapping table for AINxx -> GPIO pin number */ - const uint32_t pinmapping[] = { + /* Pinmapping table for AINxx -> GPIO pin number */ + const uint32_t pinmapping[] = { //#if (SAMD20E | SAMD21E) - PIN_PA02B_ADC_AIN0, PIN_PA03B_ADC_AIN1, - PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, - PIN_PA04B_ADC_AIN4, PIN_PA05B_ADC_AIN5, - PIN_PA06B_ADC_AIN6, PIN_PA07B_ADC_AIN7, - PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, - PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, - PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, - PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, - PIN_PA08B_ADC_AIN16, PIN_PA09B_ADC_AIN17, - PIN_PA10B_ADC_AIN18, PIN_PA11B_ADC_AIN19, + PIN_PA02B_ADC_AIN0, PIN_PA03B_ADC_AIN1, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_PA04B_ADC_AIN4, PIN_PA05B_ADC_AIN5, + PIN_PA06B_ADC_AIN6, PIN_PA07B_ADC_AIN7, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, + PIN_PA08B_ADC_AIN16, PIN_PA09B_ADC_AIN17, + PIN_PA10B_ADC_AIN18, PIN_PA11B_ADC_AIN19, /* #elif (SAMD20G | SAMD21G) */ /* PIN_PA02B_ADC_AIN0, PIN_PA03B_ADC_AIN1, */ /* PIN_PB08B_ADC_AIN2, PIN_PB09B_ADC_AIN3, */ @@ -129,21 +129,21 @@ static inline void _adc_configure_ain_pin(uint32_t pin) /* #else */ /* # error ADC pin mappings are not defined for this device. */ /* #endif */ - }; + }; - uint32_t pin_map_result = PIN_INVALID_ADC_AIN; + uint32_t pin_map_result = PIN_INVALID_ADC_AIN; - if (pin <= ADC_EXTCHANNEL_MSB) { - pin_map_result = pinmapping[pin >> ADC_INPUTCTRL_MUXPOS_Pos]; + if (pin <= ADC_EXTCHANNEL_MSB) { + pin_map_result = pinmapping[pin >> ADC_INPUTCTRL_MUXPOS_Pos]; - Assert(pin_map_result != PIN_INVALID_ADC_AIN); + Assert(pin_map_result != PIN_INVALID_ADC_AIN); - system_pinmux_pin_set_config(pin_map_result, - 1, // B - SYSTEM_PINMUX_PIN_DIR_INPUT, - SYSTEM_PINMUX_PIN_PULL_NONE, - false); - } + system_pinmux_pin_set_config(pin_map_result, + 1, // B + SYSTEM_PINMUX_PIN_DIR_INPUT, + SYSTEM_PINMUX_PIN_PULL_NONE, + false); + } } /** @@ -158,313 +158,311 @@ static inline void _adc_configure_ain_pin(uint32_t pin) * \retval ADC_STATUS_OK The configuration was successful * \retval ADC_STATUS_ERR_INVALID_ARG Invalid argument(s) were provided */ -static enum adc_status_code _adc_set_config( - struct adc_module *const module_inst, - struct adc_config *const config) +static enum adc_status_code _adc_set_config(struct adc_config *const config) { - uint8_t adjres = 0; - uint32_t resolution = ADC_RESOLUTION_16BIT; - enum adc_accumulate_samples accumulate = ADC_ACCUMULATE_DISABLE; + uint8_t adjres = 0; + uint32_t resolution = ADC_RESOLUTION_16BIT; + enum adc_accumulate_samples accumulate = ADC_ACCUMULATE_DISABLE; #ifdef SAMD20 - uint8_t revision_num = ((REG_DSU_DID & DSU_DID_DIE_Msk) >> DSU_DID_DIE_Pos); + uint8_t revision_num = ((REG_DSU_DID & DSU_DID_DIE_Msk) >> DSU_DID_DIE_Pos); #endif - /* Get the hardware module pointer */ - Adc *const adc_module = module_inst->hw; + /* Get the hardware module pointer */ + Adc *const adc_module = module_inst.hw; - /* Configure GCLK channel and enable clock */ - system_gclk_chan_set_config(ADC_GCLK_ID, config->clock_source); - system_gclk_chan_enable(ADC_GCLK_ID); + /* Configure GCLK channel and enable clock */ + system_gclk_chan_set_config(ADC_GCLK_ID, config->clock_source); + system_gclk_chan_enable(ADC_GCLK_ID); - /* Setup pinmuxing for analog inputs */ - if (config->pin_scan.inputs_to_scan != 0) { - uint8_t offset = config->pin_scan.offset_start_scan; - uint8_t start_pin = - offset +(uint8_t)config->positive_input; - uint8_t end_pin = - start_pin + config->pin_scan.inputs_to_scan; + /* Setup pinmuxing for analog inputs */ + if (config->pin_scan.inputs_to_scan != 0) { + uint8_t offset = config->pin_scan.offset_start_scan; + uint8_t start_pin = + offset +(uint8_t)config->positive_input; + uint8_t end_pin = + start_pin + config->pin_scan.inputs_to_scan; - while (start_pin < end_pin) { - _adc_configure_ain_pin((offset % 16)+(uint8_t)config->positive_input); - start_pin++; - offset++; - } - _adc_configure_ain_pin(config->negative_input); - } else { - _adc_configure_ain_pin(config->positive_input); - _adc_configure_ain_pin(config->negative_input); - } + while (start_pin < end_pin) { + _adc_configure_ain_pin((offset % 16)+(uint8_t)config->positive_input); + start_pin++; + offset++; + } + _adc_configure_ain_pin(config->negative_input); + } else { + _adc_configure_ain_pin(config->positive_input); + _adc_configure_ain_pin(config->negative_input); + } - /* Configure run in standby */ - adc_module->CTRLA.reg = (config->run_in_standby << ADC_CTRLA_RUNSTDBY_Pos); + /* Configure run in standby */ + adc_module->CTRLA.reg = (config->run_in_standby << ADC_CTRLA_RUNSTDBY_Pos); - /* Configure reference */ - adc_module->REFCTRL.reg = - (config->reference_compensation_enable << ADC_REFCTRL_REFCOMP_Pos) | - (config->reference); + /* Configure reference */ + adc_module->REFCTRL.reg = + (config->reference_compensation_enable << ADC_REFCTRL_REFCOMP_Pos) | + (config->reference); - /* Set adjusting result and number of samples */ - switch (config->resolution) { + /* Set adjusting result and number of samples */ + switch (config->resolution) { - case ADC_RESOLUTION_CUSTOM: - adjres = config->divide_result; - accumulate = config->accumulate_samples; - /* 16-bit result register */ - resolution = ADC_RESOLUTION_16BIT; - break; + case ADC_RESOLUTION_CUSTOM: + adjres = config->divide_result; + accumulate = config->accumulate_samples; + /* 16-bit result register */ + resolution = ADC_RESOLUTION_16BIT; + break; - case ADC_RESOLUTION_13BIT: - /* Increase resolution by 1 bit */ - adjres = ADC_DIVIDE_RESULT_2; - accumulate = ADC_ACCUMULATE_SAMPLES_4; - /* 16-bit result register */ - resolution = ADC_RESOLUTION_16BIT; - break; + case ADC_RESOLUTION_13BIT: + /* Increase resolution by 1 bit */ + adjres = ADC_DIVIDE_RESULT_2; + accumulate = ADC_ACCUMULATE_SAMPLES_4; + /* 16-bit result register */ + resolution = ADC_RESOLUTION_16BIT; + break; - case ADC_RESOLUTION_14BIT: - /* Increase resolution by 2 bit */ - adjres = ADC_DIVIDE_RESULT_4; - accumulate = ADC_ACCUMULATE_SAMPLES_16; - /* 16-bit result register */ - resolution = ADC_RESOLUTION_16BIT; - break; + case ADC_RESOLUTION_14BIT: + /* Increase resolution by 2 bit */ + adjres = ADC_DIVIDE_RESULT_4; + accumulate = ADC_ACCUMULATE_SAMPLES_16; + /* 16-bit result register */ + resolution = ADC_RESOLUTION_16BIT; + break; #ifdef SAMD20 - /* Please see $35.1.8 for ADC errata of SAM D20. - The revisions before D have this issue.*/ - case ADC_RESOLUTION_15BIT: - /* Increase resolution by 3 bit */ - if(revision_num < REVISON_D_NUM) { - adjres = ADC_DIVIDE_RESULT_8; - } else { - adjres = ADC_DIVIDE_RESULT_2; - } - accumulate = ADC_ACCUMULATE_SAMPLES_64; - /* 16-bit result register */ - resolution = ADC_RESOLUTION_16BIT; - break; + /* Please see $35.1.8 for ADC errata of SAM D20. + The revisions before D have this issue.*/ + case ADC_RESOLUTION_15BIT: + /* Increase resolution by 3 bit */ + if(revision_num < REVISON_D_NUM) { + adjres = ADC_DIVIDE_RESULT_8; + } else { + adjres = ADC_DIVIDE_RESULT_2; + } + accumulate = ADC_ACCUMULATE_SAMPLES_64; + /* 16-bit result register */ + resolution = ADC_RESOLUTION_16BIT; + break; - case ADC_RESOLUTION_16BIT: - if(revision_num < REVISON_D_NUM) { - /* Increase resolution by 4 bit */ - adjres = ADC_DIVIDE_RESULT_16; - } else { - adjres = ADC_DIVIDE_RESULT_DISABLE; - } - accumulate = ADC_ACCUMULATE_SAMPLES_256; - /* 16-bit result register */ - resolution = ADC_RESOLUTION_16BIT; - break; + case ADC_RESOLUTION_16BIT: + if(revision_num < REVISON_D_NUM) { + /* Increase resolution by 4 bit */ + adjres = ADC_DIVIDE_RESULT_16; + } else { + adjres = ADC_DIVIDE_RESULT_DISABLE; + } + accumulate = ADC_ACCUMULATE_SAMPLES_256; + /* 16-bit result register */ + resolution = ADC_RESOLUTION_16BIT; + break; #else - case ADC_RESOLUTION_15BIT: - /* Increase resolution by 3 bit */ - adjres = ADC_DIVIDE_RESULT_2; - accumulate = ADC_ACCUMULATE_SAMPLES_64; - /* 16-bit result register */ - resolution = ADC_RESOLUTION_16BIT; - break; + case ADC_RESOLUTION_15BIT: + /* Increase resolution by 3 bit */ + adjres = ADC_DIVIDE_RESULT_2; + accumulate = ADC_ACCUMULATE_SAMPLES_64; + /* 16-bit result register */ + resolution = ADC_RESOLUTION_16BIT; + break; - case ADC_RESOLUTION_16BIT: - /* Increase resolution by 4 bit */ - adjres = ADC_DIVIDE_RESULT_DISABLE; - accumulate = ADC_ACCUMULATE_SAMPLES_256; - /* 16-bit result register */ - resolution = ADC_RESOLUTION_16BIT; - break; + case ADC_RESOLUTION_16BIT: + /* Increase resolution by 4 bit */ + adjres = ADC_DIVIDE_RESULT_DISABLE; + accumulate = ADC_ACCUMULATE_SAMPLES_256; + /* 16-bit result register */ + resolution = ADC_RESOLUTION_16BIT; + break; #endif - case ADC_RESOLUTION_8BIT: - /* 8-bit result register */ - resolution = ADC_RESOLUTION_8BIT; - break; - case ADC_RESOLUTION_10BIT: - /* 10-bit result register */ - resolution = ADC_RESOLUTION_10BIT; - break; - case ADC_RESOLUTION_12BIT: - /* 12-bit result register */ - resolution = ADC_RESOLUTION_12BIT; - break; + case ADC_RESOLUTION_8BIT: + /* 8-bit result register */ + resolution = ADC_RESOLUTION_8BIT; + break; + case ADC_RESOLUTION_10BIT: + /* 10-bit result register */ + resolution = ADC_RESOLUTION_10BIT; + break; + case ADC_RESOLUTION_12BIT: + /* 12-bit result register */ + resolution = ADC_RESOLUTION_12BIT; + break; - default: - /* Unknown. Abort. */ - return ADC_STATUS_ERR_INVALID_ARG; - } + default: + /* Unknown. Abort. */ + return ADC_STATUS_ERR_INVALID_ARG; + } - adc_module->AVGCTRL.reg = ADC_AVGCTRL_ADJRES(adjres) | accumulate; + adc_module->AVGCTRL.reg = ADC_AVGCTRL_ADJRES(adjres) | accumulate; - /* Check validity of sample length value */ - if (config->sample_length > 63) { - return ADC_STATUS_ERR_INVALID_ARG; - } else { - /* Configure sample length */ - adc_module->SAMPCTRL.reg = - (config->sample_length << ADC_SAMPCTRL_SAMPLEN_Pos); - } + /* Check validity of sample length value */ + if (config->sample_length > 63) { + return ADC_STATUS_ERR_INVALID_ARG; + } else { + /* Configure sample length */ + adc_module->SAMPCTRL.reg = + (config->sample_length << ADC_SAMPCTRL_SAMPLEN_Pos); + } - while (adc_is_syncing(module_inst)) { - /* Wait for synchronization */ - } + while (adc_is_syncing()) { + /* Wait for synchronization */ + } - /* Configure CTRLB */ - adc_module->CTRLB.reg = - config->clock_prescaler | - resolution | - (config->correction.correction_enable << ADC_CTRLB_CORREN_Pos) | - (config->freerunning << ADC_CTRLB_FREERUN_Pos) | - (config->left_adjust << ADC_CTRLB_LEFTADJ_Pos) | - (config->differential_mode << ADC_CTRLB_DIFFMODE_Pos); + /* Configure CTRLB */ + adc_module->CTRLB.reg = + config->clock_prescaler | + resolution | + (config->correction.correction_enable << ADC_CTRLB_CORREN_Pos) | + (config->freerunning << ADC_CTRLB_FREERUN_Pos) | + (config->left_adjust << ADC_CTRLB_LEFTADJ_Pos) | + (config->differential_mode << ADC_CTRLB_DIFFMODE_Pos); - /* Check validity of window thresholds */ - if (config->window.window_mode != ADC_WINDOW_MODE_DISABLE) { - switch (resolution) { - case ADC_RESOLUTION_8BIT: - if (config->differential_mode && - (config->window.window_lower_value > 127 || - config->window.window_lower_value < -128 || - config->window.window_upper_value > 127 || - config->window.window_upper_value < -128)) { - /* Invalid value */ - return ADC_STATUS_ERR_INVALID_ARG; - } else if (config->window.window_lower_value > 255 || - config->window.window_upper_value > 255){ - /* Invalid value */ - return ADC_STATUS_ERR_INVALID_ARG; - } - break; - case ADC_RESOLUTION_10BIT: - if (config->differential_mode && - (config->window.window_lower_value > 511 || - config->window.window_lower_value < -512 || - config->window.window_upper_value > 511 || - config->window.window_upper_value > -512)) { - /* Invalid value */ - return ADC_STATUS_ERR_INVALID_ARG; - } else if (config->window.window_lower_value > 1023 || - config->window.window_upper_value > 1023){ - /* Invalid value */ - return ADC_STATUS_ERR_INVALID_ARG; - } - break; - case ADC_RESOLUTION_12BIT: - if (config->differential_mode && - (config->window.window_lower_value > 2047 || - config->window.window_lower_value < -2048 || - config->window.window_upper_value > 2047 || - config->window.window_upper_value < -2048)) { - /* Invalid value */ - return ADC_STATUS_ERR_INVALID_ARG; - } else if (config->window.window_lower_value > 4095 || - config->window.window_upper_value > 4095){ - /* Invalid value */ - return ADC_STATUS_ERR_INVALID_ARG; - } - break; - case ADC_RESOLUTION_16BIT: - if (config->differential_mode && - (config->window.window_lower_value > 32767 || - config->window.window_lower_value < -32768 || - config->window.window_upper_value > 32767 || - config->window.window_upper_value < -32768)) { - /* Invalid value */ - return ADC_STATUS_ERR_INVALID_ARG; - } else if (config->window.window_lower_value > 65535 || - config->window.window_upper_value > 65535){ - /* Invalid value */ - return ADC_STATUS_ERR_INVALID_ARG; - } - break; - } - } + /* Check validity of window thresholds */ + if (config->window.window_mode != ADC_WINDOW_MODE_DISABLE) { + switch (resolution) { + case ADC_RESOLUTION_8BIT: + if (config->differential_mode && + (config->window.window_lower_value > 127 || + config->window.window_lower_value < -128 || + config->window.window_upper_value > 127 || + config->window.window_upper_value < -128)) { + /* Invalid value */ + return ADC_STATUS_ERR_INVALID_ARG; + } else if (config->window.window_lower_value > 255 || + config->window.window_upper_value > 255){ + /* Invalid value */ + return ADC_STATUS_ERR_INVALID_ARG; + } + break; + case ADC_RESOLUTION_10BIT: + if (config->differential_mode && + (config->window.window_lower_value > 511 || + config->window.window_lower_value < -512 || + config->window.window_upper_value > 511 || + config->window.window_upper_value > -512)) { + /* Invalid value */ + return ADC_STATUS_ERR_INVALID_ARG; + } else if (config->window.window_lower_value > 1023 || + config->window.window_upper_value > 1023){ + /* Invalid value */ + return ADC_STATUS_ERR_INVALID_ARG; + } + break; + case ADC_RESOLUTION_12BIT: + if (config->differential_mode && + (config->window.window_lower_value > 2047 || + config->window.window_lower_value < -2048 || + config->window.window_upper_value > 2047 || + config->window.window_upper_value < -2048)) { + /* Invalid value */ + return ADC_STATUS_ERR_INVALID_ARG; + } else if (config->window.window_lower_value > 4095 || + config->window.window_upper_value > 4095){ + /* Invalid value */ + return ADC_STATUS_ERR_INVALID_ARG; + } + break; + case ADC_RESOLUTION_16BIT: + if (config->differential_mode && + (config->window.window_lower_value > 32767 || + config->window.window_lower_value < -32768 || + config->window.window_upper_value > 32767 || + config->window.window_upper_value < -32768)) { + /* Invalid value */ + return ADC_STATUS_ERR_INVALID_ARG; + } else if (config->window.window_lower_value > 65535 || + config->window.window_upper_value > 65535){ + /* Invalid value */ + return ADC_STATUS_ERR_INVALID_ARG; + } + break; + } + } - while (adc_is_syncing(module_inst)) { - /* Wait for synchronization */ - } + while (adc_is_syncing()) { + /* Wait for synchronization */ + } - /* Configure window mode */ - adc_module->WINCTRL.reg = config->window.window_mode; + /* Configure window mode */ + adc_module->WINCTRL.reg = config->window.window_mode; - while (adc_is_syncing(module_inst)) { - /* Wait for synchronization */ - } + while (adc_is_syncing()) { + /* Wait for synchronization */ + } - /* Configure lower threshold */ - adc_module->WINLT.reg = - config->window.window_lower_value << ADC_WINLT_WINLT_Pos; + /* Configure lower threshold */ + adc_module->WINLT.reg = + config->window.window_lower_value << ADC_WINLT_WINLT_Pos; - while (adc_is_syncing(module_inst)) { - /* Wait for synchronization */ - } + while (adc_is_syncing()) { + /* Wait for synchronization */ + } - /* Configure lower threshold */ - adc_module->WINUT.reg = config->window.window_upper_value << - ADC_WINUT_WINUT_Pos; + /* Configure lower threshold */ + adc_module->WINUT.reg = config->window.window_upper_value << + ADC_WINUT_WINUT_Pos; - uint8_t inputs_to_scan = config->pin_scan.inputs_to_scan; - if (inputs_to_scan > 0) { - /* - * Number of input sources included is the value written to INPUTSCAN - * plus 1. - */ - inputs_to_scan--; - } + uint8_t inputs_to_scan = config->pin_scan.inputs_to_scan; + if (inputs_to_scan > 0) { + /* + * Number of input sources included is the value written to INPUTSCAN + * plus 1. + */ + inputs_to_scan--; + } - if (inputs_to_scan > (ADC_INPUTCTRL_INPUTSCAN_Msk >> ADC_INPUTCTRL_INPUTSCAN_Pos) || - config->pin_scan.offset_start_scan > (ADC_INPUTCTRL_INPUTOFFSET_Msk >> ADC_INPUTCTRL_INPUTOFFSET_Pos)) { - /* Invalid number of input pins or input offset */ - return ADC_STATUS_ERR_INVALID_ARG; - } + if (inputs_to_scan > (ADC_INPUTCTRL_INPUTSCAN_Msk >> ADC_INPUTCTRL_INPUTSCAN_Pos) || + config->pin_scan.offset_start_scan > (ADC_INPUTCTRL_INPUTOFFSET_Msk >> ADC_INPUTCTRL_INPUTOFFSET_Pos)) { + /* Invalid number of input pins or input offset */ + return ADC_STATUS_ERR_INVALID_ARG; + } - while (adc_is_syncing(module_inst)) { - /* Wait for synchronization */ - } + while (adc_is_syncing()) { + /* Wait for synchronization */ + } - /* Configure pin scan mode and positive and negative input pins */ - adc_module->INPUTCTRL.reg = - config->gain_factor | - (config->pin_scan.offset_start_scan << - ADC_INPUTCTRL_INPUTOFFSET_Pos) | - (inputs_to_scan << ADC_INPUTCTRL_INPUTSCAN_Pos) | - config->negative_input | - config->positive_input; + /* Configure pin scan mode and positive and negative input pins */ + adc_module->INPUTCTRL.reg = + config->gain_factor | + (config->pin_scan.offset_start_scan << + ADC_INPUTCTRL_INPUTOFFSET_Pos) | + (inputs_to_scan << ADC_INPUTCTRL_INPUTSCAN_Pos) | + config->negative_input | + config->positive_input; - /* Configure events */ - adc_module->EVCTRL.reg = config->event_action; + /* Configure events */ + adc_module->EVCTRL.reg = config->event_action; - /* Disable all interrupts */ - adc_module->INTENCLR.reg = - (1 << ADC_INTENCLR_SYNCRDY_Pos) | (1 << ADC_INTENCLR_WINMON_Pos) | - (1 << ADC_INTENCLR_OVERRUN_Pos) | (1 << ADC_INTENCLR_RESRDY_Pos); + /* Disable all interrupts */ + adc_module->INTENCLR.reg = + (1 << ADC_INTENCLR_SYNCRDY_Pos) | (1 << ADC_INTENCLR_WINMON_Pos) | + (1 << ADC_INTENCLR_OVERRUN_Pos) | (1 << ADC_INTENCLR_RESRDY_Pos); - if (config->correction.correction_enable){ - /* Make sure gain_correction value is valid */ - if (config->correction.gain_correction > ADC_GAINCORR_GAINCORR_Msk) { - return ADC_STATUS_ERR_INVALID_ARG; - } else { - /* Set gain correction value */ - adc_module->GAINCORR.reg = config->correction.gain_correction << - ADC_GAINCORR_GAINCORR_Pos; - } + if (config->correction.correction_enable){ + /* Make sure gain_correction value is valid */ + if (config->correction.gain_correction > ADC_GAINCORR_GAINCORR_Msk) { + return ADC_STATUS_ERR_INVALID_ARG; + } else { + /* Set gain correction value */ + adc_module->GAINCORR.reg = config->correction.gain_correction << + ADC_GAINCORR_GAINCORR_Pos; + } - /* Make sure offset correction value is valid */ - if (config->correction.offset_correction > 2047 || - config->correction.offset_correction < -2048) { - return ADC_STATUS_ERR_INVALID_ARG; - } else { - /* Set offset correction value */ - adc_module->OFFSETCORR.reg = config->correction.offset_correction << - ADC_OFFSETCORR_OFFSETCORR_Pos; - } - } + /* Make sure offset correction value is valid */ + if (config->correction.offset_correction > 2047 || + config->correction.offset_correction < -2048) { + return ADC_STATUS_ERR_INVALID_ARG; + } else { + /* Set offset correction value */ + adc_module->OFFSETCORR.reg = config->correction.offset_correction << + ADC_OFFSETCORR_OFFSETCORR_Pos; + } + } - /* Load in the fixed device ADC calibration constants */ - adc_module->CALIB.reg = - ADC_CALIB_BIAS_CAL( - (*(uint32_t *)ADC_FUSES_BIASCAL_ADDR >> ADC_FUSES_BIASCAL_Pos) - ) | - ADC_CALIB_LINEARITY_CAL( - (*(uint64_t *)ADC_FUSES_LINEARITY_0_ADDR >> ADC_FUSES_LINEARITY_0_Pos) - ); + /* Load in the fixed device ADC calibration constants */ + adc_module->CALIB.reg = + ADC_CALIB_BIAS_CAL( + (*(uint32_t *)ADC_FUSES_BIASCAL_ADDR >> ADC_FUSES_BIASCAL_Pos) + ) | + ADC_CALIB_LINEARITY_CAL( + (*(uint64_t *)ADC_FUSES_LINEARITY_0_ADDR >> ADC_FUSES_LINEARITY_0_Pos) + ); - return ADC_STATUS_OK; + return ADC_STATUS_OK; } /** @@ -483,55 +481,191 @@ static enum adc_status_code _adc_set_config( * \retval ADC_STATUS_BUSY The module is busy with a reset operation * \retval ADC_STATUS_ERR_DENIED The module is enabled */ -enum adc_status_code adc_init( - struct adc_module *const module_inst, - Adc *hw, - struct adc_config *config) +enum adc_status_code adc_init(Adc *hw, + struct adc_config *config) { - /* Sanity check arguments */ - Assert(module_inst); - Assert(hw); - Assert(config); + /* Sanity check arguments */ - /* Associate the software module instance with the hardware module */ - module_inst->hw = hw; + Assert(hw); + Assert(config); - /* Turn on the digital interface clock */ - system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, PM_APBCMASK_ADC); + /* Associate the software module instance with the hardware module */ + module_inst.hw = hw; - if (hw->CTRLA.reg & ADC_CTRLA_SWRST) { - /* We are in the middle of a reset. Abort. */ - return ADC_STATUS_BUSY; - } + /* Turn on the digital interface clock */ + system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, PM_APBCMASK_ADC); - if (hw->CTRLA.reg & ADC_CTRLA_ENABLE) { - /* Module must be disabled before initialization. Abort. */ - return ADC_STATUS_ERR_DENIED; - } + if (hw->CTRLA.reg & ADC_CTRLA_SWRST) { + /* We are in the middle of a reset. Abort. */ + return ADC_STATUS_BUSY; + } - /* Store the selected reference for later use */ - module_inst->reference = config->reference; + if (hw->CTRLA.reg & ADC_CTRLA_ENABLE) { + /* Module must be disabled before initialization. Abort. */ + return ADC_STATUS_ERR_DENIED; + } -#if ADC_CALLBACK_MODE == true - for (uint8_t i = 0; i < ADC_CALLBACK_N; i++) { - module_inst->callback[i] = NULL; - }; + /* Store the selected reference for later use */ + module_inst.reference = config->reference; - module_inst->registered_callback_mask = 0; - module_inst->enabled_callback_mask = 0; - module_inst->remaining_conversions = 0; - module_inst->job_status = ADC_STATUS_OK; + for (uint8_t i = 0; i < ADC_CALLBACK_N; i++) { + module_inst.callback[i] = NULL; + }; - _adc_instances[0] = module_inst; + module_inst.registered_callback_mask = 0; + module_inst.enabled_callback_mask = 0; + module_inst.remaining_conversions = 0; + module_inst.job_status = ADC_STATUS_OK; - if (config->event_action == ADC_EVENT_ACTION_DISABLED && - !config->freerunning) { - module_inst->software_trigger = true; - } else { - module_inst->software_trigger = false; - } -#endif + if (config->event_action == ADC_EVENT_ACTION_DISABLED && + !config->freerunning) { + module_inst.software_trigger = true; + } else { + module_inst.software_trigger = false; + } - /* Write configuration to module */ - return _adc_set_config(module_inst, config); + /* Write configuration to module */ + return _adc_set_config(config); +} + +/** Interrupt handler for the ADC module. */ +void ADC_Handler(void) +{ + /* get interrupt flags and mask out enabled callbacks */ + uint32_t flags = module_inst.hw->INTFLAG.reg; + + if (flags & ADC_INTFLAG_RESRDY) { + /* job is complete. update status,disable interrupt + * and call callback */ + module_inst.job_status = ADC_STATUS_OK; + adc_disable_interrupt(ADC_INTERRUPT_RESULT_READY); + + (module_inst.callback[ADC_CALLBACK_READ_BUFFER])(); + } + + if (flags & ADC_INTFLAG_WINMON) { + module_inst.hw->INTFLAG.reg = ADC_INTFLAG_WINMON; + if ((module_inst.enabled_callback_mask & (1 << ADC_CALLBACK_WINDOW)) && + (module_inst.registered_callback_mask & (1 << ADC_CALLBACK_WINDOW))) { + (module_inst.callback[ADC_CALLBACK_WINDOW])(); + } + + } + + if (flags & ADC_INTFLAG_OVERRUN) { + module_inst.hw->INTFLAG.reg = ADC_INTFLAG_OVERRUN; + if ((module_inst.enabled_callback_mask & (1 << ADC_CALLBACK_ERROR)) && + (module_inst.registered_callback_mask & (1 << ADC_CALLBACK_ERROR))) { + (module_inst.callback[ADC_CALLBACK_ERROR])(); + } + } +} + +/** + * \brief Registers a callback + * + * Registers a callback function which is implemented by the user. + * + * \note The callback must be enabled by for the interrupt handler to call it + * when the condition for the callback is met. + * + * \param[in] module Pointer to ADC software instance struct + * \param[in] callback_func Pointer to callback function + * \param[in] callback_type Callback type given by an enum + * + */ +void adc_register_callback( + adc_callback_t callback_func, + enum adc_callback callback_type) +{ + /* Sanity check arguments */ + Assert(callback_func); + + /* Register callback function */ + module_inst.callback[callback_type] = callback_func; + + /* Set the bit corresponding to the callback_type */ + module_inst.registered_callback_mask |= (1 << callback_type); +} + +/** + * \brief Unregisters a callback + * + * Unregisters a callback function which is implemented by the user. + * + * \param[in] module Pointer to ADC software instance struct + * \param[in] callback_type Callback type given by an enum + * + */ +void adc_unregister_callback( + enum adc_callback callback_type) +{ + /* Unregister callback function */ + module_inst.callback[callback_type] = NULL; + + /* Clear the bit corresponding to the callback_type */ + module_inst.registered_callback_mask &= ~(1 << callback_type); +} + +/** + * \brief Read multiple samples from ADC + * + * Read \c samples samples from the ADC into the buffer \c buffer. + * If there is no hardware trigger defined (event action) the + * driver will retrigger the ADC conversion whenever a conversion + * is complete until \c samples samples has been acquired. To avoid + * jitter in the sampling frequency using an event trigger is advised. + * + * \param[in] module_inst Pointer to the ADC software instance struct + * \param[in] samples Number of samples to acquire + * \param[out] buffer Buffer to store the ADC samples + * + * \return Status of the job start + * \retval STATUS_OK The conversion job was started successfully and is + * in progress + * \retval STATUS_BUSY The ADC is already busy with another job + */ +enum adc_status_code adc_read_buffer_job( + uint16_t *buffer, + uint16_t samples) +{ + Assert(samples); + Assert(buffer); + + if(module_inst.remaining_conversions != 0 || + module_inst.job_status == ADC_STATUS_BUSY){ + return ADC_STATUS_BUSY; + } + + module_inst.job_status = ADC_STATUS_BUSY; + module_inst.remaining_conversions = samples; + module_inst.job_buffer = buffer; + + adc_enable_interrupt(ADC_INTERRUPT_RESULT_READY); + + if(module_inst.software_trigger == true) { + adc_start_conversion(); + } + + return ADC_STATUS_OK; +} + +/** + * \brief Gets the status of a job + * + * Gets the status of an ongoing or the last job. + * + * \param [in] module_inst Pointer to the ADC software instance struct + * \param [in] type Type of job to abort + * + * \return Status of the job + */ +enum adc_status_code adc_get_job_status( + enum adc_job_type type) +{ + if (type == ADC_JOB_READ_BUFFER ) { + return module_inst.job_status; + } else { + return ADC_STATUS_ERR_INVALID_ARG; + } } diff --git a/firmware/src/analogue.c b/firmware/src/analogue.c index 2d97081..048941a 100644 --- a/firmware/src/analogue.c +++ b/firmware/src/analogue.c @@ -24,54 +24,112 @@ #include "samd20.h" #include "adc/adc.h" +#include "system/interrupt.h" #include "hw_config.h" -struct adc_module adc_instance; +float battery_v, solar_v; -#define TEMP_ADC ADC_POSITIVE_INPUT_TEMP +#define ADC_GAINF ADC_GAIN_FACTOR_DIV2 +#define ADC_GAINF_VAL 0.5 +#define ADC_RESOLUTION ADC_RESOLUTION_12BIT +#define ADC_RESOLUTION_VAL 4096 + +enum { + ADC_PHASE_NONE, + ADC_PHASE_CONVERT_BATTERY, + ADC_PHASE_CONVERT_SOLAR, + ADC_PHASE_DONE, +} adc_phase = ADC_PHASE_NONE; + +void adc_complete_callback(void); void configure_adc(enum adc_positive_input input) { struct adc_config config_adc; adc_get_config_defaults(&config_adc); + config_adc.clock_source = GCLK_GENERATOR_0; config_adc.reference = ADC_REFERENCE_INT1V; + config_adc.clock_prescaler = ADC_CLOCK_PRESCALER_DIV64; + config_adc.resolution = ADC_RESOLUTION; config_adc.gain_factor = ADC_GAIN_FACTOR_DIV2; config_adc.positive_input = input; + config_adc.accumulate_samples = ADC_ACCUMULATE_DISABLE; + config_adc.run_in_standby = true; - adc_init(&adc_instance, ADC, &config_adc); - adc_enable(&adc_instance); + adc_init(ADC, &config_adc); + adc_enable(); + + adc_register_callback(adc_complete_callback, ADC_CALLBACK_READ_BUFFER); + adc_enable_interrupt(ADC_INTERRUPT_RESULT_READY); + + irq_register_handler(ADC_IRQn, ADC_INT_PRIO); } +/** + * Called on a ADC result ready event + */ +void adc_complete_callback(void) { + uint16_t result; + float pin_v; + + adc_read(&result); + pin_v = (float)result / (ADC_GAINF_VAL * ADC_RESOLUTION_VAL); + + if (adc_phase == ADC_PHASE_CONVERT_BATTERY) { + /* Battery */ + + /* Calcuate the battery votage */ + battery_v = pin_v / BATTERY_ADC_CHANNEL_DIV; + + /* Next up: Solar */ + configure_adc(SOLAR_ADC_CHANNEL); + adc_start_conversion(); + } else { + + /* Solar */ + + /* Calculate the solar voltage */ + solar_v = pin_v / SOLAR_ADC_CHANNEL_DIV; + } + + adc_phase++; +} + +void start_adc_conversion_sequence(void) +{ + /* First up: Battery */ + configure_adc(BATTERY_ADC_CHANNEL); + adc_start_conversion(); + adc_phase = ADC_PHASE_CONVERT_BATTERY; +} +uint8_t is_adc_conversion_done(void) { + return (adc_phase == ADC_PHASE_DONE); +} float get_battery(void) { - configure_adc(BATTERY_ADC_CHANNEL); - adc_start_conversion(&adc_instance); - - uint16_t result; - - do { - /* Wait for conversion to be done and read out result */ - } while (adc_read(&adc_instance, &result) == ADC_STATUS_BUSY); - - /* 12-bit, 1V ref, div 2 */ - return (float)(result * 2) / (4096 * BATTERY_ADC_CHANNEL_DIV); + return battery_v; } -float get_temperature(void) +float get_solar(void) { - configure_adc(TEMP_ADC); - adc_start_conversion(&adc_instance); - - uint16_t result; - - do { - /* Wait for conversion to be done and read out result */ - } while (adc_read(&adc_instance, &result) == ADC_STATUS_BUSY); - - /* 12-bit, 1V ref, div 2 */ - float voltage = (float)(result * 2) / 4096; - float millivolt_offset = (voltage - 0.667) * 1000; - - /* Temperature? Uncalibrated.. */ - return 25 + (millivolt_offset / 2.4); + return solar_v; } + +/* float get_temperature(void) */ +/* { */ +/* configure_adc(TEMP_ADC); */ +/* adc_start_conversion(&adc_instance); */ + +/* uint16_t result; */ + +/* do { */ +/* /\* Wait for conversion to be done and read out result *\/ */ +/* } while (adc_read(&adc_instance, &result) == ADC_STATUS_BUSY); */ + +/* /\* 12-bit, 1V ref, div 2 *\/ */ +/* float voltage = (float)(result * 2) / 4096; */ +/* float millivolt_offset = (voltage - 0.667) * 1000; */ + +/* /\* Temperature? Uncalibrated.. *\/ */ +/* return 25 + (millivolt_offset / 2.4); */ +/* } */ diff --git a/firmware/src/data.c b/firmware/src/data.c index 7bd69c4..4213cc7 100644 --- a/firmware/src/data.c +++ b/firmware/src/data.c @@ -59,6 +59,7 @@ struct tracker_datapoint* collect_data(void) * ---- Analogue ---- */ datapoint.battery = get_battery(); + datapoint.solar = get_solar(); datapoint.temperature = telemetry_si_temperature(); diff --git a/firmware/test/tc/adc_battery_solar_read.h b/firmware/test/tc/adc_battery_solar_read.h new file mode 100644 index 0000000..24efb8f --- /dev/null +++ b/firmware/test/tc/adc_battery_solar_read.h @@ -0,0 +1,41 @@ +#ifndef __verification__ +#define __verification__ +#endif + +/****************************//* adc_battery_solar_read_tc *//****************************/ +/** + * Write a description of your test case here + */ +#include "analogue.h" + +/* Parameters in */ +struct adc_battery_solar_read_tc_params { + + /* Input paramters to your test case go here */ + uint32_t dummy; + +} adc_battery_solar_read_tc_params; +/* Results out */ +struct adc_battery_solar_read_tc_results { + + /* Result values should be populated here */ + float battery; + float solar; + +} adc_battery_solar_read_tc_results; +/* Function */ +__verification__ void adc_battery_solar_read_tc(void) { + + /** + * The main body of the test case goes here. + * + * Use the input parameters to run the test case. Populate the + * results structure at the end + */ + + start_adc_conversion_sequence(); + while (!is_adc_conversion_done()); + + adc_battery_solar_read_tc_results.battery = get_battery(); + adc_battery_solar_read_tc_results.solar = get_solar(); +} diff --git a/firmware/test/tc/adc_battery_solar_read.py b/firmware/test/tc/adc_battery_solar_read.py new file mode 100644 index 0000000..622c600 --- /dev/null +++ b/firmware/test/tc/adc_battery_solar_read.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python + +# ------------------------------------------------------------------------------ +# Imports +# ------------------------------------------------------------------------------ + +import sys +sys.path.append("./test") +import main + +from random import randint + +# ------------------------------------------------------------------------------ +# Test Script +# ------------------------------------------------------------------------------ + +class adc_battery_solar_read_tc: + def __init__(self): + self.name = self.__class__.__name__ + self.iterations = 20 + + + def get_test(self): + """Returns some suitable test parameters""" + params = main.struct_adc_battery_solar_read_tc_params() + + """ + Assign input parameters here + """ + + return params + + def is_correct(self, params, result, print_info): + """Returns if a result is correct for the given parameters""" + + """ + Compare result and params here, decide sth. + Can use print_info + """ + print_info("Battery: {}V".format(result["battery"])) + print_info("Solar: {}V".format(result["solar"])) + + return True diff --git a/firmware/test/tmain.c b/firmware/test/tmain.c index 37feadf..7e679b4 100644 --- a/firmware/test/tmain.c +++ b/firmware/test/tmain.c @@ -44,6 +44,7 @@ #include "location_aprs_file.h" #include "backlog_write_read.h" #include "mem_erase_all.h" +#include "adc_battery_solar_read.h" /* [new_tc] */