33
33
#include "common-hal/analogbufio/BufferedIn.h"
34
34
#include "shared-bindings/analogbufio/BufferedIn.h"
35
35
#include "shared-bindings/microcontroller/Pin.h"
36
+ #include "shared/runtime/interrupt_char.h"
36
37
#include "py/runtime.h"
37
38
#include "supervisor/shared/translate/translate.h"
38
39
#include "src/rp2_common/hardware_adc/include/hardware/adc.h"
42
43
#define ADC_FIRST_PIN_NUMBER 26
43
44
#define ADC_PIN_COUNT 4
44
45
45
- void common_hal_analogbufio_bufferedin_construct (analogbufio_bufferedin_obj_t * self , const mcu_pin_obj_t * pin , uint8_t * buffer , uint32_t len , uint8_t bytes_per_sample , bool samples_signed , uint32_t sample_rate ) {
46
+ #define ADC_CLOCK_INPUT 48000000
47
+ #define ADC_MAX_CLOCK_DIV (1 << (ADC_DIV_INT_MSB - ADC_DIV_INT_LSB + 1))
46
48
49
+ void common_hal_analogbufio_bufferedin_construct (analogbufio_bufferedin_obj_t * self , const mcu_pin_obj_t * pin , uint32_t sample_rate ) {
47
50
// Make sure pin number is in range for ADC
48
51
if (pin -> number < ADC_FIRST_PIN_NUMBER || pin -> number >= (ADC_FIRST_PIN_NUMBER + ADC_PIN_COUNT )) {
49
52
raise_ValueError_invalid_pins ();
50
53
}
51
54
55
+ // Validate sample rate here
56
+ sample_rate = (uint32_t )mp_arg_validate_int_range (sample_rate , ADC_CLOCK_INPUT / ADC_MAX_CLOCK_DIV , ADC_CLOCK_INPUT / 96 , MP_QSTR_sample_rate );
57
+
52
58
// Set pin and channel
53
59
self -> pin = pin ;
54
60
claim_pin (pin );
55
61
56
62
// TODO: find a way to accept ADC4 for temperature
57
63
self -> chan = pin -> number - ADC_FIRST_PIN_NUMBER ;
58
64
59
- // Set buffer and length
60
- self -> buffer = buffer ;
61
- self -> len = len ;
62
-
63
- // Set sample rate - used in read
64
- self -> bytes_per_sample = bytes_per_sample ;
65
- self -> sample_rate = sample_rate ;
66
-
67
65
// Init GPIO for analogue use: hi-Z, no pulls, disable digital input buffer.
66
+ // TODO: Make sure we share the ADC well. Right now we just assume it is
67
+ // unused.
68
68
adc_init ();
69
69
adc_gpio_init (pin -> number );
70
70
adc_select_input (self -> chan ); // chan = pin - 26 ??
71
71
72
- // RP2040 Implementation Detail
73
- // Fills the supplied buffer with ADC values using DMA transfer.
74
- // If the buffer is 8-bit, then values are 8-bit shifted and error bit is off.
75
- // If buffer is 16-bit, then values are not shifted and error bit is present.
76
- // Number of transfers is always the number of samples which is the array
77
- // byte length divided by the bytes_per_sample.
78
-
79
- // self->bytes_per_sample == 1
80
- uint dma_size = DMA_SIZE_8 ;
81
- bool show_error_bit = false;
82
- bool shift_sample_8_bits = true;
83
- if (self -> bytes_per_sample == 2 ) {
84
- dma_size = DMA_SIZE_16 ;
85
- show_error_bit = true;
86
- shift_sample_8_bits = false;
87
- }
88
-
89
- // adc_select_input(self->pin->number - ADC_FIRST_PIN_NUMBER);
90
- adc_fifo_setup (
91
- true, // Write each completed conversion to the sample FIFO
92
- true, // Enable DMA data request (DREQ)
93
- 1 , // DREQ (and IRQ) asserted when at least 1 sample present
94
- show_error_bit , // See the ERR bit
95
- shift_sample_8_bits // Shift each sample to 8 bits when pushing to FIFO
96
- );
97
-
98
72
// Divisor of 0 -> full speed. Free-running capture with the divider is
99
73
// equivalent to pressing the ADC_CS_START_ONCE button once per `div + 1`
100
74
// cycles (div not necessarily an integer). Each conversion takes 96
@@ -104,7 +78,8 @@ void common_hal_analogbufio_bufferedin_construct(analogbufio_bufferedin_obj_t *s
104
78
// sample rate determines divisor, not zero.
105
79
106
80
// sample_rate is forced to be >= 1 in shared-bindings
107
- adc_set_clkdiv ((float )48000000.0 / (float )self -> sample_rate );
81
+ float clk_div = (float )ADC_CLOCK_INPUT / (float )sample_rate ;
82
+ adc_set_clkdiv (clk_div );
108
83
109
84
// Set up the DMA to start transferring data as soon as it appears in FIFO
110
85
uint dma_chan = dma_claim_unused_channel (true);
@@ -114,7 +89,6 @@ void common_hal_analogbufio_bufferedin_construct(analogbufio_bufferedin_obj_t *s
114
89
self -> cfg = dma_channel_get_default_config (dma_chan );
115
90
116
91
// Reading from constant address, writing to incrementing byte addresses
117
- channel_config_set_transfer_data_size (& (self -> cfg ), dma_size );
118
92
channel_config_set_read_increment (& (self -> cfg ), false);
119
93
channel_config_set_write_increment (& (self -> cfg ), true);
120
94
@@ -143,14 +117,38 @@ void common_hal_analogbufio_bufferedin_deinit(analogbufio_bufferedin_obj_t *self
143
117
dma_channel_unclaim (self -> dma_chan );
144
118
}
145
119
146
- void common_hal_analogbufio_bufferedin_read (analogbufio_bufferedin_obj_t * self ) {
120
+ uint32_t common_hal_analogbufio_bufferedin_readinto (analogbufio_bufferedin_obj_t * self , uint8_t * buffer , uint32_t len , uint8_t bytes_per_sample ) {
121
+ // RP2040 Implementation Detail
122
+ // Fills the supplied buffer with ADC values using DMA transfer.
123
+ // If the buffer is 8-bit, then values are 8-bit shifted and error bit is off.
124
+ // If buffer is 16-bit, then values are 12-bit and error bit is present. We
125
+ // stretch the 12-bit value to 16-bits and truncate the number of valid
126
+ // samples at the first sample with the error bit set.
127
+ // Number of transfers is always the number of samples which is the array
128
+ // byte length divided by the bytes_per_sample.
129
+ uint dma_size = DMA_SIZE_8 ;
130
+ bool show_error_bit = false;
131
+ if (bytes_per_sample == 2 ) {
132
+ dma_size = DMA_SIZE_16 ;
133
+ show_error_bit = true;
134
+ }
147
135
148
- uint32_t cdl = self -> len / self -> bytes_per_sample ;
136
+ adc_fifo_setup (
137
+ true, // Write each completed conversion to the sample FIFO
138
+ true, // Enable DMA data request (DREQ)
139
+ 1 , // DREQ (and IRQ) asserted when at least 1 sample present
140
+ show_error_bit , // See the ERR bit
141
+ bytes_per_sample == 1 // Shift each sample to 8 bits when pushing to FIFO
142
+ );
143
+
144
+ uint32_t sample_count = len / bytes_per_sample ;
145
+
146
+ channel_config_set_transfer_data_size (& (self -> cfg ), dma_size );
149
147
150
148
dma_channel_configure (self -> dma_chan , & (self -> cfg ),
151
- self -> buffer , // dst
149
+ buffer , // dst
152
150
& adc_hw -> fifo , // src
153
- cdl , // transfer count
151
+ sample_count , // transfer count
154
152
true // start immediately
155
153
);
156
154
@@ -159,9 +157,34 @@ void common_hal_analogbufio_bufferedin_read(analogbufio_bufferedin_obj_t *self)
159
157
160
158
// Once DMA finishes, stop any new conversions from starting, and clean up
161
159
// the FIFO in case the ADC was still mid-conversion.
162
- dma_channel_wait_for_finish_blocking (self -> dma_chan );
160
+ uint32_t remaining_transfers = sample_count ;
161
+ while (dma_channel_is_busy (self -> dma_chan ) &&
162
+ !mp_hal_is_interrupted ()) {
163
+ RUN_BACKGROUND_TASKS ;
164
+ }
165
+ remaining_transfers = dma_channel_hw_addr (self -> dma_chan )-> transfer_count ;
163
166
164
167
// Clean up
165
168
adc_run (false);
169
+ // Stopping early so abort.
170
+ if (dma_channel_is_busy (self -> dma_chan )) {
171
+ dma_channel_abort (self -> dma_chan );
172
+ }
166
173
adc_fifo_drain ();
174
+
175
+ size_t captured_count = sample_count - remaining_transfers ;
176
+ if (dma_size == DMA_SIZE_16 ) {
177
+ uint16_t * buf16 = (uint16_t * )buffer ;
178
+ for (size_t i = 0 ; i < captured_count ; i ++ ) {
179
+ uint16_t value = buf16 [i ];
180
+ // Check the error bit and "truncate" the buffer if there is an error.
181
+ if ((value & ADC_FIFO_ERR_BITS ) != 0 ) {
182
+ captured_count = i ;
183
+ break ;
184
+ }
185
+ // Scale the values to the standard 16 bit range.
186
+ buf16 [i ] = (value << 4 ) | (value >> 8 );
187
+ }
188
+ }
189
+ return captured_count ;
167
190
}
0 commit comments