00001
00038 #ifndef ADC_H
00039 #define ADC_H
00040
00041 #include <compiler.h>
00042 #include <conf_adc.h>
00043 #include <conf_intlvl.h>
00044 #include <nvm.h>
00045 #include <parts.h>
00046 #include <sleepmgr.h>
00047 #include <sysclk.h>
00048
00049 #ifdef __cplusplus
00050 extern "C" {
00051 #endif
00052
00103 #if XMEGA_A
00104 # define ADC_NR_OF_CHANNELS 4
00105 #elif XMEGA_D
00106 # define ADC_NR_OF_CHANNELS 1
00107 #endif
00108
00110 struct adc_config {
00111 #if XMEGA_A
00112 uint8_t ctrla;
00113 #endif
00114 uint8_t ctrlb;
00115 uint8_t refctrl;
00116 uint8_t evctrl;
00117 uint8_t prescaler;
00118 uint16_t cmp;
00119 };
00120
00127
00129 #define ADCACAL0 offsetof(NVM_PROD_SIGNATURES_t, ADCACAL0)
00130
00131 #define ADCACAL1 offsetof(NVM_PROD_SIGNATURES_t, ADCACAL1)
00132
00133 #define ADCBCAL0 offsetof(NVM_PROD_SIGNATURES_t, ADCBCAL0)
00134
00135 #define ADCBCAL1 offsetof(NVM_PROD_SIGNATURES_t, ADCBCAL1)
00136
00137 #define TEMPSENSE0 offsetof(NVM_PROD_SIGNATURES_t, TEMPSENSE0)
00138
00139 #define TEMPSENSE1 offsetof(NVM_PROD_SIGNATURES_t, TEMPSENSE1)
00140
00142
00144 enum adc_calibration_data {
00145 ADC_CAL_ADCA,
00146 ADC_CAL_ADCB,
00147
00152 ADC_CAL_TEMPSENSE,
00153 };
00154
00156
00157
00158 #define ADC_CH0 (1U << 0) //!< ADC channel 0.
00159
00160 #if XMEGA_A
00161 # define ADC_CH1 (1U << 1) //!< ADC channel 1.
00162 # define ADC_CH2 (1U << 2) //!< ADC channel 2.
00163 # define ADC_CH3 (1U << 3) //!< ADC channel 3.
00164 #endif
00165
00167
00169
00170
00171 #define ADC_INT_TEMPSENSE ADC_TEMPREF_bm //!< Temperature sensor.
00172 #define ADC_INT_BANDGAP ADC_BANDGAP_bm //!< Bandgap reference.
00173
00175
00182 enum adc_trigger {
00184 ADC_TRIG_MANUAL,
00189 ADC_TRIG_FREERUN_SWEEP,
00196 ADC_TRIG_EVENT_SINGLE,
00197 #if XMEGA_A
00198
00202 ADC_TRIG_EVENT_SWEEP,
00207 ADC_TRIG_EVENT_SYNCSWEEP,
00208 #endif
00209 };
00210
00212 enum adc_sign {
00213 ADC_SIGN_OFF,
00214 ADC_SIGN_ON = ADC_CONMODE_bm,
00215 };
00216
00218 enum adc_resolution {
00220 ADC_RES_8 = ADC_RESOLUTION_8BIT_gc,
00222 ADC_RES_12 = ADC_RESOLUTION_12BIT_gc,
00224 ADC_RES_12_LEFT = ADC_RESOLUTION_LEFT12BIT_gc,
00225 };
00226
00228 enum adc_reference {
00230 ADC_REF_BANDGAP = ADC_REFSEL_INT1V_gc,
00232 ADC_REF_VCC = ADC_REFSEL_VCC_gc,
00234 ADC_REF_AREFA = ADC_REFSEL_AREFA_gc,
00236 ADC_REF_AREFB = ADC_REFSEL_AREFB_gc,
00237 };
00238
00239 #if defined(CONFIG_ADC_CALLBACK_ENABLE) || defined(__DOXYGEN__)
00240
00241
00242
00251 #if !defined(CONFIG_ADC_CALLBACK_ENABLE) || defined(__DOXYGEN__)
00252 # define CONFIG_ADC_CALLBACK_ENABLE
00253 #endif
00254
00269 #if !defined(CONFIG_ADC_CALLBACK_TYPE) || defined(__DOXYGEN__)
00270 # define CONFIG_ADC_CALLBACK_TYPE uint16_t
00271 #endif
00272
00274 typedef CONFIG_ADC_CALLBACK_TYPE adc_result_t;
00275
00283 typedef void (*adc_callback_t)(ADC_t *adc, uint8_t ch, adc_result_t res);
00284
00285 void adc_set_callback(ADC_t *adc, adc_callback_t callback);
00286
00288 #endif
00289
00291
00292
00293 void adc_enable(ADC_t *adc);
00294 void adc_disable(ADC_t *adc);
00295 bool adc_is_enabled(ADC_t *adc);
00296
00307 static inline void adc_start_conversion(ADC_t *adc, uint8_t ch_mask)
00308 {
00309 irqflags_t flags = cpu_irq_save();
00310 adc->CTRLA |= ch_mask << ADC_CH0START_bp;
00311 cpu_irq_restore(flags);
00312 }
00313
00327 static inline uint8_t adc_get_interrupt_flag(ADC_t *adc, uint8_t ch_mask)
00328 {
00329 return (adc->INTFLAGS >> ADC_CH0IF_bp) & ch_mask;
00330 }
00331
00342 static inline void adc_clear_interrupt_flag(ADC_t *adc, uint8_t ch_mask)
00343 {
00344 adc->INTFLAGS = ch_mask << ADC_CH0IF_bp;
00345 }
00346
00359 static inline void adc_wait_for_interrupt_flag(ADC_t *adc, uint8_t ch_mask)
00360 {
00361 do { } while (adc_get_interrupt_flag(adc, ch_mask) != ch_mask);
00362 adc_clear_interrupt_flag(adc, ch_mask);
00363 }
00364
00376 static inline void adc_flush(ADC_t *adc)
00377 {
00378 irqflags_t flags = cpu_irq_save();
00379 adc->CTRLA |= ADC_FLUSH_bm;
00380 cpu_irq_restore(flags);
00381 }
00382
00394 #define adc_set_compare_value(adc, val) \
00395 do { \
00396 irqflags_t ATPASTE2(adc_flags, __LINE__) = cpu_irq_save(); \
00397 (adc)->CMP = val; \
00398 cpu_irq_restore(ATPASTE2(adc_flags, __LINE__)); \
00399 } while (0)
00400
00416 #define adc_get_compare_value(adc) ((adc)->CMP)
00417
00426 static inline int16_t adc_get_signed_compare_value(ADC_t *adc)
00427 {
00428 int16_t val;
00429 irqflags_t flags;
00430
00431 flags = cpu_irq_save();
00432 val = adc->CMP;
00433 cpu_irq_restore(flags);
00434
00435 return val;
00436 }
00437
00446 static inline uint16_t adc_get_unsigned_compare_value(ADC_t *adc)
00447 {
00448 uint16_t val;
00449 irqflags_t flags;
00450
00451 flags = cpu_irq_save();
00452 val = adc->CMP;
00453 cpu_irq_restore(flags);
00454
00455 return val;
00456 }
00457
00463 static inline uint16_t adc_get_calibration_data(enum adc_calibration_data cal)
00464 {
00465 uint16_t data;
00466
00467 switch (cal) {
00468 #ifdef ADCA
00469 case ADC_CAL_ADCA:
00470 data = nvm_read_production_signature_row(ADCACAL1);
00471 data <<= 8;
00472 data |= nvm_read_production_signature_row(ADCACAL0);
00473 break;
00474 #endif
00475
00476 #ifdef ADCB
00477 case ADC_CAL_ADCB:
00478 data = nvm_read_production_signature_row(ADCBCAL1);
00479 data <<= 8;
00480 data |= nvm_read_production_signature_row(ADCBCAL0);
00481 break;
00482 #endif
00483
00484 #if defined(ADCA) || defined(ADCB)
00485 case ADC_CAL_TEMPSENSE:
00486 data = nvm_read_production_signature_row(TEMPSENSE1);
00487 data <<= 8;
00488 data |= nvm_read_production_signature_row(TEMPSENSE0);
00489 break;
00490 #endif
00491
00492 default:
00493 Assert(0);
00494 data = 0;
00495 }
00496
00497 return data;
00498 }
00499
00501
00503
00504
00505 void adc_write_configuration(ADC_t *adc, const struct adc_config *conf);
00506 void adc_read_configuration(ADC_t *adc, struct adc_config *conf);
00507
00523 static inline void adc_set_clock_rate(struct adc_config *conf, uint32_t clk_adc)
00524 {
00525 uint32_t clk_per;
00526 uint16_t ratio;
00527 uint8_t psc;
00528
00529 Assert(clk_adc);
00530 #if XMEGA_A
00531 Assert(clk_adc <= 2000000UL);
00532 #elif XMEGA_D
00533 Assert(clk_adc <= 1400000UL);
00534 #endif
00535
00536 clk_per = sysclk_get_per_hz();
00537 ratio = clk_per / clk_adc;
00538
00539
00540 if(ratio <= 4) {
00541 psc = ADC_PRESCALER_DIV4_gc;
00542 } else if (ratio <= 8) {
00543 psc = ADC_PRESCALER_DIV8_gc;
00544 } else if (ratio <= 16) {
00545 psc = ADC_PRESCALER_DIV16_gc;
00546 } else if (ratio <= 32) {
00547 psc = ADC_PRESCALER_DIV32_gc;
00548 } else if (ratio <= 64) {
00549 psc = ADC_PRESCALER_DIV64_gc;
00550 } else if (ratio <= 128) {
00551 psc = ADC_PRESCALER_DIV128_gc;
00552 } else if (ratio <= 256) {
00553 psc = ADC_PRESCALER_DIV256_gc;
00554 } else {
00555 psc = ADC_PRESCALER_DIV512_gc;
00556 }
00557
00558 conf->prescaler = psc;
00559 }
00560
00572 static inline void adc_set_conversion_parameters(struct adc_config *conf,
00573 enum adc_sign sign, enum adc_resolution res,
00574 enum adc_reference ref)
00575 {
00576
00577 conf->ctrlb &= ~(ADC_CONMODE_bm | ADC_RESOLUTION_gm);
00578 conf->ctrlb |= (uint8_t)res | (uint8_t)sign;
00579
00580 conf->refctrl &= ~ADC_REFSEL_gm;
00581 conf->refctrl |= ref;
00582 }
00583
00605 static inline void adc_set_conversion_trigger(struct adc_config *conf,
00606 enum adc_trigger trig, uint8_t nr_of_ch, uint8_t base_ev_ch)
00607 {
00608 Assert(nr_of_ch);
00609 Assert(nr_of_ch <= ADC_NR_OF_CHANNELS);
00610 #if XMEGA_A
00611 Assert(base_ev_ch <= 7);
00612 #elif XMEGA_D
00613 Assert(base_ev_ch <= 3);
00614 #endif
00615
00616 switch (trig) {
00617 case ADC_TRIG_MANUAL:
00618 conf->ctrlb &= ~ADC_FREERUN_bm;
00619 conf->evctrl = ADC_EVACT_NONE_gc;
00620 break;
00621
00622 case ADC_TRIG_FREERUN_SWEEP:
00623 conf->ctrlb |= ADC_FREERUN_bm;
00624 conf->evctrl = (nr_of_ch - 1) << ADC_SWEEP_gp;
00625 break;
00626
00627 case ADC_TRIG_EVENT_SINGLE:
00628 conf->ctrlb &= ~ADC_FREERUN_bm;
00629 conf->evctrl = (base_ev_ch << ADC_EVSEL_gp) |
00630 (nr_of_ch << ADC_EVACT_gp);
00631 break;
00632
00633 #if XMEGA_A
00634 case ADC_TRIG_EVENT_SWEEP:
00635 conf->ctrlb &= ~ADC_FREERUN_bm;
00636 conf->evctrl = (nr_of_ch - 1) << ADC_SWEEP_gp |
00637 (base_ev_ch << ADC_EVSEL_gp) |
00638 ADC_EVACT_SWEEP_gc;
00639 break;
00640
00641 case ADC_TRIG_EVENT_SYNCSWEEP:
00642 conf->ctrlb &= ~ADC_FREERUN_bm;
00643 conf->evctrl = ((nr_of_ch - 1) << ADC_SWEEP_gp) |
00644 (base_ev_ch << ADC_EVSEL_gp) |
00645 ADC_EVACT_SYNCHSWEEP_gc;
00646 break;
00647 #endif
00648
00649 default:
00650 Assert(0);
00651 }
00652 }
00653
00654 #if XMEGA_A
00655
00669 static inline void adc_set_dma_request_group(struct adc_config *conf,
00670 uint8_t nr_of_ch)
00671 {
00672 Assert(nr_of_ch <= ADC_NR_OF_CHANNELS);
00673 Assert(nr_of_ch != 1);
00674
00675 if (nr_of_ch) {
00676 conf->ctrla = (nr_of_ch - 1) << ADC_DMASEL_gp;
00677 } else {
00678 conf->ctrla = ADC_DMASEL_OFF_gc;
00679 }
00680 }
00681 #endif
00682
00691 static inline void adc_enable_internal_input(struct adc_config *conf,
00692 uint8_t int_inp)
00693 {
00694 conf->refctrl |= int_inp;
00695 }
00696
00705 static inline void adc_disable_internal_input(struct adc_config *conf,
00706 uint8_t int_inp)
00707 {
00708 conf->refctrl &= ~int_inp;
00709 }
00710
00717 #define adc_set_config_compare_value(conf, val) \
00718 do { \
00719 conf->cmp = (uint16_t)val; \
00720 } while (0)
00721
00727 #define adc_get_config_compare_value(conf) (conf->cmp)
00728
00730
00752 #if !defined(CONFIG_ADC_INTLVL) || defined(__DOXYGEN__)
00753 # define CONFIG_ADC_INTLVL ADC_CH_INTLVL_LO_gc
00754 #endif
00755
00757 struct adc_channel_config {
00758 uint8_t ctrl;
00759 uint8_t muxctrl;
00760 uint8_t intctrl;
00761 };
00762
00772 enum adcch_positive_input {
00773 ADCCH_POS_PIN0,
00774 ADCCH_POS_PIN1,
00775 ADCCH_POS_PIN2,
00776 ADCCH_POS_PIN3,
00777 ADCCH_POS_PIN4,
00778 ADCCH_POS_PIN5,
00779 ADCCH_POS_PIN6,
00780 ADCCH_POS_PIN7,
00781
00783
00784 #if XMEGA_A4 || XMEGA_D
00785 ADCCH_POS_PIN8,
00786 ADCCH_POS_PIN9,
00787 ADCCH_POS_PIN10,
00788 ADCCH_POS_PIN11,
00789 #endif
00790 #if XMEGA_D3
00791 ADCCH_POS_PIN12,
00792 ADCCH_POS_PIN13,
00793 ADCCH_POS_PIN14,
00794 ADCCH_POS_PIN15,
00795 #endif
00796
00797
00799
00800 ADCCH_POS_TEMPSENSE,
00801 ADCCH_POS_BANDGAP,
00802 ADCCH_POS_SCALED_VCC,
00803 #if XMEGA_A
00804 ADCCH_POS_DAC,
00805 #endif
00806
00807 };
00808
00818 enum adcch_negative_input {
00820
00821 ADCCH_NEG_PIN0,
00822 ADCCH_NEG_PIN1,
00823 ADCCH_NEG_PIN2,
00824 ADCCH_NEG_PIN3,
00826
00828
00829 ADCCH_NEG_PIN4,
00830 ADCCH_NEG_PIN5,
00831 ADCCH_NEG_PIN6,
00832 ADCCH_NEG_PIN7,
00834
00835 ADCCH_NEG_NONE,
00836 };
00837
00839 enum adcch_mode {
00841 ADCCH_MODE_COMPLETE = ADC_CH_INTMODE_COMPLETE_gc,
00843 ADCCH_MODE_BELOW = ADC_CH_INTMODE_BELOW_gc,
00845 ADCCH_MODE_ABOVE = ADC_CH_INTMODE_ABOVE_gc,
00846 };
00847
00849
00850
00866 #define adcch_get_result(adc, ch) ((&(adc)->CH0 + ch)->RES)
00867
00879 static inline int16_t adcch_get_signed_result(ADC_t *adc, uint8_t ch)
00880 {
00881 int16_t val;
00882 irqflags_t flags;
00883 ADC_CH_t *adc_ch;
00884
00885 adc_ch = &adc->CH0 + ch;
00886
00887 flags = cpu_irq_save();
00888 val = adc_ch->RES;
00889 cpu_irq_restore(flags);
00890
00891 return val;
00892 }
00893
00905 static inline uint16_t adcch_get_unsigned_result(ADC_t*adc, uint8_t ch)
00906 {
00907 uint16_t val;
00908 irqflags_t flags;
00909 ADC_CH_t *adc_ch;
00910
00911 adc_ch = &adc->CH0 + ch;
00912
00913 flags = cpu_irq_save();
00914 val = adc_ch->RES;
00915 cpu_irq_restore(flags);
00916
00917 return val;
00918 }
00919
00921
00923
00924
00925 void adcch_write_configuration(ADC_t *adc, uint8_t ch,
00926 const struct adc_channel_config *ch_conf);
00927 void adcch_read_configuration(ADC_t *adc, uint8_t ch,
00928 struct adc_channel_config *ch_conf);
00929
00940 static inline uint8_t adcch_get_gain_setting(uint8_t gain)
00941 {
00942 switch (gain) {
00943 case 1: return ADC_CH_GAIN_1X_gc;
00944
00945 case 2: return ADC_CH_GAIN_2X_gc;
00946
00947 case 4: return ADC_CH_GAIN_4X_gc;
00948
00949 case 8: return ADC_CH_GAIN_8X_gc;
00950
00951 case 16: return ADC_CH_GAIN_16X_gc;
00952
00953 case 32: return ADC_CH_GAIN_32X_gc;
00954
00955 case 64: return ADC_CH_GAIN_64X_gc;
00956
00957 default:
00958 Assert(0);
00959 return 0;
00960 }
00961 }
00962
00981 static inline void adcch_set_input(struct adc_channel_config *ch_conf,
00982 enum adcch_positive_input pos, enum adcch_negative_input neg,
00983 uint8_t gain)
00984 {
00985 Assert(gain);
00986
00987
00988 if (pos >= ADCCH_POS_TEMPSENSE) {
00989 Assert(gain == 1);
00990 Assert(neg == ADCCH_NEG_NONE);
00991
00992 ch_conf->ctrl = ADC_CH_INPUTMODE_INTERNAL_gc;
00993 ch_conf->muxctrl = (pos - ADCCH_POS_TEMPSENSE) <<
00994 ADC_CH_MUXPOS_gp;
00995 return;
00996 }
00997
00998
00999 if (neg == ADCCH_NEG_NONE) {
01000 Assert(gain == 1);
01001
01002 ch_conf->ctrl = ADC_CH_INPUTMODE_SINGLEENDED_gc;
01003 ch_conf->muxctrl = pos << ADC_CH_MUXPOS_gp;
01004
01005
01006 } else {
01007
01008
01009
01010 if (neg < ADCCH_NEG_PIN4) {
01011 Assert(gain == 1);
01012
01013 ch_conf->ctrl = ADC_CH_INPUTMODE_DIFF_gc;
01014 ch_conf->muxctrl = (pos << ADC_CH_MUXPOS_gp) |
01015 (neg << ADC_CH_MUXNEG_gp);
01016 } else {
01017
01018
01019
01020 ch_conf->ctrl = ADC_CH_INPUTMODE_DIFFWGAIN_gc |
01021 adcch_get_gain_setting(gain);
01022 ch_conf->muxctrl = (pos << ADC_CH_MUXPOS_gp) |
01023 ((neg - ADCCH_NEG_PIN4) <<
01024 ADC_CH_MUXNEG_gp);
01025 }
01026 }
01027 }
01028
01035 static inline void adcch_set_interrupt_mode(struct adc_channel_config *ch_conf,
01036 enum adcch_mode mode)
01037 {
01038 ch_conf->intctrl &= ~ADC_CH_INTMODE_gm;
01039 ch_conf->intctrl |= mode;
01040 }
01041
01047 static inline void adcch_enable_interrupt(struct adc_channel_config *ch_conf)
01048 {
01049 ch_conf->intctrl &= ~ADC_CH_INTLVL_gm;
01050 ch_conf->intctrl |= CONFIG_ADC_INTLVL;
01051 }
01052
01058 static inline void adcch_disable_interrupt(struct adc_channel_config *ch_conf)
01059 {
01060 ch_conf->intctrl &= ~ADC_CH_INTLVL_gm;
01061 ch_conf->intctrl |= ADC_CH_INTLVL_OFF_gc;
01062 }
01063
01065
01070 #ifdef __cplusplus
01071 }
01072 #endif
01073
01074 #endif