Meanwhile there is an official Arduino support based on mbed.
https://github.com/arduino/ArduinoCore-mbed
https://github.com/arduino/ArduinoCore-mbed
it's probably possible, that is, there is sufficient computing power available. But how much Library development are you willing to do, to avoid using the Teensy 4?
Why not just use a Teensy? The libraries are powerful and mature, there's a competent & friendly support community here, and you might find that you need to do more audio processing (ie DSP filtering) on that audio that will never be possible on the Pico.
If Pico is a hard requirement (power, for instance) there are other lower quality audio solutions available. Pimoroni released an audio board for the Pico that includes a C/C++ library. No micropython yet, and about US$20.
https://shop.pimoroni.com/products/pico-audio-pack
CircuitPython on the Pico can do I2S. That may be enough for the Teensy Audio board.
Pico uses the PIO to do I2S. The code could be identical between python & C but does not have to be.If CircuitPython can do it, so should the C SDK, right?
Bill, can you provide access to your pico source code for your ADC/SD logger?
#ifndef AtomicQueue_h
#define AtomicQueue_h
#include <atomic>
template<class T, size_t Size>
class AtomicQueue {
private:
T m_data[Size + 1];
std::atomic<size_t> m_head {0};
std::atomic<size_t> m_tail {0};
size_t next(size_t index) {
return index < Size ? index + 1 : 0;
}
public:
// Not thread/core safe.
void clear() {
m_head.store(0);
m_tail.store(0);
}
bool empty() {
return m_tail.load() == m_head.load();
}
bool full() {
return next(m_tail.load()) == m_head.load();
}
bool try_pop(T& dst) {
size_t head = m_head.load();
if (head == m_tail.load()) {
return false;
}
dst = m_data[head];
m_head.store(next(head));
return true;
}
bool try_push(const T& src) {
size_t tail = m_tail.load();
size_t nextTail = next(tail);
if (nextTail == m_head.load()) {
return false;
}
m_data[tail] = src;
m_tail.store(nextTail);
return true;
}
};
#endif // AtomicQueue_h
#include "pico/multicore.h"
#include "AtomicQueue.h"
#include "SdFat.h"
#if !USE_SPI_ARRAY_TRANSFER
#error "Set USE_SPI_ARRAY_TRANSFER in SdFatConfig.h"
#endif // USE_SPI_ARRAY_TRANSFER
// Max rate until DMA is used for the ADC.
const uint32_t LOG_INTERVAL_USEC = 10; // 100,000 sps.
// Buffer for 200 SD sectors.
const size_t BUF_COUNT = 200;
const uint8_t SD_CS_PIN = SS;
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI)
// Preallocate 1GiB file.
const uint32_t PREALLOCATE_SIZE_MiB = 1024UL;
const uint64_t PREALLOCATE_SIZE = (uint64_t)PREALLOCATE_SIZE_MiB << 20;
// Use exFat
SdFs sd;
FsFile file;
uint16_t bufArray[BUF_COUNT][256];
AtomicQueue<uint16_t*, BUF_COUNT> freeQueue;
AtomicQueue<uint16_t*, BUF_COUNT> fullQueue;
std::atomic<uint32_t> adcErr {0};
std::atomic<bool> adcRun {false};
//==============================================================================
// Core1 ADC process
// Don't use core0 functions in core1.
#define adcError() adcErr.store(__LINE__)
void core1_entry() {
uint16_t* buf = nullptr;
adc_init();
// Make sure GPIO is high-impedance, no pullups etc
adc_gpio_init(26);
// Select ADC input 0 (GPIO26)
adc_select_input(0);
if (!freeQueue.try_pop(buf)) {
adcError();
return;
}
adcRun.store(true);
size_t n = 0;
uint32_t logTime = time_us_32();
while (adcRun.load()) {
logTime += LOG_INTERVAL_USEC;
// Wait until time to log data.
int32_t delta = time_us_32() - logTime;
if (delta > 0) {
adcError();
break;
}
while (delta < 0) {
delta = time_us_32() - logTime;
}
buf[n++] = adc_read();
if (n == 256) {
if (!fullQueue.try_push(buf) || !freeQueue.try_pop(buf)) {
adcError();
break;
}
n = 0;
}
}
// could tell core0 we exited
}
//==============================================================================
// Core0 SD write process
#define error(s) sd.errorHalt(&Serial, s)
void logData() {
uint16_t* buf;
// Initialize SD.
if (!sd.begin(SD_CONFIG)) {
sd.initErrorHalt(&Serial);
}
if (!file.open("PicoLog.bin", O_RDWR | O_CREAT | O_TRUNC)) {
error("file.open failed");
}
if (!file.preAllocate(PREALLOCATE_SIZE)) {
error("preAllocate failed");
}
freeQueue.clear();
fullQueue.clear();
// Put buffers in free queue
for (size_t i = 0; i < BUF_COUNT; i++) {
freeQueue.try_push(bufArray[i]);
}
// clear Serial.
do {
delay(10);
} while (Serial.read() >= 0);
Serial.println("type any character to stop");
multicore_launch_core1(core1_entry);
while (!Serial.available()) {
if (fullQueue.try_pop(buf)) {
if (file.write(buf, 512) != 512) {
error("file.write");
}
if (!freeQueue.try_push(buf)) {
// Bug in queue if this happens.
error("try_push");
}
}
if (adcErr.load()) {
Serial.print("adc error line: ");
Serial.println(adcErr.load());
break;
}
}
adcRun.store(false);
file.truncate();
file.rewind();
// Print first part of file.
for (size_t i = 0; i < 20; i++) {
uint16_t adc;
if (file.read(&adc, 2) != 2) {
error("file.read");
}
Serial.println(adc);
}
Serial.print("FileSize ");
// Warning cast used for print since fileSize is uint64_t.
Serial.println((uint32_t)file.fileSize());
file.close();
Serial.println("done");
}
void setup() {
Serial.begin(9600);
while (!Serial) {}
Serial.println(F("Type any character to begin"));
while (!Serial.available()) {
yield();
}
logData();
}
void loop() {
}
Arduino MKR ZERO SAMD21write speed and latency
speed,max,min,avg
KB/Sec,usec,usec,usec
1929.01,1761,259,260
1929.76,278,259,260
read speed and latency
speed,max,min,avg
KB/Sec,usec,usec,usec
1933.49,263,259,260
1932.74,264,259,260
write speed and latency
speed,max,min,avg
KB/Sec,usec,usec,usec
429.27,1213,1187,1189
429.23,1213,1186,1189
read speed and latency
speed,max,min,avg
KB/Sec,usec,usec,usec
438.80,1172,1161,1163
438.76,1172,1161,1163
> ADC has a design flaw
How much of this can be fixed in software?
● Up to 8 LM32 cores, with private code/data memory
● Programed in bare metal C,using standard GCC tool chain
● Each core runs a single task in a tight loop.
● No caches, no interrupts
● Inter-core communication and task synchronization
● Small, but atomically accessed
Add/subtract
Bit operations
Test-and-set
● Task synchronization primitives
Mutexes
Semaphores
Queues
Flags
Events...
Unlike Arduino, I felt right at home with the BSD Unix development environment from the 1980s
Maybe i overread something, but is the Teensy Audio Library compatible with the Pico Pi? Would like to build some basic stuff TIA