Przedstawiam płytkę z przetwornikiem cyfrowo analogowym PCM5102A. Płytka posiada wyjście audio na złącze Jack.
Można ją tanio kupić. Na allegro widziałem po około 20zł, a na aliepxress można kupić nawet za 7zł.
Uważam, że może się przydać do własnych projektów i pomyślałem, że fajnie będzie pokazać jak szybko uruchomić taką płytkę z arduino oraz RaspBerry Pi Pico 2W.
Aby uruchomić płytę nie ma konieczności podłączania do mikrokontrolera wszystkich pinów. Na stronie dolnej PCB są pola lutownicze, które zalutowując wybiera się stany na pinach.
Schemat płyty jest następujący.
Z punktu widzenia transmisji I2S, konieczne będzie podłączenie pinów BCK, DIN, LRCK, GND oraz zasilanie Vin. Na płycie jest stabilizator na 3.3V, więc na Vin podałem 5V(VBUS na płycie Pico).
LRCK jest sygnałem informującym, który kanał audio jest przesyłany, jest on też źródłem zegara dla przetwornika cyfrowo analogowego.
DIN zawiera przesyłane bity audio. Przesyłane jest 16 bitów na kanał. Bity są próbkowane na zboczu narastającym zegara BCLK.
BCLK podpiąłem do GP0
LRCLK(nazywane też WS) do GP1
DIN do GP2
W kodzie arduino użyłem klasy I2S z następującą definicją pinów:
#define pBCLK 0
#define pWS (pBCLK+1)
#define pDOUT 2
I2S i2s(OUTPUT, pBCLK, pDOUT);
Pinu SCK nie używam, pozwala on na podanie zewnętrznego zegara dla przetwornika. Gdy przez 16 cykli LRCLK stan niski się otrzymuje to uruchamiany jest wewnętrzny PLL, który generuje ten zegar na podstawie LRCLK.
Połączony 3 żyłowy I2S wraz z RaspBerry Pi Pico 2W wygląda następująco:
Kolejnym elementem jest polutowanie zworek.
Oraz schemat blokowy układu PCM:
Zworka H1L ściąga do masy pin FLT, który wybiera interpolacyjny filtr FIR(w stanie wysokim dostępny jest IIR). Tym filtrem filtrowane są próbki przez podaniem na przetwornik.
Zwora H2L łączy z masą pin DEMP, Wyłączając deemfazę.(https://pl.wikipedia.org/wiki/Deemfaza)
Zwora H3L ustawia stan wysoki 3.3V na pinie XSMT wyłączjąc programowe wyciszenie. Gdy w stanie niskim to układ realizuje wyciszenie tłumiąc sygnał o 1dB co każdą próbkę. Całkowite wyciszenie wymaga 104 próbek.
Zwora H4L ustawia FMT w stan niski wybierając format normalny I2S.
U mnie wygląda to po lutowaniu następująco:
Do przetestowania płytki użyłem kodu realizującego głośnik Bluetooth:
// A2DPSink example - Released to the public domain in 2024 by Earle F. Philhower, III
// Hook up a phono plug to GP0 and GP1 (and GND of course...the 1st 3 pins on the PCB)
// Connect wired earbuds up and connect over BT from your phone and play some music.
#include <BluetoothAudio.h>
#include <PWMAudio.h>
//https://github.com/earlephilhower/arduino-pico/blob/master/libraries/BluetoothAudio/examples/A2DPSink/A2DPSink.ino
#define pBCLK 0
#define pWS (pBCLK+1)
#define pDOUT 2
I2S i2s(OUTPUT, pBCLK, pDOUT);
A2DPSink a2dp;
volatile A2DPSink::PlaybackStatus status = A2DPSink::STOPPED;
void volumeCB(void *param, int pct) {
(void) param;
Serial.printf("Speaker volume changed to %d%%\n", pct);
}
void connectCB(void *param, bool connected) {
(void) param;
if (connected) {
Serial.printf("A2DP connection started to %s\n", bd_addr_to_str(a2dp.getSourceAddress()));
} else {
Serial.printf("A2DP connection stopped\n");
}
}
void playbackCB(void *param, A2DPSink::PlaybackStatus state) {
(void) param;
status = state;
}
void setup() {
Serial.begin(115200);
delay(3000);
Serial.printf("Starting, connect to the PicoW and start playing music\n");
Serial.printf("Use BOOTSEL to pause/resume playback\n");
a2dp.setName("PicoW Boom 00:00:00:00:00:00");
// a2dp.setConsumer(new BluetoothAudioConsumerPWM(pwm));
a2dp.setConsumer(new BluetoothAudioConsumerI2S(i2s));
a2dp.onVolume(volumeCB);
a2dp.onConnect(connectCB);
a2dp.onPlaybackStatus(playbackCB);
a2dp.begin();
}
char *nowPlaying = nullptr;
void loop() {
if (BOOTSEL) {
if (status == A2DPSink::PAUSED) {
a2dp.play();
Serial.printf("Resuming\n");
} else if (status == A2DPSink::PLAYING) {
a2dp.pause();
Serial.printf("Pausing\n");
}
while (BOOTSEL);
}
if (!nowPlaying || strcmp(nowPlaying, a2dp.trackTitle())) {
free(nowPlaying);
nowPlaying = strdup(a2dp.trackTitle());
Serial.printf("NOW PLAYING: %s\n", nowPlaying);
}
}
Załączam też skompilowany kod jako plik uf2 jakby ktoś chciał na szybko przetestować.
Fajne? Ranking DIY