From 7bcde16c96f05595969bceef76905aa2e285c66b Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 8 Nov 2022 16:18:57 -0800 Subject: [PATCH] samd21: Hook up AltOS style ADC Can't use DMA; samd21 only does ADC in continuous pins. ISR per ADC, manually step through. Signed-off-by: Keith Packard --- src/samd21/ao_adc_samd21.c | 156 ++++++++++++++++++++++++++++++++----- src/samd21/ao_adc_samd21.h | 4 +- src/samd21/samd21.h | 1 + 3 files changed, 139 insertions(+), 22 deletions(-) diff --git a/src/samd21/ao_adc_samd21.c b/src/samd21/ao_adc_samd21.c index 1457b603..6d67eda7 100644 --- a/src/samd21/ao_adc_samd21.c +++ b/src/samd21/ao_adc_samd21.c @@ -22,33 +22,107 @@ ao_adc_sync(void) ; } -static uint16_t -ao_adc_do_conversion(void) -{ - ao_adc_sync(); - samd21_adc.swtrig = (1 << SAMD21_ADC_SWTRIG_START); - ao_adc_sync(); - while ((samd21_adc.intflag & (1 << SAMD21_ADC_INTFLAG_RESRDY)) == 0) - ao_adc_sync(); - ao_adc_sync(); - return samd21_adc.result; -} +static uint8_t ao_adc_sequence; +static uint8_t ao_adc_ready; + +static uint8_t ao_adc_mux[AO_NUM_ADC] = { +#if AO_NUM_ADC > 0 + AO_ADC_SQ0, +#endif +#if AO_NUM_ADC > 1 + AO_ADC_SQ1, +#endif +#if AO_NUM_ADC > 2 + AO_ADC_SQ2, +#endif +#if AO_NUM_ADC > 3 + AO_ADC_SQ3, +#endif +#if AO_NUM_ADC > 4 + AO_ADC_SQ4, +#endif +#if AO_NUM_ADC > 5 + AO_ADC_SQ5, +#endif +#if AO_NUM_ADC > 6 + AO_ADC_SQ6, +#endif +#if AO_NUM_ADC > 7 + AO_ADC_SQ7, +#endif +#if AO_NUM_ADC > 8 + AO_ADC_SQ8, +#endif +#if AO_NUM_ADC > 9 +#error set up more ADC +#endif +}; -uint16_t -ao_adc_read(uint8_t channel) +static void +ao_adc_start(void) { - ao_adc_sync(); - samd21_adc.inputctrl = ((channel << SAMD21_ADC_INPUTCTRL_MUXPOS) | + uint8_t mux = ao_adc_mux[ao_adc_sequence]; + samd21_adc.inputctrl = ((mux << SAMD21_ADC_INPUTCTRL_MUXPOS) | (SAMD21_ADC_INPUTCTRL_MUXNEG_GND << SAMD21_ADC_INPUTCTRL_MUXNEG) | (0 << SAMD21_ADC_INPUTCTRL_INPUTSCAN) | (0 << SAMD21_ADC_INPUTCTRL_INPUTOFFSET) | (SAMD21_ADC_INPUTCTRL_GAIN_DIV2 << SAMD21_ADC_INPUTCTRL_GAIN)); + samd21_adc.swtrig = (1UL << SAMD21_ADC_SWTRIG_START); +} + +void +samd21_adc_isr(void) +{ + uint16_t *out; + + /* Store converted value in packet */ + out = (uint16_t *) &ao_data_ring[ao_data_head].adc; + out[ao_adc_sequence] = (uint16_t) samd21_adc.result; + if (++ao_adc_sequence < AO_NUM_ADC) { + ao_adc_start(); + return; + } + + AO_DATA_PRESENT(AO_DATA_ADC); + ao_data_fill(ao_data_head); + ao_adc_ready = 1; +} - /* Read twice and discard the first value as recommended by app note - * http://www.atmel.com/images/Atmel-42645-ADC-Configurations-with-Examples_ApplicationNote_AT11481.pdf - */ - (void) ao_adc_do_conversion(); - return ao_adc_do_conversion(); +void +ao_adc_poll(void) +{ + if (!ao_adc_ready) + return; + ao_adc_ready = 0; + ao_adc_sequence = 0; + ao_adc_start(); +} + +static void +ao_adc_dump(void) +{ + struct ao_data packet; + + ao_data_get(&packet); + AO_ADC_DUMP(&packet); +} + +const struct ao_cmds ao_adc_cmds[] = { + { ao_adc_dump, "a\0Display current ADC values" }, + { 0, NULL }, +}; + +static inline void +set_adc(struct samd21_port *port, uint8_t pin) +{ + samd21_port_pmux_set(port, pin, SAMD21_PORT_PMUX_FUNC_B); + samd21_port_pincfg_set(port, pin, + (1 << SAMD21_PORT_PINCFG_DRVSTR) | + (1 << SAMD21_PORT_PINCFG_PULLEN) | + (1 << SAMD21_PORT_PINCFG_INEN), + (0 << SAMD21_PORT_PINCFG_DRVSTR) | + (0 << SAMD21_PORT_PINCFG_PULLEN) | + (1 << SAMD21_PORT_PINCFG_INEN)); } void @@ -96,5 +170,47 @@ ao_adc_init(void) ao_adc_sync(); + samd21_adc.intenset = (1UL << SAMD21_ADC_INTFLAG_RESRDY); + samd21_adc.ctrla = (1 << SAMD21_ADC_CTRLA_ENABLE); + + /* configure interrupts */ + samd21_nvic_set_enable(SAMD21_NVIC_ISR_ADC_POS); + samd21_nvic_set_priority(SAMD21_NVIC_ISR_ADC_POS, 0); + + ao_cmd_register(&ao_adc_cmds[0]); + + /* configure pins */ +#if AO_NUM_ADC_PIN > 0 + set_adc(AO_ADC_PIN0_PORT, AO_ADC_PIN0_PIN); +#endif +#if AO_NUM_ADC_PIN > 1 + set_adc(AO_ADC_PIN1_PORT, AO_ADC_PIN1_PIN); +#endif +#if AO_NUM_ADC_PIN > 2 + set_adc(AO_ADC_PIN2_PORT, AO_ADC_PIN2_PIN); +#endif +#if AO_NUM_ADC_PIN > 3 + set_adc(AO_ADC_PIN3_PORT, AO_ADC_PIN3_PIN); +#endif +#if AO_NUM_ADC_PIN > 4 + set_adc(AO_ADC_PIN4_PORT, AO_ADC_PIN4_PIN); +#endif +#if AO_NUM_ADC_PIN > 5 + set_adc(AO_ADC_PIN5_PORT, AO_ADC_PIN5_PIN); +#endif +#if AO_NUM_ADC_PIN > 6 + set_adc(AO_ADC_PIN6_PORT, AO_ADC_PIN6_PIN); +#endif +#if AO_NUM_ADC_PIN > 7 + set_adc(AO_ADC_PIN7_PORT, AO_ADC_PIN7_PIN); +#endif +#if AO_NUM_ADC_PIN > 8 + set_adc(AO_ADC_PIN8_PORT, AO_ADC_PIN8_PIN); +#endif +#if AO_NUM_ADC_PIN > 9 +#error set up more ADC bits +#endif + + ao_adc_ready = 1; } diff --git a/src/samd21/ao_adc_samd21.h b/src/samd21/ao_adc_samd21.h index dd562a05..3d1658be 100644 --- a/src/samd21/ao_adc_samd21.h +++ b/src/samd21/ao_adc_samd21.h @@ -15,8 +15,8 @@ #ifndef _AO_ADC_SAMD21_H_ #define _AO_ADC_SAMD21_H_ -uint16_t -ao_adc_read(uint8_t channel); +void +ao_adc_poll(void); void ao_adc_init(void); diff --git a/src/samd21/samd21.h b/src/samd21/samd21.h index 4a18e757..91ad52bf 100644 --- a/src/samd21/samd21.h +++ b/src/samd21/samd21.h @@ -860,6 +860,7 @@ struct samd21_adc { #define SAMD21_ADC_SWTRIG_START 1 #define SAMD21_ADC_INPUTCTRL_MUXPOS 0 +# define SAMD21_ADC_INPUTCTRL_MUXPOS_TEMP 0x18 # define SAMD21_ADC_INPUTCTRL_MUXPOS_BANDGAP 0x19 # define SAMD21_ADC_INPUTCTRL_MUXPOS_SCALEDCOREVCC 0x1a # define SAMD21_ADC_INPUTCTRL_MUXPOS_SCALEDIOVCC 0x1b -- 2.30.2