diff --git a/README.md b/README.md index 33cc672..2b5a399 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,38 @@ # Arduino Portenta H7 I2S Library -This library allows you to use the I2S protocol on the Arduino Portenta H7 in PlatformIO. +This library allows you to use the I2S protocol on the Arduino Portenta H7 in PlatformIO. It is compatible with both the M4 and M7 cores on the Portenta. -Huge thanks to Max Gerhardt from PlatformIO for helping me get this working. +Huge thanks to Max Gerhardt from PlatformIO for helping me get I2S ported from Cube to PlatformIO. +## Usage +1. Create the I2S object +```cpp +PortentaI2S i2s = PortentaI2S(USE_I2S2, I2S_AUDIOFREQ_44K); +``` + +Currently only I2S2 is supported on the Portenta (this is connected to the I2S header on the Portenta breakout board). However, you can chose any audio frequency you wish from this list: +```cpp +I2S_AUDIOFREQ_192K 192000hz +I2S_AUDIOFREQ_96K 96000hz +I2S_AUDIOFREQ_48K 48000hz +I2S_AUDIOFREQ_44K 44100hz +I2S_AUDIOFREQ_32K 32000hz +I2S_AUDIOFREQ_22K 22050hz +I2S_AUDIOFREQ_16K 16000hz +I2S_AUDIOFREQ_11K 11025hz +I2S_AUDIOFREQ_8K 8000hz +I2S_AUDIOFREQ_DEFAULT 2hz +``` + +2. Initialize the I2S interface +```cpp +i2s.begin(); +``` + +3. Play your audio buffer +```cpp +i2s.play(buffer, bufferLen); +``` + +## Examples +A simple example is provided for both the M4 and M7 cores (usage is the same no matter the core), which plays a sine wave at 440.0Hz (A4) out of the I2S2 interface. \ No newline at end of file diff --git a/examples/sine-wave/main.cpp b/examples/sine-wave/main.cpp new file mode 100644 index 0000000..19e67f7 --- /dev/null +++ b/examples/sine-wave/main.cpp @@ -0,0 +1,68 @@ +#ifdef CORE_CM4 + +#include +#include + +PortentaI2S i2s = PortentaI2S(USE_I2S2, I2S_AUDIOFREQ_44K); + +void setup() +{ + i2s.begin(); + + // Generate sine wave + uint16_t samplebuf[8192]; // for both left + right + const int nsamples = sizeof(samplebuf) / sizeof(samplebuf[0]); + int i = 0; + while(i < nsamples) { + double t = ((double)i / 2.0) / 44100.0; + samplebuf[i] = 32767*((sin((440.0 - FREQ_OFFSET) * TAU * t) / 2)); // left channel + samplebuf[i+1] = samplebuf[i]; // right channel (same) + i += 2; + } + + // Play continuously + while(1){ + i2s.play(samplebuf, nsamples); + } +} + +void loop() +{ + +} + +#endif + +#ifdef CORE_CM7 +#include "Arduino.h" +#include + +PortentaI2S i2s = PortentaI2S(USE_I2S2, I2S_AUDIOFREQ_44K); + +void setup() +{ + Serial.begin(115200); + i2s.begin(); + + // Generate sine wave + uint16_t samplebuf[8192]; // for both left + right + const int nsamples = sizeof(samplebuf) / sizeof(samplebuf[0]); + int i = 0; + while(i < nsamples) { + double t = ((double)i / 2.0) / 44100.0; + samplebuf[i] = 32767*((sin((440.0 - FREQ_OFFSET) * TAU * t) / 2)); // left channel + samplebuf[i+1] = samplebuf[i]; // right channel (same) + i += 2; + } + + // Play continuously + while(1){ + i2s.play(samplebuf, nsamples); + } +} + +void loop() +{ + +} +#endif \ No newline at end of file diff --git a/examples/sine-wave/platformio.ini b/examples/sine-wave/platformio.ini new file mode 100644 index 0000000..2202011 --- /dev/null +++ b/examples/sine-wave/platformio.ini @@ -0,0 +1,23 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[env:portenta_h7_m7] +platform = ststm32 +board = portenta_h7_m7 +framework = arduino +upload_protocol = stlink +debug_tool = stlink + +[env:portenta_h7_m4] +platform = ststm32 +board = portenta_h7_m4 +framework = arduino +upload_protocol = stlink +debug_tool = stlink \ No newline at end of file diff --git a/library.json b/library.json new file mode 100644 index 0000000..26b89ca --- /dev/null +++ b/library.json @@ -0,0 +1,21 @@ +{ + "name": "Portenta-I2S", + "version": "1.0.0", + "description": "A simple I2S implementation using HAL for the Portenta H7 series.", + "repository": + { + "type": "git", + "url": "https://github.com/trylaarsdam/portenta-i2s.git" + }, + "authors": + [ + { + "name": "Todd Rylaarsdam", + "email": "todd@toddr.org", + "url": "https://toddr.org", + "maintainer": true + } + ], + "frameworks": "Arduino", + "platforms": "*" +} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp deleted file mode 100644 index f9a1658..0000000 --- a/src/main.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#ifdef CORE_CM4 - -#include - - -// #ifndef PI -// #define PI 3.14159265358979323846 -// #endif -// #define TAU (2.0 * PI) -// #define FREQ_OFFSET 5 - -// void setup() -// { -// MX_GPIO_Init(); -// MX_I2S2_Init(); -// // fill signal buffer with sine wave -// int i = 0; -// while(i < nsamples) { -// double t = ((double)i/2.0)/((double)nsamples); -// samplebuf[i] = 32767*sin(100.0 * TAU * t); // left channel -// samplebuf[i+1] = samplebuf[i]; // right channel (same) -// i += 2; -// } -// } - -void setup() -{ - // const double sampleRate = 44100.0; // substitute with your actual sample rate - // MX_GPIO_Init_I2S2(); - // MX_I2S2_Init(I2S_AUDIOFREQ_44K); - // // fill signal buffer with sine wave - -} - - -void loop() -{ - // transmit full buffer over and over again - // HAL_I2S_Transmit(&hi2s2, samplebuf, nsamples, HAL_MAX_DELAY); - // delay(500); -} - -#endif - -#ifdef CORE_CM7 -#include "Arduino.h" -#include - -PortentaI2S i2s = PortentaI2S(USE_I2S2, I2S_AUDIOFREQ_44K); - -void setup() -{ - i2s.begin(); - uint16_t samplebuf[8192]; // for both left + right - const int nsamples = sizeof(samplebuf) / sizeof(samplebuf[0]); - int i = 0; - while(i < nsamples) { - double t = ((double)i / 2.0) / 44100.0; - samplebuf[i] = 32767*((sin((440.0 - FREQ_OFFSET) * TAU * t) / 2)); // left channel - samplebuf[i+1] = samplebuf[i]; // right channel (same) - i += 2; - } - while(1){ - HAL_I2S_Transmit(&hi2s2, samplebuf, nsamples, HAL_MAX_DELAY); - } -} - -void loop() -{ - -} -#endif \ No newline at end of file diff --git a/src/portenta-i2s.cpp b/src/portenta-i2s.cpp index dda210f..6d0584c 100644 --- a/src/portenta-i2s.cpp +++ b/src/portenta-i2s.cpp @@ -38,10 +38,16 @@ void PortentaI2S::begin(void) I2S_Init(); } -void PortentaI2S::play(uint16_t *buffer, uint32_t bufferSize) +void PortentaI2S::play(uint16_t* buffer, int bufferSize) { - HAL_I2S_Transmit(&hi2s2, buffer, bufferSize, HAL_MAX_DELAY); /* + if(HAL_I2S_Transmit(&hi2s2, buffer, bufferSize, HAL_MAX_DELAY) != HAL_OK) + { + Serial.println("HAL I2S Transmit Error"); + } + delay(bufferSize / audioFreq * 1000); + */ + uint16_t numBuffers = bufferSize / I2S_BUFFER_SIZE; if(bufferSize % I2S_BUFFER_SIZE != 0) { @@ -65,28 +71,12 @@ void PortentaI2S::play(uint16_t *buffer, uint32_t bufferSize) // transmit audioBuffer if(i2sSelection == USE_I2S1) { - HAL_I2S_Transmit(&hi2s1, audioBuffer, I2S_BUFFER_SIZE, HAL_MAX_DELAY); + // HAL_I2S_Transmit(&hi2s1, audioBuffer, I2S_BUFFER_SIZE, HAL_MAX_DELAY); } else { HAL_I2S_Transmit(&hi2s2, audioBuffer, I2S_BUFFER_SIZE, HAL_MAX_DELAY); } - }*/ -} - -void PortentaI2S::playSineWave(double freq, uint32_t duration) -{ - // uint32_t numSamples = duration * audioFreq / 1000; - long timer = millis(); - uint32_t numSamples = 8192; - uint16_t buffer[numSamples]; - int i = 0; - while (i < nsamples) - { - double t = ((double)i / 2.0) / ((double)nsamples); - buffer[i] = 32767 * sin((freq - FREQ_OFFSET) * TAU * t); // left channel - buffer[i + 1] = buffer[i]; // right channel (same) - i += 2; + delay(I2S_BUFFER_SIZE / audioFreq * 1000); } - play(buffer, numSamples); -} +} \ No newline at end of file diff --git a/src/portenta-i2s.h b/src/portenta-i2s.h index f256681..fdc23aa 100644 --- a/src/portenta-i2s.h +++ b/src/portenta-i2s.h @@ -18,8 +18,6 @@ class PortentaI2S { private: - I2S_HandleTypeDef hi2s2; - I2S_HandleTypeDef hi2s1; bool i2sSelection; unsigned long audioFreq; GPIO_InitTypeDef GPIO_InitStruct; @@ -27,10 +25,8 @@ class PortentaI2S void GPIO_Init(void); uint16_t audioBuffer[I2S_BUFFER_SIZE]; // for both left + right const int nsamples = I2S_BUFFER_SIZE / 2; - public: PortentaI2S(bool i2s = USE_I2S2, uint32_t sampleRate = 44100.0); void begin(void); - void play(uint16_t* buffer, uint32_t bufferSize); - void playSineWave(double freq, uint32_t duration); + void play(uint16_t* buffer, int bufferSize); }; \ No newline at end of file