2626
2727#include <string.h>
2828
29+ #include "py/gc.h"
2930#include "py/nlr.h"
3031#include "py/runtime.h"
3132#include "py/binary.h"
3536#include "asf/sam0/drivers/adc/adc.h"
3637#include "samd21_pins.h"
3738
39+ // Number of active ADC channels.
40+ volatile uint8_t active_channel_count ;
41+ struct adc_module * adc_instance = NULL ;
42+
3843void common_hal_nativeio_analogin_construct (nativeio_analogin_obj_t * self ,
3944const mcu_pin_obj_t * pin ) {
4045if (!pin -> has_adc ) {
@@ -44,42 +49,55 @@ void common_hal_nativeio_analogin_construct(nativeio_analogin_obj_t* self,
4449
4550self -> pin = pin ;
4651
47- struct adc_config config_adc ;
48- adc_get_config_defaults (& config_adc );
52+ if (adc_instance == NULL ) {
53+ struct adc_config config_adc ;
54+ adc_get_config_defaults (& config_adc );
55+
56+ config_adc .reference = ADC_REFERENCE_INTVCC1 ;
57+ config_adc .gain_factor = ADC_GAIN_FACTOR_DIV2 ;
58+ config_adc .positive_input = self -> pin -> adc_input ;
59+ config_adc .resolution = ADC_RESOLUTION_16BIT ;
60+ config_adc .clock_prescaler = ADC_CLOCK_PRESCALER_DIV128 ;
61+
62+ // Allocate the instance on the heap so we only use the memory when we
63+ // need it.
64+ adc_instance = gc_alloc (sizeof (struct adc_module ), false);
4965
50- config_adc .reference = ADC_REFERENCE_INTVCC1 ;
51- config_adc .gain_factor = ADC_GAIN_FACTOR_DIV2 ;
52- config_adc .positive_input = self -> pin -> adc_input ;
53- config_adc .resolution = ADC_RESOLUTION_16BIT ;
54- config_adc .clock_prescaler = ADC_CLOCK_PRESCALER_DIV128 ;
66+ adc_init (adc_instance ,ADC ,& config_adc );
67+ }
5568
56- adc_init (& self -> adc_instance ,ADC ,& config_adc );
69+ self -> adc_instance = adc_instance ;
70+ active_channel_count ++ ;
5771}
5872
5973void common_hal_nativeio_analogin_deinit (nativeio_analogin_obj_t * self ) {
60- // TODO(tannewt): Count how many pins are in use and only reset the ADC when
61- // none are used.
62- adc_reset (& self -> adc_instance );
74+ active_channel_count -- ;
75+ if (active_channel_count == 0 ) {
76+ adc_reset (adc_instance );
77+ gc_free (adc_instance );
78+ // Set our reference to NULL so the GC doesn't mistakenly see the
79+ // pointer in memory.
80+ adc_instance = NULL ;
81+ }
6382reset_pin (self -> pin -> pin );
6483}
6584
66- // TODO(tannewt): Don't turn it all on just for one read. This simplifies
67- // handling of reading multiple inputs and surviving sleep though so for now its
68- // ok.
6985uint16_t common_hal_nativeio_analogin_get_value (nativeio_analogin_obj_t * self ) {
70- adc_enable (& self -> adc_instance );
71- adc_start_conversion (& self -> adc_instance );
86+ adc_set_positive_input (adc_instance ,self -> pin -> adc_input );
87+
88+ adc_enable (adc_instance );
89+ adc_start_conversion (adc_instance );
7290
7391uint16_t data ;
74- enum status_code status = adc_read (& self -> adc_instance ,& data );
92+ enum status_code status = adc_read (adc_instance ,& data );
7593while (status == STATUS_BUSY ) {
76- status = adc_read (& self -> adc_instance ,& data );
94+ status = adc_read (adc_instance ,& data );
7795 }
7896if (status == STATUS_ERR_OVERFLOW ) {
7997// TODO(tannewt): Throw an error.
8098 }
8199
82- adc_disable (& self -> adc_instance );
100+ adc_disable (adc_instance );
83101return data ;
84102}
85103