8000 Merge pull request #6757 from latkinso42/adcdma · litui/circuitpython@8a568d1 · GitHub
[go: up one dir, main page]

Skip to content

Commit 8a568d1

Browse files
authored
Merge pull request adafruit#6757 from latkinso42/adcdma
analogbufio
2 parents 4a69dfa + 6bb4703 commit 8a568d1

File tree

11 files changed

+577
-1
lines changed

11 files changed

+577
-1
lines changed

locale/circuitpython.pot

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ msgstr ""
7979
msgid "%q"
8080
msgstr ""
8181

82+
#: shared-bindings/analogbufio/BufferedIn.c
83+
msgid "%q ``must`` be a bytearray or array of type 'h', 'H', 'b' or 'B'"
84+
msgstr ""
85+
8286
#: shared-bindings/microcontroller/Pin.c
8387
msgid "%q and %q contain duplicate pins"
8488
msgstr ""
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* SPDX-FileCopyrightText: Copyright (c) 2022 Lee Atkinson, MeanStride Technology, Inc.
7+
*
8+
* SPDX-License-Identifier: BSD-3-Clause
9+
*
10+
* Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
11+
* https://github.com/raspberrypi/pico-examples/blob/master/adc/dma_capture/dma_capture.c
12+
*
13+
* Permission is hereby granted, free of charge, to any person obtaining a copy
14+
* of this software and associated documentation files (the "Software"), to deal
15+
* in the Software without restriction, including without limitation the rights
16+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17+
* copies of the Software, and to permit persons to whom the Software is
18+
* furnished to do so, subject to the following conditions:
19+
*
20+
* The above copyright notice and this permission notice shall be included in
21+
* all copies or substantial portions of the Software.
22+
*
23+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29+
* THE SOFTWARE.
30+
*/
31+
32+
#include <stdio.h>
33+
#include "common-hal/analogbufio/BufferedIn.h"
34+
#include "shared-bindings/analogbufio/BufferedIn.h"
35+
#include "shared-bindings/microcontroller/Pin.h"
36+
#include "py/runtime.h"
37+
#include "supervisor/shared/translate/translate.h"
38+
#include "src/rp2_common/hardware_adc/include/hardware/adc.h"
39+
#include "src/rp2_common/hardware_dma/include/hardware/dma.h"
40+
#include "src/common/pico_stdlib/include/pico/stdlib.h"
41+
42+
#define ADC_FIRST_PIN_NUMBER 26
43+
#define ADC_PIN_COUNT 4
44+
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+
47+
// Make sure pin number is in range for ADC
48+
if (pin->number < ADC_FIRST_PIN_NUMBER || pin->number >= (ADC_FIRST_PIN_NUMBER + ADC_PIN_COUNT)) {
49+
raise_ValueError_invalid_pins();
50+
}
51+
52+
// Set pin and channel
53+
self->pin = pin;
54+
claim_pin(pin);
55+
56+
// TODO: find a way to accept ADC4 for temperature
57+
self->chan = pin->number - ADC_FIRST_PIN_NUMBER;
58+
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+
// Init GPIO for analogue use: hi-Z, no pulls, disable digital input buffer.
68+
adc_init();
69+
adc_gpio_init(pin->number);
70+
adc_select_input(self->chan); // chan = pin - 26 ??
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+
// Divisor of 0 -> full speed. Free-running capture with the divider is
99+
// equivalent to pressing the ADC_CS_START_ONCE button once per `div + 1`
100+
// cycles (div not necessarily an integer). Each conversion takes 96
101+
// cycles, so in general you want a divider of 0 (hold down the button
102+
// continuously) or > 95 (take samples less frequently than 96 cycle
103+
// intervals). This is all timed by the 48 MHz ADC clock.
104+
// sample rate determines divisor, not zero.
105+
106+
// sample_rate is forced to be >= 1 in shared-bindings
107+
adc_set_clkdiv((float)48000000.0 / (float)self->sample_rate);
108+
109+
// Set up the DMA to start transferring data as soon as it appears in FIFO
110+
uint dma_chan = dma_claim_unused_channel(true);
111+
self->dma_chan = dma_chan;
112+
113+
// Set Config
114+
self->cfg = dma_channel_get_default_config(dma_chan);
115+
116+
// Reading from constant address, writing to incrementing byte addresses
117+
channel_config_set_transfer_data_size(&(self->cfg), dma_size);
118+
channel_config_set_read_increment(&(self->cfg), false);
119+
channel_config_set_write_increment(&(self->cfg), true);
120+
121+
// Pace transfers based on availability of ADC samples
122+
channel_config_set_dreq(&(self->cfg), DREQ_ADC);
123+
124+
// clear any previous activity
125+
adc_fifo_drain();
126+
adc_run(false);
127+
}
128+
129+
bool common_hal_analogbufio_bufferedin_deinited(analogbufio_bufferedin_obj_t *self) {
130+
return self->pin == NULL;
131+
}
132+
133+
void common_hal_analogbufio_bufferedin_deinit(analogbufio_bufferedin_obj_t *self) {
134+
if (common_hal_analogbufio_bufferedin_deinited(self)) {
135+
return;
136+
}
137+
138+
// Release ADC Pin
139+
reset_pin_number(self->pin->number);
140+
self->pin = NULL;
141+
142+
// Release DMA Channel
143+
dma_channel_unclaim(self->dma_chan);
144+
}
145+
146+
void common_hal_analogbufio_bufferedin_read(analogbufio_bufferedin_obj_t *self) {
147+
148+
uint32_t cdl = self->len / self->bytes_per_sample;
149+
150+
dma_channel_configure(self->dma_chan, &(self->cfg),
151+
self->buffer, // dst
152+
&adc_hw->fifo, // src
153+
cdl, // transfer count
154+
true // start immediately
155+
);
156+
157+
// Start the ADC
158+
adc_run(true);
159+
160+
// Once DMA finishes, stop any new conversions from starting, and clean up
161+
// the FIFO in case the ADC was still mid-conversion.
162+
dma_channel_wait_for_finish_blocking(self->dma_chan);
163+
164+
// Clean up
165+
adc_run(false);
166+
adc_fifo_drain();
167+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* SPDX-FileCopyrightText: Copyright (c) 2022 Lee Atkinson, MeanStride Technology, Inc.
F987 7+
*
8+
* SPDX-License-Identifier: BSD-3-Clause
9+
*
10+
* Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
11+
* https://github.com/raspberrypi/pico-examples/blob/master/adc/dma_capture/dma_capture.c
12+
*
13+
* Permission is hereby granted, free of charge, to any person obtaining a copy
14+
* of this software and associated documentation files (the "Software"), to deal
15+
* in the Software without restriction, including without limitation the rights
16+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17+
* copies of the Software, and to permit persons to whom the Software is
18+
* furnished to do so, subject to the following conditions:
19+
*
20+
* The above copyright notice and this permission notice shall be included in
21+
* all copies or substantial portions of the Software.
22+
*
23+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29+
* THE SOFTWARE.
30+
*/
31+
32+
#ifndef MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_ANALOGBUFIO_BUFFEREDIN_H
33+
#define MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_ANALOGBUFIO_BUFFEREDIN_H
34+
35+
#include "common-hal/microcontroller/Pin.h"
36+
#include "src/rp2_common/hardware_dma/include/hardware/dma.h"
37+
38+
#include "py/obj.h"
39+
40+
// This is the analogbufio object
41+
typedef struct {
42+
mp_obj_base_t base;
43+
const mcu_pin_obj_t *pin;
44+
uint8_t *buffer;
45+
uint32_t len;
46+
uint8_t bytes_per_sample;
47+
bool samples_signed;
48+
uint32_t sample_rate;
49+
uint8_t chan;
50+
uint dma_chan;
51+
dma_channel_config cfg;
52+
} analogbufio_bufferedin_obj_t;
53+
54+
void bufferedin_init(void);
55+
56+
#endif // MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_ANALOGBUFIO_BUFFEREDIN_H
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
// No analogbufio module functions.

ports/raspberrypi/mpconfigport.mk

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ CIRCUITPY_NVM = 1
2626
CIRCUITPY_PULSEIO ?= 1
2727
CIRCUITPY_WATCHDOG ?= 1
2828

29+
# Use of analogbufio
30+
CIRCUITPY_ANALOGBUFIO = 1
31+
2932
# Audio via PWM
3033
CIRCUITPY_AUDIOIO = 0
3134
CIRCUITPY_AUDIOBUSIO ?= 1

py/circuitpy_defns.mk

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,9 @@ endif
109109
ifeq ($(CIRCUITPY_ALARM),1)
110110
SRC_PATTERNS += alarm/%
111111
endif
112+
ifeq ($(CIRCUITPY_ANALOGBUFIO),1)
113+
SRC_PATTERNS += analogbufio/%
114+
endif
112115
ifeq ($(CIRCUITPY_ANALOGIO),1)
113116
SRC_PATTERNS += analogio/%
114117
endif
@@ -391,6 +394,8 @@ SRC_COMMON_HAL_ALL = \
391394
alarm/pin/PinAlarm.c \
392395
alarm/time/TimeAlarm.c \
393396
alarm/touch/TouchAlarm.c \
397+
analogbufio/BufferedIn.c \
398+
analogbufio/__init__.c \
394399
analogio/AnalogIn.c \
395400
analogio/AnalogOut.c \
396401
analogio/__init__.c \
@@ -481,7 +486,6 @@ SRC_C += \
481486

482487
endif
483488

484-
485489
SRC_COMMON_HAL = $(filter $(SRC_PATTERNS), $(SRC_COMMON_HAL_ALL))
486490

487491
# These don't have corresponding files in each port but are still located in

py/circuitpy_mpconfig.mk

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ CFLAGS += -DCIRCUITPY_AESIO=$(CIRCUITPY_AESIO)
6262
CIRCUITPY_ALARM ?= 0
6363
CFLAGS += -DCIRCUITPY_ALARM=$(CIRCUITPY_ALARM)
6464

65+
CIRCUITPY_ANALOGBUFIO ?= 0
66+
CFLAGS += -DCIRCUITPY_ANALOGBUFIO=$(CIRCUITPY_ANALOGBUFIO)
67+
6568
CIRCUITPY_ANALOGIO ?= 1
6669
CFLAGS += -DCIRCUITPY_ANALOGIO=$(CIRCUITPY_ANALOGIO)
6770

0 commit comments

Comments
 (0)
0