Skip to content

Commit

Permalink
RP2040 I2S Support
Browse files Browse the repository at this point in the history
  • Loading branch information
pschatzmann committed Feb 25, 2022
1 parent 7611f36 commit 6e6ee65
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,19 @@

#include "AudioTools.h"

typedef int16_t sound_t; // sound will be represented as int16_t (with 2 bytes)
uint16_t sample_rate=44100;
uint8_t channels = 2; // The stream will have 2 channels
SineWaveGenerator<sound_t> sineWave(32000); // subclass of SoundGenerator with max amplitude of 32000
GeneratedSoundStream<sound_t> sound(sineWave); // Stream generated from sine wave
SineWaveGenerator<int16_t> sineWave(32000); // subclass of SoundGenerator with max amplitude of 32000
GeneratedSoundStream<int16_t> sound(sineWave); // Stream generated from sine wave
I2SStream out;
StreamCopy copier(out, sound); // copies sound into i2s

// Arduino Setup
void setup(void) {
// Open Serial
Serial.begin(115200);
AudioLogger::instance().begin(Serial, AudioLogger::Warning);
while(!Serial);
AudioLogger::instance().begin(Serial, AudioLogger::Info);

// start I2S
Serial.println("starting I2S...");
Expand Down
6 changes: 6 additions & 0 deletions src/AudioConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,12 @@
#ifndef COPY_DELAY_ON_NODATA
#define COPY_DELAY_ON_NODATA 10
#endif

#ifndef COPY_RETRY_LIMIT
#define COPY_RETRY_LIMIT 20
#endif


/**
* -------------------------------------------------------------------------
* @brief PWM
Expand Down
90 changes: 70 additions & 20 deletions src/AudioI2S/I2SRP2040.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class I2SBasePIO {
}

/// starts the DAC with the default config in TX Mode
bool begin(RxTxMode mode = TX_MODE) {
bool begin(RxTxMode mode = TX_MODE) {
LOGD(LOG_METHOD);
return begin(defaultConfig(mode));
}
Expand All @@ -58,19 +58,26 @@ class I2SBasePIO {
LOGE("Unsupported bits_per_sample: %d", cfg.bits_per_sample);
return false;
}
if (cfg.channels != 2 ){

if (cfg.channels < 1 || cfg.channels > 2 ){
LOGE("Unsupported channels: '%d' - only 2 is supported", cfg.channels);
return false;
}
if (!I2S.begin(cfg.sample_rate)){

int rate = cfg.sample_rate;
if (cfg.channels==1){
rate = rate /2;
}

if (!I2S.begin(rate)){
LOGE("Could not start I2S");
return false;
}
return true;
}

/// stops the I2C and unistalls the driver
void end(){
void end() {
I2S.end();
}

Expand All @@ -80,37 +87,80 @@ class I2SBasePIO {
}

/// writes the data to the I2S interface
size_t writeBytes(const void *src, size_t size_bytes){
size_t writeBytes(const void *src, size_t size_bytes) {
LOGD(LOG_METHOD);
// size_t result = I2S.write(src, frames);
size_t result = 0;
uint32_t *p32 = (uint32_t *)src;
for (int j=0;j<size_bytes/4;j++){
while (!I2S.write((void*)p32[j], 4)){
delay(5);
}
result = j*4;
}
LOGD("%s: %d -> %d ", LOG_METHOD, size_bytes, result);
int16_t *p16 = (int16_t *)src;

if (cfg.channels==1){
int samples = size_bytes/2;
// multiply 1 channel into 2
int16_t buffer[samples*2]; // from 1 byte to 2 bytes
for (int j=0;j<samples;j++){
buffer[j*2]= p16[j];
buffer[j*2+1]= p16[j];
}
result = I2S.write((const uint8_t*)buffer, size_bytes*2)*2;
} else if (cfg.channels==2){
result = I2S.write((const uint8_t*)src, size_bytes)*4;
}
return result;
}

size_t readBytes(void *dest, size_t size_bytes){
LOGD(LOG_METHOD);
size_t readBytes(void *dest, size_t size_bytes) {
LOGE(LOG_METHOD);
size_t result = 0;
return result;
}

virtual int availableForWrite() {
return I2S.availableForWrite();
int availableForWrite() {
int result = 0;
if (cfg.channels == 1){
// it should be a multiple of 2
result = I2S.availableForWrite()/2*2;
// return half of it because we double when writing
result = result / 2;
} else {
// it should be a multiple of 4
result = I2S.availableForWrite()/4*4;
}
if (result<4){
result = 0;
}
return result;
}

int available() {
return 0;
}

int available() {
return I2S.available();
void flush() {
return I2S.flush();
}

protected:
I2SConfig cfg;

// blocking write
void writeSample(int16_t sample){
int written = I2S.write(sample);
while (!written) {
delay(5);
LOGW("written: %d ", written);
written = I2S.write(sample);
}
}

int writeSamples(int samples, int16_t* values){
int result=0;
for (int j=0;j<samples;j++){
int16_t sample = values[j];
writeSample(sample);
writeSample(sample);
result++;
}
return result;
}

};

Expand Down
2 changes: 1 addition & 1 deletion src/AudioTools/AudioCopy.h
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ class StreamCopyT {
void *onWriteObj = nullptr;
bool is_first = false;
const char* actual_mime = nullptr;
int retryLimit = 20;
int retryLimit = COPY_RETRY_LIMIT;
int delay_on_no_data = COPY_DELAY_ON_NODATA;

// blocking write - until everything is processed
Expand Down
4 changes: 2 additions & 2 deletions tests/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@

In the subdirectories you find the test sketches that can be build on the desktop.
For details [see the wiki](https://github.com/pschatzmann/arduino-audio-tools/wiki/Running-an-Audio-Sketch-on-the-Desktop)
In the subdirectories you find the test sketches that can be built on the desktop.
For details [see the Wiki](https://github.com/pschatzmann/arduino-audio-tools/wiki/Running-an-Audio-Sketch-on-the-Desktop)

0 comments on commit 6e6ee65

Please sign in to comment.