Skip to content

Commit

Permalink
initial complete release
Browse files Browse the repository at this point in the history
  • Loading branch information
trylaarsdam committed Jun 16, 2023
1 parent 3464292 commit d64f153
Show file tree
Hide file tree
Showing 7 changed files with 158 additions and 100 deletions.
36 changes: 34 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -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.
68 changes: 68 additions & 0 deletions examples/sine-wave/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#ifdef CORE_CM4

#include <Arduino.h>
#include <portenta-i2s.h>

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 <portenta-i2s.h>

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
23 changes: 23 additions & 0 deletions examples/sine-wave/platformio.ini
Original file line number Diff line number Diff line change
@@ -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
21 changes: 21 additions & 0 deletions library.json
Original file line number Diff line number Diff line change
@@ -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": "*"
}
72 changes: 0 additions & 72 deletions src/main.cpp

This file was deleted.

32 changes: 11 additions & 21 deletions src/portenta-i2s.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -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);
}
}
6 changes: 1 addition & 5 deletions src/portenta-i2s.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,15 @@
class PortentaI2S
{
private:
I2S_HandleTypeDef hi2s2;
I2S_HandleTypeDef hi2s1;
bool i2sSelection;
unsigned long audioFreq;
GPIO_InitTypeDef GPIO_InitStruct;
void I2S_Init(void);
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);
};

0 comments on commit d64f153

Please sign in to comment.