2 * Copyright © 2019 Keith Packard <keithp@keithp.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
16 #include <ao_adc_samd21.h>
21 while (samd21_adc.status & (1 << SAMD21_ADC_STATUS_SYNCBUSY))
25 static uint8_t ao_adc_sequence;
26 static uint8_t ao_adc_ready;
28 static uint8_t ao_adc_mux[AO_NUM_ADC] = {
57 #error set up more ADC
64 uint8_t mux = ao_adc_mux[ao_adc_sequence];
65 samd21_adc.inputctrl = ((mux << SAMD21_ADC_INPUTCTRL_MUXPOS) |
66 (SAMD21_ADC_INPUTCTRL_MUXNEG_GND << SAMD21_ADC_INPUTCTRL_MUXNEG) |
67 (0 << SAMD21_ADC_INPUTCTRL_INPUTSCAN) |
68 (0 << SAMD21_ADC_INPUTCTRL_INPUTOFFSET) |
69 (SAMD21_ADC_INPUTCTRL_GAIN_DIV2 << SAMD21_ADC_INPUTCTRL_GAIN));
70 samd21_adc.swtrig = (1UL << SAMD21_ADC_SWTRIG_START);
78 /* Store converted value in packet */
79 out = (uint16_t *) &ao_data_ring[ao_data_head].adc;
80 out[ao_adc_sequence] = (uint16_t) samd21_adc.result;
81 if (++ao_adc_sequence < AO_NUM_ADC) {
86 AO_DATA_PRESENT(AO_DATA_ADC);
87 ao_data_fill(ao_data_head);
104 struct ao_data packet;
106 ao_data_get(&packet);
107 AO_ADC_DUMP(&packet);
110 const struct ao_cmds ao_adc_cmds[] = {
111 { ao_adc_dump, "a\0Display current ADC values" },
116 set_adc(struct samd21_port *port, uint8_t pin)
118 samd21_port_pmux_set(port, pin, SAMD21_PORT_PMUX_FUNC_B);
119 samd21_port_pincfg_set(port, pin,
120 (1 << SAMD21_PORT_PINCFG_DRVSTR) |
121 (1 << SAMD21_PORT_PINCFG_PULLEN) |
122 (1 << SAMD21_PORT_PINCFG_INEN),
123 (0 << SAMD21_PORT_PINCFG_DRVSTR) |
124 (0 << SAMD21_PORT_PINCFG_PULLEN) |
125 (1 << SAMD21_PORT_PINCFG_INEN));
132 samd21_gclk_clkctrl(0, SAMD21_GCLK_CLKCTRL_ID_ADC);
134 /* enable the device */
135 samd21_pm.apbcmask |= (1 << SAMD21_PM_APBCMASK_ADC);
138 samd21_adc.ctrla = (1 << SAMD21_ADC_CTRLA_SWRST);
142 while ((samd21_adc.ctrla & (1 << SAMD21_ADC_CTRLA_SWRST)) != 0 ||
143 (samd21_adc.status & (1 << SAMD21_ADC_STATUS_SYNCBUSY)) != 0)
146 /* Load ADC calibration values */
147 uint32_t b = (samd21_aux1.calibration >> SAMD21_AUX1_CALIBRATION_ADC_BIASCAL) & SAMD21_AUX1_CALIBRATION_ADC_BIASCAL_MASK;
148 uint32_t l = (samd21_aux1.calibration >> SAMD21_AUX1_CALIBRATION_ADC_LINEARITY) & SAMD21_AUX1_CALIBRATION_ADC_LINEARITY_MASK;
150 samd21_adc.calib = (uint16_t) ((b << SAMD21_ADC_CALIB_BIAS_CAL) |
151 (l << SAMD21_ADC_CALIB_LINEARITY_CAL));
156 samd21_adc.ctrlb = ((0 << SAMD21_ADC_CTRLB_DIFFMODE) |
157 (0 << SAMD21_ADC_CTRLB_LEFTADJ) |
158 (0 << SAMD21_ADC_CTRLB_FREERUN) |
159 (0 << SAMD21_ADC_CTRLB_CORREN) |
160 (SAMD21_ADC_CTRLB_RESSEL_12BIT << SAMD21_ADC_CTRLB_RESSEL) |
161 (SAMD21_ADC_CTRLB_PRESCALER_DIV512 << SAMD21_ADC_CTRLB_PRESCALER));
165 samd21_adc.sampctrl = 0x1f;
169 samd21_adc.refctrl = (SAMD21_ADC_REFCTRL_REFSEL_INTVCC1 << SAMD21_ADC_REFCTRL_REFSEL);
173 samd21_adc.intenset = (1UL << SAMD21_ADC_INTFLAG_RESRDY);
175 samd21_adc.ctrla = (1 << SAMD21_ADC_CTRLA_ENABLE);
177 /* configure interrupts */
178 samd21_nvic_set_enable(SAMD21_NVIC_ISR_ADC_POS);
179 samd21_nvic_set_priority(SAMD21_NVIC_ISR_ADC_POS, 0);
181 ao_cmd_register(&ao_adc_cmds[0]);
184 #if AO_NUM_ADC_PIN > 0
185 set_adc(AO_ADC_PIN0_PORT, AO_ADC_PIN0_PIN);
187 #if AO_NUM_ADC_PIN > 1
188 set_adc(AO_ADC_PIN1_PORT, AO_ADC_PIN1_PIN);
190 #if AO_NUM_ADC_PIN > 2
191 set_adc(AO_ADC_PIN2_PORT, AO_ADC_PIN2_PIN);
193 #if AO_NUM_ADC_PIN > 3
194 set_adc(AO_ADC_PIN3_PORT, AO_ADC_PIN3_PIN);
196 #if AO_NUM_ADC_PIN > 4
197 set_adc(AO_ADC_PIN4_PORT, AO_ADC_PIN4_PIN);
199 #if AO_NUM_ADC_PIN > 5
200 set_adc(AO_ADC_PIN5_PORT, AO_ADC_PIN5_PIN);
202 #if AO_NUM_ADC_PIN > 6
203 set_adc(AO_ADC_PIN6_PORT, AO_ADC_PIN6_PIN);
205 #if AO_NUM_ADC_PIN > 7
206 set_adc(AO_ADC_PIN7_PORT, AO_ADC_PIN7_PIN);
208 #if AO_NUM_ADC_PIN > 8
209 set_adc(AO_ADC_PIN8_PORT, AO_ADC_PIN8_PIN);
211 #if AO_NUM_ADC_PIN > 9
212 #error set up more ADC bits