26
26
27
27
#include <string.h>
28
28
29
+ #include "py/gc.h"
29
30
#include "py/nlr.h"
30
31
#include "py/runtime.h"
31
32
#include "py/binary.h"
35
36
#include "asf/sam0/drivers/adc/adc.h"
36
37
#include "samd21_pins.h"
37
38
39
+ // Number of active ADC channels.
40
+ volatile uint8_t active_channel_count ;
41
+ struct adc_module * adc_instance = NULL ;
42
+
38
43
void common_hal_nativeio_analogin_construct (nativeio_analogin_obj_t * self ,
39
44
const mcu_pin_obj_t * pin ) {
40
45
if (!pin -> has_adc ) {
@@ -44,42 +49,55 @@ void common_hal_nativeio_analogin_construct(nativeio_analogin_obj_t* self,
44
49
45
50
self -> pin = pin ;
46
51
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);
49
65
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
+ }
55
68
56
- adc_init (& self -> adc_instance , ADC , & config_adc );
69
+ self -> adc_instance = adc_instance ;
70
+ active_channel_count ++ ;
57
71
}
58
72
59
73
void 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
+ }
63
82
reset_pin (self -> pin -> pin );
64
83
}
65
84
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.
69
85
uint16_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 );
72
90
73
91
uint16_t data ;
74
- enum status_code status = adc_read (& self -> adc_instance , & data );
92
+ enum status_code status = adc_read (adc_instance , & data );
75
93
while (status == STATUS_BUSY ) {
76
- status = adc_read (& self -> adc_instance , & data );
94
+ status = adc_read (adc_instance , & data );
77
95
}
78
96
if (status == STATUS_ERR_OVERFLOW ) {
79
97
// TODO(tannewt): Throw an error.
80
98
}
81
99
82
- adc_disable (& self -> adc_instance );
100
+ adc_disable (adc_instance );
83
101
return data ;
84
102
}
85
103
0 commit comments