3333#include "common-hal/analogbufio/BufferedIn.h"
3434#include "shared-bindings/analogbufio/BufferedIn.h"
3535#include "shared-bindings/microcontroller/Pin.h"
36+ #include "shared/runtime/interrupt_char.h"
3637#include "py/runtime.h"
3738#include "supervisor/shared/translate/translate.h"
3839#include "src/rp2_common/hardware_adc/include/hardware/adc.h"
4243#define ADC_FIRST_PIN_NUMBER 26
4344#define ADC_PIN_COUNT 4
4445
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))
4648
49+ void common_hal_analogbufio_bufferedin_construct (analogbufio_bufferedin_obj_t * self , const mcu_pin_obj_t * pin , uint32_t sample_rate ) {
4750 // Make sure pin number is in range for ADC
4851 if (pin -> number < ADC_FIRST_PIN_NUMBER || pin -> number >= (ADC_FIRST_PIN_NUMBER + ADC_PIN_COUNT )) {
4952 raise_ValueError_invalid_pins ();
5053 }
5154
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+
5258 // Set pin and channel
5359 self -> pin = pin ;
5460 claim_pin (pin );
5561
5662 // TODO: find a way to accept ADC4 for temperature
5763 self -> chan = pin -> number - ADC_FIRST_PIN_NUMBER ;
5864
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-
6765 // 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.
6868 adc_init ();
6969 adc_gpio_init (pin -> number );
7070 adc_select_input (self -> chan ); // chan = pin - 26 ??
7171
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-
9872 // Divisor of 0 -> full speed. Free-running capture with the divider is
9973 // equivalent to pressing the ADC_CS_START_ONCE button once per `div + 1`
10074 // 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
10478 // sample rate determines divisor, not zero.
10579
10680 // 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 );
10883
10984 // Set up the DMA to start transferring data as soon as it appears in FIFO
11085 uint dma_chan = dma_claim_unused_channel (true);
@@ -114,7 +89,6 @@ void common_hal_analogbufio_bufferedin_construct(analogbufio_bufferedin_obj_t *s
11489 self -> cfg = dma_channel_get_default_config (dma_chan );
11590
11691 // Reading from constant address, writing to incrementing byte addresses
117- channel_config_set_transfer_data_size (& (self -> cfg ), dma_size );
11892 channel_config_set_read_increment (& (self -> cfg ), false);
11993 channel_config_set_write_increment (& (self -> cfg ), true);
12094
@@ -143,14 +117,38 @@ void common_hal_analogbufio_bufferedin_deinit(analogbufio_bufferedin_obj_t *self
143117 dma_channel_unclaim (self -> dma_chan );
144118}
145119
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+ }
147135
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 );
149147
150148 dma_channel_configure (self -> dma_chan , & (self -> cfg ),
151- self -> buffer , // dst
149+ buffer , // dst
152150 & adc_hw -> fifo , // src
153- cdl , // transfer count
151+ sample_count , // transfer count
154152 true // start immediately
155153 );
156154
@@ -159,9 +157,34 @@ void common_hal_analogbufio_bufferedin_read(analogbufio_bufferedin_obj_t *self)
159157
160158 // Once DMA finishes, stop any new conversions from starting, and clean up
161159 // 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 ;
163166
164167 // Clean up
165168 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+ }
166173 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 ;
167190}
0 commit comments