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,9 @@ 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+ mp_printf (& mp_plat_print , "clk_div %f for %d\n" , (double )clk_div , sample_rate );
83+ adc_set_clkdiv (clk_div );
10884
10985 // Set up the DMA to start transferring data as soon as it appears in FIFO
11086 uint dma_chan = dma_claim_unused_channel (true);
@@ -114,7 +90,6 @@ void common_hal_analogbufio_bufferedin_construct(analogbufio_bufferedin_obj_t *s
11490 self -> cfg = dma_channel_get_default_config (dma_chan );
11591
11692 // Reading from constant address, writing to incrementing byte addresses
117- channel_config_set_transfer_data_size (& (self -> cfg ), dma_size );
11893 channel_config_set_read_increment (& (self -> cfg ), false);
11994 channel_config_set_write_increment (& (self -> cfg ), true);
12095
@@ -143,14 +118,36 @@ void common_hal_analogbufio_bufferedin_deinit(analogbufio_bufferedin_obj_t *self
143118 dma_channel_unclaim (self -> dma_chan );
144119}
145120
146- void common_hal_analogbufio_bufferedin_read (analogbufio_bufferedin_obj_t * self ) {
121+ uint32_t common_hal_analogbufio_bufferedin_readinto (analogbufio_bufferedin_obj_t * self , uint8_t * buffer , uint32_t len , uint8_t bytes_per_sample ) {
122+ // RP2040 Implementation Detail
123+ // Fills the supplied buffer with ADC values using DMA transfer.
124+ // If the buffer is 8-bit, then values are 8-bit shifted and error bit is off.
125+ // If buffer is 16-bit, then values are not shifted and error bit is present.
126+ // Number of transfers is always the number of samples which is the array
127+ // byte length divided by the bytes_per_sample.
128+ uint dma_size = DMA_SIZE_8 ;
129+ bool show_error_bit = false;
130+ if (bytes_per_sample == 2 ) {
131+ dma_size = DMA_SIZE_16 ;
132+ show_error_bit = true;
133+ }
134+
135+ adc_fifo_setup (
136+ true, // Write each completed conversion to the sample FIFO
137+ true, // Enable DMA data request (DREQ)
138+ 1 , // DREQ (and IRQ) asserted when at least 1 sample present
139+ show_error_bit , // See the ERR bit
140+ bytes_per_sample == 1 // Shift each sample to 8 bits when pushing to FIFO
141+ );
142+
143+ uint32_t sample_count = len / bytes_per_sample ;
147144
148- uint32_t cdl = self -> len / self -> bytes_per_sample ;
145+ channel_config_set_transfer_data_size ( & ( self -> cfg ), dma_size ) ;
149146
150147 dma_channel_configure (self -> dma_chan , & (self -> cfg ),
151- self -> buffer , // dst
148+ buffer , // dst
152149 & adc_hw -> fifo , // src
153- cdl , // transfer count
150+ sample_count , // transfer count
154151 true // start immediately
155152 );
156153
@@ -159,9 +156,34 @@ void common_hal_analogbufio_bufferedin_read(analogbufio_bufferedin_obj_t *self)
159156
160157 // Once DMA finishes, stop any new conversions from starting, and clean up
161158 // the FIFO in case the ADC was still mid-conversion.
162- dma_channel_wait_for_finish_blocking (self -> dma_chan );
159+ uint32_t remaining_transfers = sample_count ;
160+ while (dma_channel_is_busy (self -> dma_chan ) &&
161+ !mp_hal_is_interrupted ()) {
162+ RUN_BACKGROUND_TASKS ;
163+ }
164+ remaining_transfers = dma_channel_hw_addr (self -> dma_chan )-> transfer_count ;
163165
164166 // Clean up
165167 adc_run (false);
168+ // Stopping early so abort.
169+ if (dma_channel_is_busy (self -> dma_chan )) {
170+ dma_channel_abort (self -> dma_chan );
171+ }
166172 adc_fifo_drain ();
173+
174+ size_t captured_count = sample_count - remaining_transfers ;
175+ if (dma_size == DMA_SIZE_16 ) {
176+ uint16_t * buf16 = (uint16_t * )buffer ;
177+ for (size_t i = 0 ; i < captured_count ; i ++ ) {
178+ uint16_t value = buf16 [i ];
179+ // Check the error bit and "truncate" the buffer if there is an error.
180+ if ((value & ADC_FIFO_ERR_BITS ) != 0 ) {
181+ captured_count = i ;
182+ break ;
183+ }
184+ // Scale the values to the standard 16 bit range.
185+ buf16 [i ] = (value << 4 ) | (value >> 8 );
186+ }
187+ }
188+ return captured_count ;
167189}
0 commit comments