This Solution compiles on a RP2040 now #13
Replies: 5 comments 2 replies
-
Hi, so far I get stuck at the network connection phase I think. I'm using an official RPi Pico, an Ethernet shield W5500 lite and a MAX98357 amplifier on I2S. On the Arduino core side I have tested the WiFiClient-W5500 example successfully. Unfortunately the (current, 3.7.2) core installation on PlatformIO downloads 4GB of framework, 2.5GB in tinyusb, it's a recurring issue I was hoping it was resolved. On Audio Tools side I have tested the Sine and Memory mp3 examples successfully, but not the URL mp3, I don't seem to be able to make the connection between Wiznet5500lwIP, WiFiClient and URLStream. On Snapclient so far
Click to see captured logsThe log before defining the server IP and local MAC is
Log after defining server IP, but not MAC, is
after which I have to unplug the PICO and enter into boot mode to be able to upload again. Log with server IP and local MAC specified
which causes a Snapserver condition that blocks other clients. I had to restart MPD but not Snapserver. Snapdroid recovers by itself, but the client on ESP32 has to be restarted. On PICO I can upload normally after this test. The log settings in platformio.ini are build_flags =
-D CONFIG_ARDUHAL_LOG_COLORS=1
-D CORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_VERBOSE
-D LOG_LOCAL_LEVEL=5 Click to see the code that I have used for tests so far:#if 1
// input test selection
#define EXAMPLE_SNAPCAST 1
#define EXAMPLE_MP3_URL 0
#define EXAMPLE_MP3_MEM 0
#define EXAMPLE_SINE 0
// options
#define SNAPCAST_RTOS_PROCESSOR 1
#define CONFIG_SNAPCAST_SERVER_HOST "192.168.100.100"
#include <AudioTools.h>
I2SStream out;
#if EXAMPLE_SNAPCAST
//#define CONFIG_PROCESSING_TIME_MS (172*2) // default:172
//#define CONFIG_STREAMIN_DECODER_BUFFER (24*1024) // default:12
//#define CONFIG_USE_PSRAM false
#include "SnapClient.h"
#if SNAPCAST_RTOS_PROCESSOR
#include "api/SnapProcessorRTOS.h"
#endif
#define OPUS_DEC_MAX_BUFFER_SIZE (8 * 1024) // default:4
#include "AudioCodecs/CodecOpus.h"
#define ARDUINO_LOOP_STACK_SIZE (10 * 1024) // was 10
OpusAudioDecoder opus;
WiFiClient wifi;
#if defined(ARDUINO_ARCH_RP2040)
#include <W5500lwIP.h>
Wiznet5500lwIP eth(17 /* chip select */, SPI /* SPI interface */, 21 /* Interrupt GPIO */);
#endif
#if SNAPCAST_RTOS_PROCESSOR
SnapProcessorRTOS rtos(1024*8); // define queue with 8 kbytes
#endif
SnapTimeSyncDynamic synch(172, 10); // optional configuratioin
SnapClient client(wifi, out, opus);
#elif EXAMPLE_MP3_URL
#include "AudioCodecs/CodecMP3Helix.h"
URLStream url(CONFIG_WIFI_SSID, CONFIG_WIFI_PASSWORD);
EncodedAudioStream decoded(&out, new MP3DecoderHelix()); // Decoding stream
StreamCopy copier(decoded, url); // copy url to decoder
#elif EXAMPLE_MP3_MEM
#include "AudioCodecs/CodecMP3Helix.h"
//#include <examples/examples-stream/streams-memory_mp3-pwm/BabyElephantWalk60_mp3.h>
#include "BabyElephantWalk60_mp3.h"
MemoryStream mp3(BabyElephantWalk60_mp3, BabyElephantWalk60_mp3_len);
//extern MemoryStream mp3;
EncodedAudioStream decoded(&out, new MP3DecoderHelix()); // output to decoder
StreamCopy copier(decoded, mp3); // copy in to out
#elif EXAMPLE_SINE
AudioInfo info(8000, 1, 16);
SineWaveGenerator<int16_t> sineWave(32000); // subclass of SoundGenerator with max amplitude of 32000
GeneratedSoundStream<int16_t> sound(sineWave); // Stream generated from sine wave
StreamCopy copier(out, sound); // copy in to out
#endif // EXAMPLE global variables
void setup() {
Serial.begin(115200);
AudioLogger::instance().begin(Serial, AudioLogger::Info);
#if EXAMPLE_SNAPCAST
#if SNAPCAST_RTOS_PROCESSOR
// Use FreeRTOS
client.setSnapProcessor(rtos);
#endif
#if defined(ARDUINO_ARCH_RP2040)
// Set up SPI pinout to match your HW
SPI.setRX(16);
SPI.setCS(17);
SPI.setSCK(18);
SPI.setTX(19);
// 20 RST
// 21 INT
delay(1000);
Serial.println();
Serial.println("Starting Ethernet port");
// Start the Ethernet port
if (!eth.begin()) {
Serial.println("No wired Ethernet hardware detected. Check pinouts, wiring.");
while (1) {
delay(1000);
}
}
while (!eth.connected()) {
Serial.print(".");
delay(500);
}
Serial.println("");
Serial.println("Ethernet connected");
Serial.print("Eth IP address: ");
Serial.println(eth.localIP());
uint8_t mac[8];
eth.macAddress(mac);
char mac_address[20];
snprintf(mac_address, sizeof(mac_address), "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
Serial.print("Eth MAC address: ");
Serial.println(mac_address);
//client.setMacAddress(mac_address);
rtos.setMacAddress(mac_address);
Serial.print("WiFi.status(): ");
Serial.println(WiFi.status());
Serial.print("WiFi IP address: ");
Serial.println(WiFi.localIP());
#elif defined(ESP32)
// login to wifi
WiFi.begin(CONFIG_WIFI_SSID, CONFIG_WIFI_PASSWORD);
Serial.print("Connecting to WiFi ..");
while (WiFi.status() != WL_CONNECTED) {
Serial.print('.');
delay(1000);
}
// print ip address
Serial.println();
Serial.println(WiFi.localIP());
#endif
#elif EXAMPLE_MP3_MEM
mp3.setLoop(true);
// update audio info with info from decoder
decoded.addNotifyAudioChange(out);
#elif EXAMPLE_MP3_URL
// update audio info with info from decoder
decoded.addNotifyAudioChange(out);
#elif EXAMPLE_SINE
sineWave.begin(info, N_B4);
#endif // EXAMPLE input
// configure output
auto cfg = out.defaultConfig();
#if defined(ARDUINO_ARCH_RP2040)
cfg.pin_bck = 27;
cfg.pin_ws = 28;
cfg.pin_data = 26;
#elif CONFIG_IDF_TARGET_ESP32S3
cfg.pin_bck = 11;
cfg.pin_ws = 10;
cfg.pin_data = 12;
#else
cfg.pin_bck = 26;
cfg.pin_ws = 25;
cfg.pin_data = 27;
#endif
#if USE_I2S_PDM
cfg.signal_type = audio_tools::I2SSignalType::PDM;
#endif
#if EXAMPLE_SNAPCAST
cfg.sample_rate = 48000;
#elif EXAMPLE_SINE
cfg.sample_rate = 8000;
#endif
out.begin(cfg);
#if EXAMPLE_SNAPCAST
// start snap client
client.begin(synch);
#elif EXAMPLE_MP3_MEM
decoded.begin();
#elif EXAMPLE_MP3_URL
decoded.begin();
// mp3 radio
url.begin("http://stream.srg-ssr.ch/m/rsj/mp3_128", "audio/mp3");
#elif EXAMPLE_SINE
#endif
}
void loop() {
#if EXAMPLE_SNAPCAST
client.doLoop();
//delay(1);
#elif EXAMPLE_MP3_MEM
if (mp3) {
copier.copy();
} else {
auto info = decoded.decoder().audioInfo();
LOGI("The audio rate from the mp3 file is %d", info.sample_rate);
LOGI("The channels from the mp3 file is %d", info.channels);
out.end();
stop();
}
#elif EXAMPLE_MP3_URL
copier.copy();
#elif EXAMPLE_SINE
copier.copy();
#endif
}
#endif // compile (edited to make scrolling easier by moving logs and code into collapsible sections). |
Beta Was this translation helpful? Give feedback.
-
If you don't have a RP2040W that provides WIFi you must not use WiFiClient wifi; but the Client which is relevant for your hardware e.g: Wiznet5500lwIP eth(17 /* chip select /, SPI / SPI interface /, 21 / Interrupt GPIO */); |
Beta Was this translation helpful? Give feedback.
-
I never used any Ethernet board, but I would have expected that the following should work I suggest to try the initialization from this example: |
Beta Was this translation helpful? Give feedback.
-
I'm testing on a RP2040W now, it doesn't get to the loop yet, did you get any better results? The example URL MP3 with Helix sounds garbled on this board, I'm not sure that RP2040 has the processing power to decode Opus. Here is a log taken with debug flag on, click to expand.
Some modified library files ...
#elif defined(ARDUINO_ARCH_RP2040)
# define ESP_LOGE(tag, ...) LOGE(__VA_ARGS__)
# define ESP_LOGW(tag, ...) LOGW(__VA_ARGS__)
# define ESP_LOGI(tag, ...) LOGI(__VA_ARGS__)
# define ESP_LOGD(tag, ...) LOGD(__VA_ARGS__) The current sketch with a battery of tests, modify the #define EXAMPLE_... to select which one to run#if 1
// input, only one example must be selected
#define EXAMPLE_SNAPCAST 0
#define EXAMPLE_MP3_URL 1
#define EXAMPLE_MP3_MEM 0
#define EXAMPLE_SINE 0
#define EXAMPLE_NETWORKED (EXAMPLE_SNAPCAST || EXAMPLE_MP3_URL)
// options
#define SNAPCAST_ON_DIFFERENT_CORE 0
#define SNAPCAST_RTOS_PROCESSOR 1
#define USE_I2S_PDM 0
#if defined(ARDUINO_ARCH_RP2040) && !defined(ARDUINO_RASPBERRY_PI_PICO_W)
#define USE_W5500 1
#endif
#define CONFIG_SNAPCAST_SERVER_HOST "192.168.100.100"
//#pragma GCC push_options
//#pragma GCC optimize ("O3")
#include <AudioTools.h>
I2SStream out;
#if EXAMPLE_NETWORKED
#if USE_W5500
#include <W5500lwIP.h>
//#include <Ethernet.h>
//EthernetClient netClient;
WiFiClient netClient;
Wiznet5500lwIP eth(17 /* chip select */, SPI /* SPI interface */, 21 /* Interrupt GPIO */);
#else
WiFiClient netClient;
#endif
#endif
#if EXAMPLE_SNAPCAST
//#define CONFIG_PROCESSING_TIME_MS (172*2) // default:172
//#define CONFIG_STREAMIN_DECODER_BUFFER (24*1024) // default:12
//#define CONFIG_USE_PSRAM false
#include "SnapClient.h"
#if SNAPCAST_RTOS_PROCESSOR
#include "api/SnapProcessorRTOS.h" // install https://github.com/pschatzmann/arduino-freertos-addons
#endif
#define OPUS_DEC_MAX_BUFFER_SIZE (8 * 1024) // default:4
#include "AudioCodecs/CodecOpus.h"
//#include <AudioCodecs/>
//#include <nvs_flash.h>
#define ARDUINO_LOOP_STACK_SIZE (10 * 1024) // was 10
#if SNAPCAST_RTOS_PROCESSOR
SnapProcessorRTOS rtos(1024*8); // define queue with 8 kbytes
#endif
SnapTimeSyncDynamic synch(172, 10); // optional configuratioin
OpusAudioDecoder opus;
SnapClient client(netClient, out, opus);
#elif EXAMPLE_MP3_URL
#include "AudioCodecs/CodecMP3Helix.h"
#if USE_W5500
URLStream url(netClient);
#else
WiFiMulti wifiMulti;
//URLStream url(CONFIG_WIFI_SSID, CONFIG_WIFI_PASSWORD);
URLStream url(netClient);
#endif
EncodedAudioStream decoded(&out, new MP3DecoderHelix()); // Decoding stream
StreamCopy copier(decoded, url); // copy url to decoder
#elif EXAMPLE_MP3_MEM
#include "AudioCodecs/CodecMP3Helix.h"
//#include <examples/examples-stream/streams-memory_mp3-pwm/BabyElephantWalk60_mp3.h>
#include "BabyElephantWalk60_mp3.h"
MemoryStream mp3(BabyElephantWalk60_mp3, BabyElephantWalk60_mp3_len);
//extern MemoryStream mp3;
EncodedAudioStream decoded(&out, new MP3DecoderHelix()); // output to decoder
StreamCopy copier(decoded, mp3); // copy in to out
#elif EXAMPLE_SINE
AudioInfo info(8000, 1, 16);
SineWaveGenerator<int16_t> sineWave(32000); // subclass of SoundGenerator with max amplitude of 32000
GeneratedSoundStream<int16_t> sound(sineWave); // Stream generated from sine wave
StreamCopy copier(out, sound); // copy in to out
#endif // EXAMPLE global variables
void setup() {
Serial.begin(115200);
AudioLogger::instance().begin(Serial, AudioLogger::Info);
//nvs_flash_erase();
Serial.println("Testing snapcast");
// configure output
auto cfg = out.defaultConfig();
#if defined(ARDUINO_ARCH_RP2040)
cfg.pin_bck = 27;
cfg.pin_ws = 28;
cfg.pin_data = 26;
#elif CONFIG_IDF_TARGET_ESP32S3
cfg.pin_bck = 11;
cfg.pin_ws = 10;
cfg.pin_data = 12;
#else
cfg.pin_bck = 26;
cfg.pin_ws = 25;
cfg.pin_data = 27;
#endif
#if USE_I2S_PDM
cfg.signal_type = audio_tools::I2SSignalType::PDM;
#endif
#if EXAMPLE_SNAPCAST
cfg.sample_rate = 48000;
#elif EXAMPLE_SINE
cfg.sample_rate = 8000;
#endif
out.begin(cfg);
// configure input
#if EXAMPLE_NETWORKED
#if USE_W5500
// Set up SPI pinout to match your HW
SPI.setRX(16);
SPI.setCS(17);
SPI.setSCK(18);
SPI.setTX(19);
// 20 RST
// 21 INT
delay(1000);
Serial.println();
Serial.println("Starting Ethernet port");
// Start the Ethernet port
if (!eth.begin()) {
Serial.println("No wired Ethernet hardware detected. Check pinouts, wiring.");
while (1) {
delay(1000);
}
}
while (!eth.connected()) {
Serial.print(".");
delay(500);
}
Serial.println("");
Serial.println("Ethernet connected");
Serial.print("Eth IP address: ");
Serial.println(eth.localIP());
uint8_t mac[8];
eth.macAddress(mac);
char mac_address[20];
snprintf(mac_address, sizeof(mac_address), "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
Serial.print("Eth MAC address: ");
Serial.println(mac_address);
//client.setMacAddress(mac_address);
#if EXAMPLE_SNAPCAST
rtos.setMacAddress(mac_address);
#endif
Serial.print("Ethernet status: ");
Serial.println(netClient.status());
Serial.print("WiFi.status(): ");
Serial.println(WiFi.status());
Serial.print("WiFi IP address: ");
Serial.println(WiFi.localIP());
#elif 1
// login to wifi
WiFi.begin(CONFIG_WIFI_SSID, CONFIG_WIFI_PASSWORD);
Serial.print("Connecting to WiFi ..");
while (WiFi.status() != WL_CONNECTED) {
Serial.print('.');
delay(1000);
}
// print ip address
Serial.println();
Serial.println(WiFi.localIP());
#else
wifiMulti.addAP(CONFIG_WIFI_SSID, CONFIG_WIFI_PASSWORD);
if (wifiMulti.run() != WL_CONNECTED) {
Serial.println("Unable to connect to network, rebooting in 10 seconds...");
delay(10000);
rp2040.reboot();
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
#endif // ethernet or wifi
#if 0
const char* host = "djxmmx.net";
const uint16_t port = 17;
//const char* host = "http://stream.srg-ssr.ch/m/rsj/mp3_128";
//const uint16_t port = 80;
Serial.print("connecting to ");
Serial.print(host);
Serial.print(':');
Serial.println(port);
// Use WiFiClient class to create TCP connections
//WiFiClient client;
auto& client = netClient;
if (!client.connect(host, port)) {
Serial.println("connection failed");
delay(5000);
return;
}
// This will send a string to the server
Serial.println("sending data to server");
if (client.connected()) {
client.println("hello from RP2040");
}
// wait for data to be available
unsigned long timeout = millis();
while (client.available() == 0) {
if (millis() - timeout > 5000) {
Serial.println(">>> Client Timeout !");
client.stop();
delay(60000);
return;
}
}
// Read all the lines of the reply from server and print them to Serial
Serial.println("receiving from remote server");
// not testing 'client.connected()' since we do not need to send data here
while (client.available()) {
char ch = static_cast<char>(client.read());
Serial.print(ch);
}
// Close the connection
Serial.println();
Serial.println("closing connection");
client.stop();
#endif
//configTime(...);
//gettimeofday();
//settimeofday();
#endif // EXAMPLE_NETWORKED
#if EXAMPLE_SNAPCAST
#if SNAPCAST_RTOS_PROCESSOR
// Use FreeRTOS
client.setSnapProcessor(rtos);
#endif
#elif EXAMPLE_MP3_MEM
mp3.setLoop(true);
// update audio info with info from decoder
decoded.addNotifyAudioChange(out);
#elif EXAMPLE_MP3_URL
// update audio info with info from decoder
decoded.addNotifyAudioChange(out);
#elif EXAMPLE_SINE
sineWave.begin(info, N_B4);
#endif // EXAMPLE input
#if EXAMPLE_SNAPCAST
// start snap client
client.begin(synch);
#elif EXAMPLE_MP3_MEM
decoded.begin();
#elif EXAMPLE_MP3_URL
decoded.begin();
// mp3 radio
url.begin("http://stream.srg-ssr.ch/m/rsj/mp3_128", "audio/mp3");
#elif EXAMPLE_SINE
#endif
#if EXAMPLE_SNAPCAST && SNAPCAST_ON_DIFFERENT_CORE
constexpr int otherCore = CONFIG_ARDUINO_RUNNING_CORE == 0 ? 1 : 0;
#if 0
// in case the idle task interrupts audio at 100Hz
TaskHandle_t idle_x = xTaskGetIdleTaskHandleForCPU(otherCore);
if(idle_x == NULL || esp_task_wdt_delete(idle_x) != ESP_OK){
log_e("Failed to remove Core x IDLE task from WDT");
}
#endif
TaskHandle_t snapTaskHandle = nullptr;
xTaskCreateUniversal([](void*) {
//esp_task_wdt_delete(NULL);
while(true) {
//loop1();
client.doLoop();
delay(1); // allow for wifi etc
}
vTaskDelete(NULL);
}, "snapTask", 16384, NULL, 1, &snapTaskHandle, otherCore);
#endif
}
void loop() {
#if EXAMPLE_SNAPCAST
#if !SNAPCAST_ON_DIFFERENT_CORE
client.doLoop();
delay(1);
#endif
#elif EXAMPLE_MP3_MEM
if (mp3) {
copier.copy();
} else {
auto info = decoded.decoder().audioInfo();
LOGI("The audio rate from the mp3 file is %d", info.sample_rate);
LOGI("The channels from the mp3 file is %d", info.channels);
out.end();
stop();
}
#elif EXAMPLE_MP3_URL
copier.copy();
#elif EXAMPLE_SINE
copier.copy();
#endif
}
#endif // compile |
Beta Was this translation helpful? Give feedback.
-
I have spent some time to play with Rasperry Pico 2W:
So it is just too much do do Wifi, decoding and i2s output on a single core! As a next approach I tried to split up the processing to the 2 cores: Wifi and receiving data on core 0 and Decoding and i2s output on core 1. This is wokring much better now. Here is the related rp2040 example |
Beta Was this translation helpful? Give feedback.
-
I managed to resolve the compile issues of this project for the RP2040 Pico and I am looking for volunteers to test this application on this new architecture...
Beta Was this translation helpful? Give feedback.
All reactions