* Convert to SDK RP2350A/B determination Fixes #2878 The SDK uses `defined(PICO_RP2350) && !PICO_RP2350A` to indicate an RP2350B chip, not the define PICO_RP2350B. Match the SDK's usage by converting from `defined(PICO_RP2350B)` to `defined(PICO_RP2350) && !PICO_RP2350A` and update the chip variants accordingly. * Need to explicitly override PICO_RP2350A for all The *SDK*'s board definition file hardcodes a PICO_RP2350A value for all boards, but we use the same board file for both A and B variants. Override the SDK board definition in the variant definition file. * Generic RP2350 needs 2-stage PICO_RP2350A setting Also ensure SDK board definition included before pins_arduino.h for clearing up redefinition errors. * Factor out undef PICO_RP2350A * Update Arduino.h
200 lines
4.7 KiB
C++
200 lines
4.7 KiB
C++
/*
|
|
ADCInput
|
|
Records ADC values (i.e. microphone, sensors) and presents an I2S-like
|
|
callback/immediate read interface
|
|
|
|
Copyright (c) 2023 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with this library; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#include <Arduino.h>
|
|
#include "ADCInput.h"
|
|
#include <hardware/adc.h>
|
|
|
|
ADCInput::ADCInput(pin_size_t p0, pin_size_t p1, pin_size_t p2, pin_size_t p3, pin_size_t p4, pin_size_t p5, pin_size_t p6, pin_size_t p7) {
|
|
_running = false;
|
|
setPins(p0, p1, p2, p3, p4, p5, p6, p7);
|
|
_freq = 48000;
|
|
_arb = nullptr;
|
|
_cb = nullptr;
|
|
_buffers = 8;
|
|
_bufferWords = 0;
|
|
}
|
|
|
|
ADCInput::~ADCInput() {
|
|
end();
|
|
}
|
|
|
|
bool ADCInput::setBuffers(size_t buffers, size_t bufferWords) {
|
|
if (_running || (buffers < 3) || (bufferWords < 8)) {
|
|
return false;
|
|
}
|
|
_buffers = buffers;
|
|
_bufferWords = bufferWords;
|
|
return true;
|
|
}
|
|
|
|
int ADCInput::_mask(pin_size_t p) {
|
|
switch (p) {
|
|
#if defined(PICO_RP2350) && !PICO_RP2350A // RP2350B
|
|
case 26: return 1;
|
|
case 27: return 2;
|
|
case 28: return 4;
|
|
case 29: return 8;
|
|
#else // Starts at 40 and there are 8 of them
|
|
case 40: return 1;
|
|
case 41: return 2;
|
|
case 42: return 4;
|
|
case 43: return 8;
|
|
case 44: return 16;
|
|
case 45: return 32;
|
|
case 46: return 64;
|
|
case 47: return 128;
|
|
#endif
|
|
default: return 0;
|
|
}
|
|
}
|
|
|
|
bool ADCInput::setPins(pin_size_t pin0, pin_size_t pin1, pin_size_t pin2, pin_size_t pin3, pin_size_t pin4, pin_size_t pin5, pin_size_t pin6, pin_size_t pin7) {
|
|
if (_running) {
|
|
return false;
|
|
}
|
|
_pinMask = _mask(pin0) | _mask(pin1) | _mask(pin2) | _mask(pin3) | _mask(pin4) | _mask(pin5) | _mask(pin6) | _mask(pin7);
|
|
return true;
|
|
}
|
|
|
|
bool ADCInput::setFrequency(int newFreq) {
|
|
_freq = newFreq;
|
|
int scaledFreq = newFreq * __builtin_popcount(_pinMask); // Want to sample all channels at given frequency
|
|
adc_set_clkdiv(48000000.0f / scaledFreq - 1.0f);
|
|
return true;
|
|
}
|
|
|
|
void ADCInput::onReceive(void(*fn)(void)) {
|
|
_cb = fn;
|
|
if (_running) {
|
|
_arb->setCallback(_cb);
|
|
}
|
|
}
|
|
|
|
bool ADCInput::begin() {
|
|
if (_running) {
|
|
return false;
|
|
}
|
|
|
|
_running = true;
|
|
|
|
_isHolding = 0;
|
|
|
|
if (!_bufferWords) {
|
|
_bufferWords = 16;
|
|
}
|
|
|
|
// Set up the GPIOs to go to ADC
|
|
adc_init();
|
|
int cnt = 0;
|
|
#if defined(PICO_RP2350) && !PICO_RP2350A // RP2350B
|
|
int startpin = 26;
|
|
int maxpin = 29;
|
|
#else
|
|
int startpin = 40;
|
|
int maxpin = 47;
|
|
#endif
|
|
for (int mask = 1, pin = startpin; pin <= maxpin; mask <<= 1, pin++) {
|
|
if (_pinMask & mask) {
|
|
if (!cnt) {
|
|
adc_select_input(pin - startpin);
|
|
}
|
|
cnt++;
|
|
adc_gpio_init(pin);
|
|
}
|
|
}
|
|
adc_set_round_robin(_pinMask);
|
|
adc_fifo_setup(true, true, 1, false, false);
|
|
|
|
setFrequency(_freq);
|
|
|
|
_arb = new AudioBufferManager(_buffers, _bufferWords, 0, INPUT, DMA_SIZE_16);
|
|
if (!_arb->begin(DREQ_ADC, (volatile void*)&adc_hw->fifo)) {
|
|
delete _arb;
|
|
_arb = nullptr;
|
|
return false;
|
|
}
|
|
_arb->setCallback(_cb);
|
|
|
|
adc_fifo_drain();
|
|
|
|
adc_run(true);
|
|
|
|
return true;
|
|
}
|
|
|
|
void ADCInput::end() {
|
|
if (_running) {
|
|
_running = false;
|
|
delete _arb;
|
|
_arb = nullptr;
|
|
}
|
|
adc_run(false);
|
|
adc_fifo_drain();
|
|
}
|
|
|
|
int ADCInput::available() {
|
|
if (!_running) {
|
|
return 0;
|
|
} else {
|
|
return _arb->available();
|
|
}
|
|
}
|
|
|
|
int ADCInput::read() {
|
|
if (!_running) {
|
|
return -1;
|
|
}
|
|
|
|
if (_hasPeeked) {
|
|
_hasPeeked = false;
|
|
return _peekSaved;
|
|
}
|
|
|
|
if (_isHolding <= 0) {
|
|
_arb->read(&_holdWord, true);
|
|
_isHolding = 32;
|
|
}
|
|
|
|
int ret = _holdWord & 0x0fff;
|
|
_holdWord >>= 16;
|
|
_isHolding -= 16;
|
|
return ret;
|
|
}
|
|
|
|
int ADCInput::peek() {
|
|
if (!_running) {
|
|
return -1;
|
|
}
|
|
if (!_hasPeeked) {
|
|
_peekSaved = read();
|
|
_hasPeeked = true;
|
|
}
|
|
return _peekSaved;
|
|
}
|
|
|
|
void ADCInput::flush() {
|
|
if (_running) {
|
|
_arb->flush();
|
|
}
|
|
}
|