Trying to get an RP2040 USB audio to i2s working. #5
-
Hi, Firstly thank you for all your hard work on this port and Arduino audio tools. I am trying to get working a RP2040 to be a simple USB interface and transfer audio via i2s to a DAC. Eventually to get a working usb wifi audio transmitter to a receiving end. I have the receiving end working with Arduino Audio tools Vban->i2s with an esp32s3 and the same DAC listed below. It is working using the Voicemeter software to send out the vban stream. However I am looking to get it via usb for the transmitter rather than requiring Voicemeter. Hardware I am using: The RP2040 board - https://www.aliexpress.com/item/1005007650325892.html Pin config: The code:
Platformio config:
Problem I am having: I tried just the usb side by just outputting the data directly to serial instead of i2s the data gets sent and doesn't appear to lock up. So thinking it might be an i2s issue I tried both a generator example and mp3 (from memory) to i2s (from Arduino audio tools). Both played as expected with clear audio and didn't lock up. The i2s side of the configuration was left identical to when it was using the usb as the input. I thought maybe it was an issue with the wiring so I changed around to different pins and tried some jumper cables instead of the breadboard. This didn't appear to make any difference at all. I tried playing around with different sample rate/channel/bit configs as well but didn't appear to make any difference. Something I did notice is if I set the sample rate to 48000 (running on windows 11) it doesn't seem to pick up that its 48000 as per the sound settings window. Set to 44100 however, it does show up. So I am at a loss on what to try next. I am not a super good programmer and more so a webdev rather than more complex c/c++ code. If ideally the code should work maybe there is an issue with the RP2040 I have. If so I'll try ordering some different variants of them and try with those. If there is anything you can think of to try I would greatly appreciate it. Thanks, Have a great day! |
Beta Was this translation helpful? Give feedback.
Replies: 7 comments 16 replies
-
I would like to know if it will work at 48 kHz too. Thank you for testing this for me. I hope this can be made to work in the future. |
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
Since you did not comment out the Serial.print in the loop(): what does the log say ? |
Beta Was this translation helpful? Give feedback.
-
I needed to extend the AudioTools a bit to provide some RP2040 concurrency classes: I am writing the data into a queue and process it in the loop to output the i2s. I haven't connected a DAC yet but the this implementation is not blocking any more: #include "Adafruit_TinyUSB.h"
#include "AudioTools.h"
#include "AudioTools/Concurrency/RP2040.h"
AudioInfo info(44100, 2, 16);
Adafruit_USBD_Audio usb;
BufferRP2040 buffer(1024, 10); // Multi-core and IRQ safe queue
QueueStream queue(buffer); // Stream API for queue
I2SStream i2s; // i2s output
StreamCopy copier(i2s, queue);
size_t writeCB(const uint8_t* data, size_t len, Adafruit_USBD_Audio& ref) {
return queue.write(data, len); // fill the queue with data from USB
}
void setup() {
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
while(!Serial); // wait for serial
Serial.println("starting...");
// start queue
queue.begin();
// start i2s
auto cfg = i2s.defaultConfig(TX_MODE);
cfg.copyFrom(info);
i2s.begin(cfg);
// Start USB device as Audio Sink
usb.setWriteCallback(writeCB);
usb.begin(info.sample_rate, info.channels, info.bits_per_sample);
// If already enumerated, additional class driverr begin() e.g msc, hid, midi won't take effect until re-enumeration
if (TinyUSBDevice.mounted()) {
TinyUSBDevice.detach();
delay(10);
TinyUSBDevice.attach();
}
}
void loop() {
usb.updateLED();
copier.copy();
}
If the quality is not good, change the log level from Info to Warning |
Beta Was this translation helpful? Give feedback.
-
I think I have made some progress now: it is not locking up any more at the playback: the key was to move the i2s ougpug to the other core: #include "Adafruit_TinyUSB.h"
#include "AudioTools.h"
#include "AudioTools/Concurrency/RP2040.h"
AudioInfo info(44100, 2, 16);
Adafruit_USBD_Audio usb;
BufferRP2040 buffer(1024, 10);
QueueStream queue(buffer);
I2SStream i2s;
StreamCopy copier(i2s, queue);
size_t writeCB(const uint8_t* data, size_t len, Adafruit_USBD_Audio& ref) {
return queue.write(data, len);
}
void setup() {
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
//while(!Serial); // wait for serial
delay(1000);
Serial.println("starting...");
// start queue
queue.begin();
//start i2s
auto cfg = i2s.defaultConfig(TX_MODE);
cfg.copyFrom(info);
if (!i2s.begin(cfg)){
Serial.print("i2s error");
}
// Start USB device as Audio Sink
usb.setWriteCallback(writeCB);
if (!usb.begin(info.sample_rate, info.channels, info.bits_per_sample)){
Serial.println("USB error");
}
// If already enumerated, additional class driverr begin() e.g msc, hid, midi won't take effect until re-enumeration
if (TinyUSBDevice.mounted()) {
TinyUSBDevice.detach();
delay(10);
TinyUSBDevice.attach();
}
}
void loop() {
usb.updateLED();
}
void loop1() {
copier.copy();
} |
Beta Was this translation helpful? Give feedback.
-
I added some manual feedback support which takes the buffer fill status into consideration. This is working now w/o any under or overruns: #include "Adafruit_TinyUSB.h"
#include "AudioTools.h"
#include "AudioTools/Concurrency/RP2040.h"
AudioInfo info(44100, 2, 16);
Adafruit_USBD_Audio usb;
BufferRP2040 buffer(256, 20);
QueueStream queue(buffer);
I2SStream i2s;
StreamCopy copier(i2s, queue);
size_t writeCB(const uint8_t* data, size_t len, Adafruit_USBD_Audio& ref) {
usb.setFeedbackPercent(buffer.size()*100 / buffer.available());
return queue.write(data, len);
}
void setup() {
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning);
while(!Serial); // wait for serial
Serial.println("starting...");
// start queue
queue.begin(80);
// Start USB device as Audio Sink
usb.setFeedbackMethod(AUDIO_FEEDBACK_METHOD_DISABLED);
usb.setWriteCallback(writeCB);
if (!usb.begin(info.sample_rate, info.channels, info.bits_per_sample)){
Serial.println("USB error");
}
// If already enumerated, additional class driverr begin() e.g msc, hid, midi won't take effect until re-enumeration
if (TinyUSBDevice.mounted()) {
TinyUSBDevice.detach();
delay(10);
TinyUSBDevice.attach();
}
}
void loop() {
usb.updateLED();
}
void setup1(){
//start i2s
auto cfg = i2s.defaultConfig(TX_MODE);
cfg.copyFrom(info);
cfg.buffer_size = 256;
cfg.buffer_count = 3;
if (!i2s.begin(cfg)){
Serial.print("i2s error");
}
}
void loop1() {
copier.copy();
}
|
Beta Was this translation helpful? Give feedback.
-
Could we use the DMA to feed the I2S? |
Beta Was this translation helpful? Give feedback.
I added some manual feedback support which takes the buffer fill status into consideration. This is working now w/o any under or overruns: