Skip to content

DRAFT: Fixes for I2S #7117

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 58 commits into from
Closed
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
306cf89
Initial support for second I2S - not tested
PilnyTomas Aug 12, 2022
f9af615
Merge branch 'master' into i2s_fix
PilnyTomas Aug 12, 2022
d87aa62
Initial support for 24 bits per second - not tested yet!
PilnyTomas Aug 12, 2022
54e9554
SimpleTone supports all available bitrates
PilnyTomas Aug 15, 2022
481c439
Merge branch 'espressif:master' into i2s_fix
PilnyTomas Sep 21, 2022
db32ea6
Minor changes to fix compilation errors
PilnyTomas Sep 21, 2022
f2fdca7
Remapped pins
PilnyTomas Sep 21, 2022
578e871
Changed default pins
PilnyTomas Sep 27, 2022
b376699
Added notes into README as a guide for propper documentation
PilnyTomas Sep 27, 2022
dc1769e
WIP Backup of documentation update
PilnyTomas Sep 30, 2022
adff9e1
Finished documenting header file + README.md
PilnyTomas Sep 30, 2022
26ac979
Updated pins in examples + removed skip files
PilnyTomas Oct 3, 2022
7a9fd45
Merge branch 'espressif:master' into i2s_fix
PilnyTomas Oct 14, 2022
c7d011e
Added C3 PDM support
PilnyTomas Oct 17, 2022
b02596b
Simplified peek() - NOT tested
PilnyTomas Oct 17, 2022
0f8e9bc
Updated README.md - section describing modes
PilnyTomas Oct 17, 2022
2b04bf8
Revert "Simplified peek() - NOT tested"
PilnyTomas Oct 18, 2022
989817c
Extended mode warning and added mode text array
PilnyTomas Oct 18, 2022
fe268c8
Added new example demonstrating usage of both I2S module (not working…
PilnyTomas Oct 24, 2022
a0ab150
Changed mutex to recursive mutex
PilnyTomas Oct 25, 2022
0b38c9b
Merge branch 'espressif:master' into i2s_fix
PilnyTomas Oct 26, 2022
d7e1228
Added missing initializers to satisfy compilier's warnings
PilnyTomas Oct 27, 2022
e96f5a9
Fix for previous commit - I2S_TDM_ACTIVE_CH
PilnyTomas Oct 27, 2022
8f6613e
First I2S tests
PilnyTomas Oct 27, 2022
5f3542c
Changed default FS pin which was accidentally set on UART TX for C3
PilnyTomas Oct 27, 2022
f67ce84
Added getI2SNum()
PilnyTomas Oct 31, 2022
0719bdc
Added function isInitialized()
PilnyTomas Oct 31, 2022
9721149
Extended begin test for slave mode + added pin setter & getter test
PilnyTomas Oct 31, 2022
2899011
Added & modified buffer functions; Renamed I2S1 to I2S_1
PilnyTomas Nov 3, 2022
d746aa2
Updated DualModule example
PilnyTomas Nov 7, 2022
de30999
Added test
PilnyTomas Nov 11, 2022
53d8f23
Updated default pins
PilnyTomas Nov 11, 2022
a3898e6
Fixed buffer calls in example
PilnyTomas Nov 11, 2022
405723a
Merge branch 'espressif:master' into i2s_fix
PilnyTomas Nov 11, 2022
6ac821e
Added skip files for DualModule example
PilnyTomas Nov 11, 2022
27149b8
Merge branch 'espressif:master' into i2s_fix
PilnyTomas Nov 23, 2022
85b0ea4
Renamed data parameter to sample; removed _buffer_byte_size - now usi…
PilnyTomas Nov 28, 2022
9fa388c
Added MCLK
PilnyTomas Nov 30, 2022
5f779df
Fixed constructor
PilnyTomas Nov 30, 2022
b8dcf69
fixed variable order
PilnyTomas Nov 30, 2022
51a7914
Merge branch 'espressif:master' into i2s_fix
PilnyTomas Dec 1, 2022
70c9e26
Fixed freezing output
PilnyTomas Dec 7, 2022
6aed27f
Separated info message with doc link for each SoC
PilnyTomas Dec 7, 2022
d831f1a
Changed default MCLK pins
PilnyTomas Dec 7, 2022
9761860
Modified MCLK code and doc
PilnyTomas Dec 8, 2022
77a876e
Added note to legacy example
PilnyTomas Dec 8, 2022
653c995
Fixed input
PilnyTomas Dec 8, 2022
83f5372
changed default input pin to match with ADC support
PilnyTomas Dec 9, 2022
94a9169
Merge branch 'espressif:master' into i2s_fix
PilnyTomas Dec 9, 2022
4af7fa3
Fixed DAC
PilnyTomas Dec 15, 2022
4d174af
Added setDMABufferSampleSize function and made few changes in README
PilnyTomas Dec 16, 2022
17caf84
Lowered I2S task priority
PilnyTomas Dec 18, 2022
b12cc18
Merge branch 'espressif:master' into i2s_fix
PilnyTomas Dec 18, 2022
46aee1f
Merge branch 'espressif:master' into i2s_fix
PilnyTomas Dec 27, 2022
d5cde9e
Merge branch 'espressif:master' into i2s_fix
PilnyTomas Jun 23, 2023
3d85853
backup
PilnyTomas Jul 17, 2023
1d85571
work in progress
PilnyTomas Jul 17, 2023
b2d000a
Merge remote-tracking branch 'origin/i2s_fix' into i2s_fix
PilnyTomas Jul 17, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cores/esp32/esp32-hal-gpio.c
Original file line number Diff line number Diff line change
@@ -135,7 +135,9 @@ extern void ARDUINO_ISR_ATTR __pinMode(uint8_t pin, uint8_t mode)
extern void ARDUINO_ISR_ATTR __digitalWrite(uint8_t pin, uint8_t val)
{
#ifdef RGB_BUILTIN
log_d("RGB_BUILTIN is defined");
if(pin == RGB_BUILTIN){
log_d("and its the target");
//use RMT to set all channels on/off
const uint8_t comm_val = val != 0 ? RGB_BRIGHTNESS : 0;
neopixelWrite(RGB_BUILTIN, comm_val, comm_val, comm_val);
1 change: 1 addition & 0 deletions cores/esp32/esp32-hal-rgb-led.c
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@


void neopixelWrite(uint8_t pin, uint8_t red_val, uint8_t green_val, uint8_t blue_val){
log_d("light it up to %d", red_val);
rmt_data_t led_data[24];
static rmt_obj_t* rmt_send = NULL;
static bool initialized = false;
2 changes: 1 addition & 1 deletion libraries/BLE/src/BLEAddress.h
Original file line number Diff line number Diff line change
@@ -30,7 +30,7 @@ class BLEAddress {
bool operator>(const BLEAddress& otherAddress) const;
bool operator>=(const BLEAddress& otherAddress) const;
esp_bd_addr_t* getNative();
std::string toString();
String toString();

private:
esp_bd_addr_t m_address;
180 changes: 90 additions & 90 deletions libraries/BLE/src/BLEAdvertisedDevice.h
Original file line number Diff line number Diff line change
@@ -28,82 +28,82 @@ class BLEScan;
*/
class BLEAdvertisedDevice {
public:
BLEAdvertisedDevice();

BLEAddress getAddress();
uint16_t getAppearance();
std::string getManufacturerData();
std::string getName();
int getRSSI();
BLEScan* getScan();
std::string getServiceData();
std::string getServiceData(int i);
BLEUUID getServiceDataUUID();
BLEUUID getServiceDataUUID(int i);
BLEUUID getServiceUUID();
BLEUUID getServiceUUID(int i);
int getServiceDataCount();
int getServiceDataUUIDCount();
int getServiceUUIDCount();
int8_t getTXPower();
uint8_t* getPayload();
size_t getPayloadLength();
esp_ble_addr_type_t getAddressType();
void setAddressType(esp_ble_addr_type_t type);


bool isAdvertisingService(BLEUUID uuid);
bool haveAppearance();
bool haveManufacturerData();
bool haveName();
bool haveRSSI();
bool haveServiceData();
bool haveServiceUUID();
bool haveTXPower();

std::string toString();
BLEAdvertisedDevice();

BLEAddress getAddress();
uint16_t getAppearance();
std::string getManufacturerData();
std::string getName();
int getRSSI();
BLEScan* getScan();
std::string getServiceData();
std::string getServiceData(int i);
BLEUUID getServiceDataUUID();
BLEUUID getServiceDataUUID(int i);
BLEUUID getServiceUUID();
BLEUUID getServiceUUID(int i);
int getServiceDataCount();
int getServiceDataUUIDCount();
int getServiceUUIDCount();
int8_t getTXPower();
uint8_t* getPayload();
size_t getPayloadLength();
esp_ble_addr_type_t getAddressType();
void setAddressType(esp_ble_addr_type_t type);


bool isAdvertisingService(BLEUUID uuid);
bool haveAppearance();
bool haveManufacturerData();
bool haveName();
bool haveRSSI();
bool haveServiceData();
bool haveServiceUUID();
bool haveTXPower();

std::string toString();

private:
friend class BLEScan;

void parseAdvertisement(uint8_t* payload, size_t total_len=62);
void setPayload(uint8_t* payload, size_t total_len=62);
void setAddress(BLEAddress address);
void setAdFlag(uint8_t adFlag);
void setAdvertizementResult(uint8_t* payload);
void setAppearance(uint16_t appearance);
void setManufacturerData(std::string manufacturerData);
void setName(std::string name);
void setRSSI(int rssi);
void setScan(BLEScan* pScan);
void setServiceData(std::string data);
void setServiceDataUUID(BLEUUID uuid);
void setServiceUUID(const char* serviceUUID);
void setServiceUUID(BLEUUID serviceUUID);
void setTXPower(int8_t txPower);

bool m_haveAppearance;
bool m_haveManufacturerData;
bool m_haveName;
bool m_haveRSSI;
bool m_haveTXPower;


BLEAddress m_address = BLEAddress((uint8_t*)"\0\0\0\0\0\0");
uint8_t m_adFlag;
uint16_t m_appearance;
int m_deviceType;
std::string m_manufacturerData;
std::string m_name;
BLEScan* m_pScan;
int m_rssi;
std::vector<BLEUUID> m_serviceUUIDs;
int8_t m_txPower;
std::vector<std::string> m_serviceData;
std::vector<BLEUUID> m_serviceDataUUIDs;
uint8_t* m_payload;
size_t m_payloadLength = 0;
esp_ble_addr_type_t m_addressType;
friend class BLEScan;

void parseAdvertisement(uint8_t* payload, size_t total_len=62);
void setPayload(uint8_t* payload, size_t total_len=62);
void setAddress(BLEAddress address);
void setAdFlag(uint8_t adFlag);
void setAdvertizementResult(uint8_t* payload);
void setAppearance(uint16_t appearance);
void setManufacturerData(std::string manufacturerData);
void setName(std::string name);
void setRSSI(int rssi);
void setScan(BLEScan* pScan);
void setServiceData(std::string data);
void setServiceDataUUID(BLEUUID uuid);
void setServiceUUID(const char* serviceUUID);
void setServiceUUID(BLEUUID serviceUUID);
void setTXPower(int8_t txPower);

bool m_haveAppearance;
bool m_haveManufacturerData;
bool m_haveName;
bool m_haveRSSI;
bool m_haveTXPower;


BLEAddress m_address = BLEAddress((uint8_t*)"\0\0\0\0\0\0");
uint8_t m_adFlag;
uint16_t m_appearance;
int m_deviceType;
std::string m_manufacturerData;
std::string m_name;
BLEScan* m_pScan;
int m_rssi;
std::vector<BLEUUID> m_serviceUUIDs;
int8_t m_txPower;
std::vector<std::string> m_serviceData;
std::vector<BLEUUID> m_serviceDataUUIDs;
uint8_t* m_payload;
size_t m_payloadLength = 0;
esp_ble_addr_type_t m_addressType;
};

/**
@@ -115,27 +115,27 @@ class BLEAdvertisedDevice {
*/
class BLEAdvertisedDeviceCallbacks {
public:
virtual ~BLEAdvertisedDeviceCallbacks() {}
/**
* @brief Called when a new scan result is detected.
*
* As we are scanning, we will find new devices. When found, this call back is invoked with a reference to the
* device that was found. During any individual scan, a device will only be detected one time.
*/
virtual void onResult(BLEAdvertisedDevice advertisedDevice) = 0;
virtual ~BLEAdvertisedDeviceCallbacks() {}
/**
* @brief Called when a new scan result is detected.
*
* As we are scanning, we will find new devices. When found, this call back is invoked with a reference to the
* device that was found. During any individual scan, a device will only be detected one time.
*/
virtual void onResult(BLEAdvertisedDevice advertisedDevice) = 0;
};

#ifdef CONFIG_BT_BLE_50_FEATURES_SUPPORTED
class BLEExtAdvertisingCallbacks {
public:
virtual ~BLEExtAdvertisingCallbacks() {}
/**
* @brief Called when a new scan result is detected.
*
* As we are scanning, we will find new devices. When found, this call back is invoked with a reference to the
* device that was found. During any individual scan, a device will only be detected one time.
*/
virtual void onResult(esp_ble_gap_ext_adv_reprot_t report) = 0;
virtual ~BLEExtAdvertisingCallbacks() {}
/**
* @brief Called when a new scan result is detected.
*
* As we are scanning, we will find new devices. When found, this call back is invoked with a reference to the
* device that was found. During any individual scan, a device will only be detected one time.
*/
virtual void onResult(esp_ble_gap_ext_adv_reprot_t report) = 0;
};
#endif // CONFIG_BT_BLE_50_FEATURES_SUPPORTED

1 change: 1 addition & 0 deletions libraries/BLE/src/BLEAdvertising.cpp
Original file line number Diff line number Diff line change
@@ -297,6 +297,7 @@ void BLEAdvertisementData::addData(std::string data) {
if ((m_payload.length() + data.length()) > ESP_BLE_ADV_DATA_LEN_MAX) {
return;
}
log_d("Appending 0x%X", data.c_str());
m_payload.append(data);
} // addData

1 change: 1 addition & 0 deletions libraries/BLE/src/BLEBeacon.cpp
Original file line number Diff line number Diff line change
@@ -51,6 +51,7 @@ int8_t BLEBeacon::getSignalPower() {
* Set the raw data for the beacon record.
*/
void BLEBeacon::setData(std::string data) {
log_d("getting data of length %d", data.length());
if (data.length() != sizeof(m_beaconData)) {
log_e("Unable to set the data ... length passed in was %d and expected %d", data.length(), sizeof(m_beaconData));
return;
38 changes: 29 additions & 9 deletions libraries/BLE/src/BLEEddystoneURL.cpp
Original file line number Diff line number Diff line change
@@ -20,8 +20,26 @@ BLEEddystoneURL::BLEEddystoneURL() {
memset(m_eddystoneData.url, 0, sizeof(m_eddystoneData.url));
} // BLEEddystoneURL

std::string BLEEddystoneURL::getData() {
return std::string((char*) &m_eddystoneData, sizeof(m_eddystoneData));

BLEEddystoneURL(BLEAdvertisedDevice *advertisedDevice){
uint8_t *payLoad = advertisedDevice->getPayload();
beaconUUID = 0xFEAA;
m_eddystoneData.frameType = EDDYSTONE_URL_FRAME_TYPE;
if(payload[11] != 0x10){ // Not Eddystone URL!
log_e("Failed to interpret Advertised Device as Eddystone URL!");
lengthURL = 0;
m_eddystoneData.advertisedTxPower = 0;
memset(m_eddystoneData.url, 0, sizeof(m_eddystoneData.url));
}
lengthURL = payload[7] - 6; // Subtracting 6 Bytes containing header and other data which are not actual URL data
//setData(String((char*)payLoad+11, lengthURL));
m_eddystoneData.advertisedTxPower = payload[12];
log_d("using data from [14]=0x%02X=%c up to [%d]=0x%02X=%c", payload[14], payload[14], lengthURL, payload[14+lengthURL], payload[14+lengthURL]);
memcpy(m_eddystoneData.url, payload[14], lengthURL);
}

String BLEEddystoneURL::getData() {
return String((char*) &m_eddystoneData, sizeof(m_eddystoneData));
} // getData

BLEUUID BLEEddystoneURL::getUUID() {
@@ -32,13 +50,14 @@ int8_t BLEEddystoneURL::getPower() {
return m_eddystoneData.advertisedTxPower;
} // getPower

std::string BLEEddystoneURL::getURL() {
return std::string((char*) &m_eddystoneData.url, sizeof(m_eddystoneData.url));
String BLEEddystoneURL::getURL() {
return String((char*) &m_eddystoneData.url, sizeof(m_eddystoneData.url));
} // getURL

std::string BLEEddystoneURL::getDecodedURL() {
std::string decodedURL = "";

String BLEEddystoneURL::getDecodedURL() {
String decodedURL = "";
log_d("prefix = m_eddystoneData.url[0] 0x%02X",m_eddystoneData.url[0]);
log_e("prefix type m_eddystoneData.url[0]=%d", m_eddystoneData.url[0]); // this is actually debug
switch (m_eddystoneData.url[0]) {
case 0x00:
decodedURL += "http://www.";
@@ -60,6 +79,7 @@ std::string BLEEddystoneURL::getDecodedURL() {
if (m_eddystoneData.url[i] > 33 && m_eddystoneData.url[i] < 127) {
decodedURL += m_eddystoneData.url[i];
} else {
log_d("suffix = m_eddystoneData.url[%d] 0x%02X", i, m_eddystoneData.url[i]);
switch (m_eddystoneData.url[i]) {
case 0x00:
decodedURL += ".com/";
@@ -116,7 +136,7 @@ std::string BLEEddystoneURL::getDecodedURL() {
/**
* Set the raw data for the beacon record.
*/
void BLEEddystoneURL::setData(std::string data) {
void BLEEddystoneURL::setData(String data) {
if (data.length() > sizeof(m_eddystoneData)) {
log_e("Unable to set the data ... length passed in was %d and max expected %d", data.length(), sizeof(m_eddystoneData));
return;
@@ -134,7 +154,7 @@ void BLEEddystoneURL::setPower(int8_t advertisedTxPower) {
m_eddystoneData.advertisedTxPower = advertisedTxPower;
} // setPower

void BLEEddystoneURL::setURL(std::string url) {
void BLEEddystoneURL::setURL(String url) {
if (url.length() > sizeof(m_eddystoneData.url)) {
log_e("Unable to set the url ... length passed in was %d and max expected %d", url.length(), sizeof(m_eddystoneData.url));
return;
2 changes: 1 addition & 1 deletion libraries/BLE/src/BLEUUID.cpp
Original file line number Diff line number Diff line change
@@ -64,6 +64,7 @@ static void memrcpy(uint8_t* target, uint8_t* source, uint32_t size) {
* @param [in] value The string to build a UUID from.
*/
BLEUUID::BLEUUID(std::string value) {
Serial.printf("BLEUUID string constructor- input=\"%s\"\n", value.c_str());
m_valueSet = true;
if (value.length() == 4) {
m_uuid.len = ESP_UUID_LEN_16;
@@ -118,7 +119,6 @@ BLEUUID::BLEUUID(std::string value) {
}
} //BLEUUID(std::string)


/**
* @brief Create a UUID from 16 bytes of memory.
*
11 changes: 6 additions & 5 deletions libraries/BLE/src/BLEValue.h
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@

#ifndef COMPONENTS_CPP_UTILS_BLEVALUE_H_
#define COMPONENTS_CPP_UTILS_BLEVALUE_H_
#include <Arduino.h>
#include "sdkconfig.h"
#if defined(CONFIG_BLUEDROID_ENABLED)
#include <string>
@@ -17,22 +18,22 @@
class BLEValue {
public:
BLEValue();
void addPart(std::string part);
void addPart(String part);
void addPart(uint8_t* pData, size_t length);
void cancel();
void commit();
uint8_t* getData();
size_t getLength();
uint16_t getReadOffset();
std::string getValue();
String getValue();
void setReadOffset(uint16_t readOffset);
void setValue(std::string value);
void setValue(String value);
void setValue(uint8_t* pData, size_t length);

private:
std::string m_accumulation;
String m_accumulation;
uint16_t m_readOffset;
std::string m_value;
String m_value;

};
#endif // CONFIG_BLUEDROID_ENABLED
3 changes: 3 additions & 0 deletions libraries/ESP32/examples/I2S/HiFreq_ADC/HiFreq_ADC.ino
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
/*
NOTE: This is a legacy example using IDF I2S driver. There is an I2S library using Arduino API.
You can find it on relative address `../../../../I2S/` or absolute address `arduino-esp32/libraries/I2S/`
This example demonstrates I2S ADC capability to sample high frequency analog signals.
The PWM signal generated with ledc is only for ease of use when first trying out.
To sample the generated signal connect default pins 27(PWM) and 32(Sampling) together.
535 changes: 535 additions & 0 deletions libraries/I2S/README.md

Large diffs are not rendered by default.

9 changes: 4 additions & 5 deletions libraries/I2S/examples/ADCPlotter/ADCPlotter.ino
Original file line number Diff line number Diff line change
@@ -49,10 +49,10 @@ Second option to measure voltage on trimmer / potentiometer has following connec
Tools -> Board -> ESP32 Arduino -> your board
2. Upload sketch
Press upload button (arrow in top left corner)
When you see in console line like this: "Connecting........_____.....__"
On your board press and hold Boot button and press EN button shortly. Now you can release both buttons.
When you see in console line like this: "Connecting........_____.....__" press "Boot" button on your board.
You should see lines like this: "Writing at 0x00010000... (12 %)" with rising percentage on each line.
If this fails, try the board buttons right after pressing upload button, or reconnect the USB cable.
If this fails, try the pressing the "Boot" button on board right after pressing upload button in IDE.
You can also try reconnect the USB cable. Reconnecting may change the serial port on your computer.
3. Open plotter
Tools -> Serial Plotter
Enjoy
@@ -72,8 +72,7 @@ void setup() {
; // wait for serial port to connect. Needed for native USB port only
}

// start I2S at 8 kHz with 32-bits per sample
if (!I2S.begin(ADC_DAC_MODE, 8000, 16)) {
if (!I2S.begin(ADC_DAC_MODE, 44100, 16)) {
Serial.println("Failed to initialize I2S!");
while (1); // do nothing
}
162 changes: 162 additions & 0 deletions libraries/I2S/examples/BufferedTone/BufferedTone.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
/*
This example generates a square wave based tone at a specified frequency
and sample rate. Then outputs the data using the I2S interface to a
MAX08357 I2S Amp Breakout board.
I2S Circuit:
* Arduino/Genuino Zero, MKR family, Nano 33 IoT or any ESP32
* MAX08357 or PCM510xA:
| Pin | Zero | MKR | Nano | ESP32 | ESP32-S2, ESP32-C3, ESP32-S3 |
| -----|-------|-------|-------|-------|------------------------------|
| GND | GND | GND | GND | GND | GND |
| 5V | 5V | 5V | 5V | 5V | 5V |
| SCK | 1 | 2 | A3 | 18 | 18 |
| FS | 0 | 3 | A2 | 19 | 19 |
| SD | 9 | A6 | 4 | 21 | 4 |
* note: those chips supports only 16/24/32 bits per sample, i.e. 8 bps will be refused = no audio output
DAC Circuit:
* ESP32
* Audio amplifier
- Note:
- ESP32 has DAC on GPIO pins 25 and 26.
- Connect speaker(s) or headphones.
created 17 November 2016
by Sandeep Mistry
For ESP extended
Tomas Pilny
2nd September 2021
*/

#include <I2S.h>
const int frequency = 1000; // frequency of square wave in Hz
const int sampleRate = 8000; // sample rate in Hz
//const int sampleRate = 44100; // sample rate in Hz
const int bps = 16;
const int amplitude = (1<<(bps-1))-1; // amplitude of square wave

const int halfWavelength = (sampleRate / frequency); // half wavelength of square wave

int32_t sample = amplitude; // current sample value
int count = 0;

void *data;
const size_t data_elements = halfWavelength * 2 * CHANNEL_NUMBER;
const size_t data_len = (bps / 8) * data_elements;

i2s_mode_t mode = I2S_PHILIPS_MODE; // I2S decoder is needed
//i2s_mode_t mode = ADC_DAC_MODE; // bps must be 16; Audio amplifier is needed

// Mono channel input
// This is ESP specific implementation -
// samples will be automatically copied to both channels inside I2S driver
// If you want to have true mono output use I2S_PHILIPS_MODE and interlay
// second channel with 0-value samples.
// The order of channels is RIGH followed by LEFT
//i2s_mode_t mode = I2S_RIGHT_JUSTIFIED_MODE; // I2S decoder is needed

void setup() {
Serial.begin(115200);
Serial.println("I2S simple tone");

// Generate data for buffer write
data = malloc(data_len);
if(data == NULL){
Serial.println("Failed to create data buffer!");
while (1); // do nothing
}

int high;
int low;
switch(bps){
case 8:
high = (mode == I2S_PHILIPS_MODE) ? 0x7F : 0xFF;
low = (mode == I2S_PHILIPS_MODE) ? 0x80 : 0x00;
break;
case 16:
high = (mode == I2S_PHILIPS_MODE) ? 0x7FFF : 0xFFFF;
low = (mode == I2S_PHILIPS_MODE) ? 0x8000 : 0x00;
break;
case 24:
// 24 bps is stored in 32 bit data type on lower 3 Bytes (MSB is ignored)
high = (mode == I2S_PHILIPS_MODE) ? 0x007FFFFF : 0x00FFFFFF;
low = (mode == I2S_PHILIPS_MODE) ? 0x00800000 : 0x00;
break;
case 32:
high = (mode == I2S_PHILIPS_MODE) ? 0x7FFFFFFF : 0xFFFFFFFF;
low = (mode == I2S_PHILIPS_MODE) ? 0x80000000 : 0x00;
break;
}

Serial.printf("Create data buffer for bps %d with values %d=0x%d for high and %d=0x%x for low\n", bps, high, high, low, low);
for(int i = 0; i < data_elements; ++i){
switch(bps){
case 8:
//((int8_t*)data)[i] = i <= data_elements/2 ? 0x7F : 0x80;
//((int8_t*)data)[i] = i <= data_elements/2 ? 0xFF : 0x0;
((int8_t*)data)[i] = (int8_t)(i <= data_elements/2 ? high : low);
break;
case 16:
//((int16_t*)data)[i] = i <= data_elements/2 ? 0x7FFF : 0x8000;
//((int16_t*)data)[i] = i <= data_elements/2 ? 0xFFFF : 0x0;
((int16_t*)data)[i] = (int16_t)(i <= data_elements/2 ? high : low);
break;
case 24:
// 24 bps is stored in 32 bit data type on lower 3 Bytes (MSB is ignored)
//((int32_t*)data)[i] = i <= data_elements/2 ? 0x007FFFFF : 0x00800000;
//((int32_t*)data)[i] = i <= data_elements/2 ? 0x00FFFFFF : 0x0;
((int32_t*)data)[i] = (int32_t)(i <= data_elements/2 ? high : low);
break;
case 32:
//((int32_t*)data)[i] = i <= data_elements/2 ? 0x7FFFFFFF : 0x80000000;
//((int32_t*)data)[i] = i <= data_elements/2 ? 0xFFFFFFFF : 0x0;
((int32_t*)data)[i] = (int32_t)(i <= data_elements/2 ? high : low);
break;
}
}

I2S.setDMABufferSampleSize(data_elements);
Serial.printf("Set buffer sample size to %d\n", data_elements);

// start I2S at the sample rate with 16-bits per sample
if (!I2S.begin(mode, sampleRate, bps)) {
Serial.println("Failed to initialize I2S!");
while (1); // do nothing
}
//I2S.write(data, data_len);
//I2S.write(data, data_len);
}

void loop() {
//size_t bytes_written;
//i2s_write(I2S_NUM_0, data, data_len, &bytes_written, portMAX_DELAY);

int avail = I2S.availableForWrite();
if(avail >= data_len){
Serial.printf("avail for write = %d; data_len=%d\n", avail, data_len);
I2S.write(data, data_len);
//int written = I2S.write(data, data_len);
//Serial.printf("written = %d\n", written);
}else{
//Serial.printf("data_len=%d cannot fit inside buffer of size%d => flush\n",data_len, avail);
//I2S.flush();
//TODO
delay(1);
}


/*
if (count % halfWavelength == 0 ) {
// invert the sample every half wavelength count multiple to generate square wave
sample = -1 * sample;
Serial.printf("sample %d\n", sample);
}
I2S.write(sample); // Right channel
I2S.write(sample); // Left channel
// increment the counter for the next sample
count++;
*/
}
287 changes: 287 additions & 0 deletions libraries/I2S/examples/DualModule/DualModule.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,287 @@
/*
This example is only for ESP32 and ESP32-S3 which have two separate I2S modules
This example demonstrates simultaneous usage of both I2S module.
The application generates square wave for both modules and transfers to each other.
You can plot the waves with Arduino plotter
To prepare the example you will need to connect the output pins of the modules as if they were standalone devices.
The pin-out differ for the SoCs - refer to the table of used SoC.
ESP32
| Pin | I2S | I2S_1 |
| -----|-------|- --------|
| SCK | 18 | 22 |
| FS | 19 | 23 |
| SD 1 | 21 | 35 | I2S DOUT -> I2S_1 DIN
| SD 2 | 34 | 27 | I2S DIN <- I2S_1 DOUT
ESP32-S3
| Pin | I2S | I2S_1 |
| -----|-------|- --------|
| SCK | 18 | 36 |
| FS | 19 | 37 |
| SD 1 | 4 | 40 | I2S DOUT -> I2S_1 DIN
| SD 2 | 5 | 39 | I2S DIN <- I2S_1 DOUT
created 7 Nov 2022
by Tomas Pilny
*/

//#define INTERNAL_CONNECTIONS // uncomment to use without external connections

//#if SOC_I2S_NUM > 1

#include <I2S.h>
#include "hal/gpio_hal.h"
#include "esp_rom_gpio.h"

#include "soc/i2s_periph.h"
#include "soc/gpio_sig_map.h"

const long sampleRate = 8000;
const int bps = 8;
uint8_t *buffer;
uint8_t *buffer1;

const int signal_frequency = 1000; // frequency of square wave in Hz
const int signal_frequency1 = 2000; // frequency of square wave in Hz
const int amplitude = (1<<(bps-1))-1; // amplitude of square wave
const int halfWavelength = (sampleRate / signal_frequency); // half wavelength of square wave
const int halfWavelength1 = (sampleRate / signal_frequency1); // half wavelength of square wave
int32_t write_sample = amplitude; // current sample value
//int32_t write_sample = 165; // current sample value
int32_t write_sample1 = amplitude; // current sample value
int count = 0;
int count1 = 0;

void *write_buffer0;
size_t wr_buf_size0 = (bps/8)*halfWavelength*2;

void *write_buffer1;
size_t wr_buf_size1 = (bps/8)*halfWavelength1*2;

//#define TASK_PRIORITY 0 // only reads
//#define TASK_PRIORITY 1 // sometimes working ok; sometimes only writes
#define TASK_PRIORITY 2 // only writes

/*
static void I2S_write_task(void *args){
while(true){
if(I2S.availableForWrite() >= wr_buf_size0){
Serial.printf("ok write because: I2S.availableForWrite() = %d\n", I2S.availableForWrite());
I2S.write(write_buffer0, wr_buf_size0);
}else{
//Serial.printf("no write because: I2S.availableForWrite() = %d\n", I2S.availableForWrite());
}
delay(1);
}
}
static void I2S_1_write_task(void *args){
while(true){
if(I2S_1.availableForWrite() >= wr_buf_size1){
Serial.printf("ok write because: I2S_1.availableForWrite() = %d\n", I2S_1.availableForWrite());
I2S_1.write(write_buffer1, wr_buf_size1);
}else{
Serial.printf("no write because: I2S_1.availableForWrite() = %d\n", I2S_1.availableForWrite());
}
delay(1);
}
}
*/

void setup() {
Serial.begin(115200, SERIAL_8N1, 16, 17);
while(!Serial);

Serial.printf("Try to init\nI2S: MCLK=%d, SCK=%d, FS=%d, SD=%d, OUT=%d, IN=%d\nI2S1: MCLK=%d, SCK=%d, FS=%d, SD=%d, OUT=%d, IN=%d\n",
I2S.getMclkPin(), I2S.getSckPin(), I2S.getFsPin(), I2S.getDataPin(), I2S.getDataOutPin(), I2S.getDataInPin(),
I2S_1.getMclkPin(), I2S_1.getSckPin(), I2S_1.getFsPin(), I2S_1.getDataPin(), I2S_1.getDataOutPin(), I2S_1.getDataInPin());

I2S.setDMABufferFrameSize(32);
//I2S.setDMABufferFrameSize(halfWavelength > 8 ? halfWavelength : 8);
I2S_1.setDMABufferFrameSize(32);
//I2S_1.setDMABufferFrameSize(halfWavelength1 > 8 ? halfWavelength1 : 8);

if(!I2S.setDuplex()){
Serial.println("ERROR - could not set duplex for I2S");
while(true){
vTaskDelay(10); // Cannot continue
}
}

if (!I2S.begin(I2S_PHILIPS_MODE, sampleRate, bps)) {
Serial.println("Failed to initialize I2S!");
while(true){
vTaskDelay(10); // Cannot continue
}
}
buffer = (uint8_t*) malloc(I2S.getDMABufferByteSize());
if(buffer == NULL){
Serial.println("Failed to allocate buffer!");
while(true){
vTaskDelay(10); // Cannot continue
}
}

if(!I2S_1.setDuplex()){
Serial.println("ERROR - could not set duplex for I2S_1");
while(true){
vTaskDelay(10); // Cannot continue
}
}
if (!I2S_1.begin(I2S_PHILIPS_MODE, bps)) { // start in slave mode
Serial.println("Failed to initialize I2S_1!");
while(true){
vTaskDelay(10); // Cannot continue
}
}

buffer1 = (uint8_t*) malloc(I2S_1.getDMABufferByteSize());
if(buffer1 == NULL){
Serial.println("Failed to allocate buffer1!");
while(true){
vTaskDelay(10); // Cannot continue
}
}

Serial.printf("Initialized successfully\nI2S: MCLK=%d, SCK=%d, FS=%d, SD=%d, OUT=%d, IN=%d\nI2S1: MCLK=%d, SCK=%d, FS=%d, SD=%d, OUT=%d, IN=%d\n",
I2S.getMclkPin(), I2S.getSckPin(), I2S.getFsPin(), I2S.getDataPin(), I2S.getDataOutPin(), I2S.getDataInPin(),
I2S_1.getMclkPin(), I2S_1.getSckPin(), I2S_1.getFsPin(), I2S_1.getDataPin(), I2S_1.getDataOutPin(), I2S_1.getDataInPin());
/*
Serial.printf("Setup done; create tasks with priority %d\n", (int) TASK_PRIORITY);
delay(1000);
xTaskCreate(I2S_write_task, "I2S_write_task", 4096, NULL, (UBaseType_t) TASK_PRIORITY, NULL);
xTaskCreate(I2S_1_write_task, "I2S_1_write_task", 4096, NULL, (UBaseType_t) TASK_PRIORITY, NULL);
xTaskCreate(read_task, "read_task", 4096, NULL, (UBaseType_t) TASK_PRIORITY, NULL);
Serial.println("Tasks created");
*/
Serial.printf("write value (amplitude) = %d\n", write_sample);

// create buffers
write_buffer0 = malloc(wr_buf_size0);
if(write_buffer0 == NULL){
Serial.printf("ERROR creating write_buffer0; halt.");
while(true);
}
write_buffer1 = malloc(wr_buf_size1);
if(write_buffer1 == NULL){
Serial.printf("ERROR creating write_buffer0; halt.");
while(true);
}

for(int i = 0; i < halfWavelength*2; ++i){
if(i % halfWavelength == 0 ) {
write_sample = -1 * write_sample;
}
switch(bps){
case 8:
((int8_t*)write_buffer0)[i] = write_sample;
break;
case 16:
((int16_t*)write_buffer0)[i] = write_sample;
break;
case 24:
case 32:
((int32_t*)write_buffer0)[i] = write_sample;
break;
}
}

for(int i = 0; i < halfWavelength1*2; ++i){
if(i % halfWavelength1 == 0 ) {
write_sample1 = -1 * write_sample1;
}
switch(bps){
case 8:
((int8_t*)write_buffer1)[i] = write_sample1;
break;
case 16:
((int16_t*)write_buffer1)[i] = write_sample1;
break;
case 24:
case 32:
((int32_t*)write_buffer1)[i] = write_sample1;
break;
}
}

/*
xTaskCreate(I2S_write_task, "I2S_write_task", 4096, NULL, (UBaseType_t) TASK_PRIORITY, NULL);
xTaskCreate(I2S_1_write_task, "I2S_1_write_task", 4096, NULL, (UBaseType_t) TASK_PRIORITY, NULL);
Serial.println("Tasks created");
*/

#ifdef INTERNAL_CONNECTIONS
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[PIN_I2S_MCLK], PIN_FUNC_GPIO);
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[PIN_I2S_SCK], PIN_FUNC_GPIO);
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[PIN_I2S_FS], PIN_FUNC_GPIO);
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[PIN_I2S_SD_OUT], PIN_FUNC_GPIO);
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[PIN_I2S_SD_IN], PIN_FUNC_GPIO);

gpio_set_direction(PIN_I2S_MCLK, GPIO_MODE_INPUT_OUTPUT);
gpio_set_direction(PIN_I2S_SCK, GPIO_MODE_INPUT_OUTPUT);
gpio_set_direction(PIN_I2S_FS, GPIO_MODE_INPUT_OUTPUT);
gpio_set_direction(PIN_I2S_SD_OUT, GPIO_MODE_INPUT_OUTPUT);
gpio_set_direction(PIN_I2S_SD_IN, GPIO_MODE_INPUT_OUTPUT);

esp_rom_gpio_connect_out_signal(PIN_I2S_SCK, I2S0I_BCK_OUT_IDX, 0, 0);
esp_rom_gpio_connect_in_signal(PIN_I2S1_SCK, I2S1O_BCK_IN_IDX, 0);

esp_rom_gpio_connect_out_signal(PIN_I2S_FS, I2S0I_WS_OUT_IDX, 0, 0);
esp_rom_gpio_connect_in_signal(PIN_I2S1_FS, I2S1O_WS_IN_IDX, 0);

esp_rom_gpio_connect_out_signal(DATA_MASTER_TO_SLAVE, I2S0_DATA_OUT_IDX, 0, 0);
esp_rom_gpio_connect_in_signal(DATA_MASTER_TO_SLAVE, I2S1_DATA_IN_IDX, 0);

esp_rom_gpio_connect_out_signal(DATA_SLAVE_TO_MASTER, I2S1_DATA_OUT_IDX, 0, 0);
esp_rom_gpio_connect_in_signal(DATA_SLAVE_TO_MASTER, I2S0_DATA_IN_IDX, 0);
#endif
}

int read_sample;
int read_sample1;

void loop() {
if(I2S.availableForWrite() >= wr_buf_size0){
//Serial.printf("ok write because: I2S.availableForWrite() = %d and the buffer is %d Bytes (wr_buf_size0)\n", I2S.availableForWrite(), wr_buf_size0);
I2S.write(write_buffer0, wr_buf_size0);
}
if(I2S_1.availableForWrite() >= wr_buf_size1){
//Serial.printf("ok write because: I2S_1.availableForWrite() = %d and the buffer is %d Bytes (wr_buf_size1)\n", I2S_1.availableForWrite(), wr_buf_size1);
//Serial.printf("ok write because: I2S_1.availableForWrite() = %d\n", I2S_1.availableForWrite());
I2S_1.write(write_buffer1, wr_buf_size1);
}

if(I2S.available()){
read_sample = I2S.read();
Serial.printf("Slave to master: 0x%X=%hhd\n", read_sample, (char)read_sample);
//Serial.printf("1->0: 0x%X=%hhd\n", read_sample, (char)read_sample);
}

if(I2S_1.available()){
read_sample1 = I2S_1.read();
//Serial.printf("0->1: 0x%X=%hhd\n", read_sample1, (char)read_sample1);
Serial.printf("Master to slave: 0x%X=%hhd\n", read_sample1, (char)read_sample1);
}

// if(read_sample && read_sample1){
/*
if(read_sample || read_sample1){
Serial.printf("1->0: 0x%X=%hhd; 0->1: 0x%X=%hhd\n", read_sample, (char)read_sample, read_sample1, (char)read_sample1);
}
*/
}
/*
extern "C" void app_main(){
setup();
while(true){loop();}
}
*/
//#else
// #error "This example cannot run on current SoC - the example requires two I2S modules found in ESP32 and ESP32-S3"
//#endif



35 changes: 16 additions & 19 deletions libraries/I2S/examples/FullDuplex/FullDuplex.ino
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
/*
This example is only for ESP
This example demonstrates simultaneous usage of microphone and speaker using single I2S module.
The application transfers data from input to output
The application transfers data from input to output.
You will need I2S microphone I2S decoder + headphones or speaker to be plugged into the I2S decoder.
Circuit:
* ESP32
* GND connected GND
* VIN connected 5V
* SCK 5
* FS 25
* DIN 35
* DOUT 26
* I2S microphone
* I2S decoder + headphones / speaker
| Pin | ESP32 | ESP32-S2, ESP32-C3, ESP32-S3 |
| -------- |-------|------------------------------|
| GND | GND | GND |
| VIN | 5V | 5V |
| SCK | 18 | 18 |
| FS | 19 | 19 |
| SD(DOUT) | 21 | 4 |
| DIN | 34 | 5 |
created 8 October 2021
by Tomas Pilny
@@ -25,7 +24,7 @@ uint8_t *buffer;

void setup() {
Serial.begin(115200);
//I2S.setAllPins(5, 25, 35, 26); // you can change default pins; order of pins = (CLK, WS, IN, OUT)
//I2S.setAllPins(18, 19, 21, 21, 34); // you can change default pins; order of pins = (CLK, WS, SD, SDIN, SDOUT)
if(!I2S.setDuplex()){
Serial.println("ERROR - could not set duplex");
while(true){
@@ -38,7 +37,7 @@ void setup() {
vTaskDelay(10); // Cannot continue
}
}
buffer = (uint8_t*) malloc(I2S.getBufferSize() * (bitsPerSample / 8));
buffer = (uint8_t*) malloc(I2S.getDMABufferByteSize());
if(buffer == NULL){
Serial.println("Failed to allocate buffer!");
while(true){
@@ -49,11 +48,9 @@ void setup() {
}

void loop() {
//I2S.write(I2S.read()); // primitive implementation sample-by-sample
//I2S.write(I2S.read()); // Primitive implementation sample-by-sample is discouraged

// Buffer based implementation
I2S.read(buffer, I2S.getBufferSize() * (bitsPerSample / 8));
I2S.write(buffer, I2S.getBufferSize() * (bitsPerSample / 8));

//optimistic_yield(1000); // yield if last yield occurred before <parameter> CPU clock cycles ago
// Buffer based implementation which is strongly advised
I2S.read(buffer, I2S.getDMABufferByteSize());
I2S.write(buffer, I2S.getDMABufferByteSize());
}
27 changes: 17 additions & 10 deletions libraries/I2S/examples/InputSerialPlotter/InputSerialPlotter.ino
Original file line number Diff line number Diff line change
@@ -7,11 +7,14 @@
Circuit:
* Arduino/Genuino Zero, MKR family and Nano 33 IoT
* ICS43432:
* GND connected GND
* 3.3V connected to 3.3V (Zero, Nano, ESP32), VCC (MKR)
* WS connected to pin 0 (Zero) or 3 (MKR), A2 (Nano) or 25 (ESP32)
* CLK connected to pin 1 (Zero) or 2 (MKR), A3 (Nano) or 5 (ESP32)
* SD connected to pin 9 (Zero) or A6 (MKR), 4 (Nano) or 26 (ESP32)
| Pin | Zero | MKR | Nano | ESP32 | ESP32-S2, ESP32-C3, ESP32-S3 |
| -----|-------|-------|-------|-------|------------------------------|
| GND | GND | GND | GND | GND | GND |
| 3.3V | 3.3V | 3.3V | 3.3V | 3.3V | 3.3V |
| SCK | 1 | 2 | A3 | 18 | 18 |
| FS | 0 | 3 | A2 | 19 | 19 |
| SD | 9 | A6 | 4 | 21 | 4 |
created 17 November 2016
by Sandeep Mistry
*/
@@ -28,17 +31,21 @@ void setup() {
}

// start I2S at 8 kHz with 32-bits per sample
if (!I2S.begin(I2S_PHILIPS_MODE, 8000, 32)) {
if (!I2S.begin(I2S_PHILIPS_MODE, 32000, 32)) {
Serial.println("Failed to initialize I2S!");
while (1); // do nothing
}
}

void loop() {
// read a sample
int sample = I2S.read();
int sample;
int available = I2S.available();
//Serial.printf("avail %d\n", available);
if(available){
sample = I2S.read(); // read a sample

if (sample && sample != -1 && sample != 1) {
Serial.println(sample);
//if(abs(sample) > 2){
Serial.println(sample);
//}
}
}
88 changes: 88 additions & 0 deletions libraries/I2S/examples/PinMap/PinMap.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// This is actually some personal stuff, not actually example ...
// probably to search usable pins - hence the name


/*
This example is only for ESP32 and ESP32-S3 which have two separate I2S modules
This example demonstrates simultaneous usage of both I2S module.
The application generates square wave for both modules and transfers to each other.
You can plot the waves with Arduino plotter
To prepare the example you will need to connect the output pins of the modules as if they were standalone devices.
The pin-out differ for the SoCs - refer to the table of used SoC.
ESP32
| Pin | I2S | I2S_1 |
| -----|-------|- --------|
| SCK | 18 | 22 |
| FS | 19 | 23 |
| SD 1 | 21 | 35 | I2S DOUT -> I2S_1 DIN
| SD 2 | 34 | 27 | I2S DIN <- I2S_1 DOUT
ESP32-S3
| Pin | I2S | I2S_1 |
| -----|-------|- --------|
| SCK | 18 | 36 |
| FS | 19 | 37 |
| SD 1 | 4 | 40 | I2S DOUT -> I2S_1 DIN
| SD 2 | 5 | 39 | I2S DIN <- I2S_1 DOUT
created 7 Nov 2022
by Tomas Pilny
*/

#include <I2S.h>
#include "hal/gpio_hal.h"
#include "esp_rom_gpio.h"

#include "soc/i2s_periph.h"
#include "soc/gpio_sig_map.h"

//uint8_t ban_pins[] = {1,3,6,7,8,9,10,11,24,28,29,30,31}; // ESP32 WROVER-B
uint8_t ban_pins[] = {1,3,6,7,8,9,10,11,20,24,28,29,30,31}; // ESP32 WROVER-B
uint8_t data[] = {0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55};

void setup() {
Serial.begin(115200);
while(!Serial);

if (!I2S.begin(I2S_PHILIPS_MODE, 8000, 8)) {
Serial.println("Failed to initialize I2S!");
while(true){
vTaskDelay(10); // Cannot continue
}
}
int ret;
bool skip;
I2S.setDataPin(21);
int ban_size = sizeof(ban_pins) / sizeof(ban_pins[0]);
Serial.println("Initial setup done");
for(int pin = 22; pin < 34; ++pin){
skip = false;
Serial.printf("* * * * * * * * Try to set SCK pin to %d * * * * * * * *\n", pin);
for(int i = 0; i < ban_size; ++i){
if(pin == ban_pins[i]){
Serial.printf("pin %d is on ban list - skip\n", pin);
skip = true;
break; // out of inner loop
}
}
if(skip){ continue; }
if(pin == I2S.getFsPin()) I2S.setFsPin(pin-1);
if(pin == I2S.getDataPin()) I2S.setDataPin(pin-1);
ret = I2S.setSckPin(pin);
Serial.printf("Set pin returned %s\n", ret ? "OK" : "FAILED");
Serial.printf("I2S: SCK=%d, FS=%d, SD=%d\n", I2S.getSckPin(), I2S.getFsPin(), I2S.getDataPin());
uint8_t byte;
while(!Serial.available()){
I2S.write_blocking(data, sizeof(data) / sizeof(data[0]));
//delay(10);
}
byte = Serial.read();
Serial.printf("Serial received byte %d = char %c\n", byte, byte);
}
}

void loop() {
delay(1000);
}
Empty file.
35 changes: 16 additions & 19 deletions libraries/I2S/examples/SimpleTone/SimpleTone.ino
Original file line number Diff line number Diff line change
@@ -4,20 +4,22 @@
MAX08357 I2S Amp Breakout board.
I2S Circuit:
* Arduino/Genuino Zero, MKR family and Nano 33 IoT
* MAX08357:
* GND connected GND
* VIN connected 5V
* LRC connected to pin 0 (Zero) or 3 (MKR), A2 (Nano) or 25 (ESP32)
* BCLK connected to pin 1 (Zero) or 2 (MKR), A3 (Nano) or 5 (ESP32)
* DIN connected to pin 9 (Zero) or A6 (MKR), 4 (Nano) or 26 (ESP32)
* Arduino/Genuino Zero, MKR family, Nano 33 IoT or any ESP32
* MAX08357 or PCM510xA:
| Pin | Zero | MKR | Nano | ESP32 | ESP32-S2, ESP32-C3, ESP32-S3 |
| -----|-------|-------|-------|-------|------------------------------|
| GND | GND | GND | GND | GND | GND |
| 5V | 5V | 5V | 5V | 5V | 5V |
| SCK | 1 | 2 | A3 | 18 | 18 |
| FS | 0 | 3 | A2 | 19 | 19 |
| SD | 9 | A6 | 4 | 21 | 4 |
* note: those chips supports only 16/24/32 bits per sample, i.e. 8 bps will be refused = no audio output
DAC Circuit:
* ESP32 or ESP32-S2
* ESP32
* Audio amplifier
- Note:
- ESP32 has DAC on GPIO pins 25 and 26.
- ESP32-S2 has DAC on GPIO pins 17 and 18.
- Connect speaker(s) or headphones.
created 17 November 2016
@@ -29,17 +31,17 @@

#include <I2S.h>
const int frequency = 440; // frequency of square wave in Hz
const int amplitude = 500; // amplitude of square wave
const int sampleRate = 8000; // sample rate in Hz
const int bps = 16;
const int amplitude = (1<<(bps-1))-1; // amplitude of square wave

const int halfWavelength = (sampleRate / frequency); // half wavelength of square wave

short sample = amplitude; // current sample value
int32_t sample = amplitude; // current sample value
int count = 0;

i2s_mode_t mode = I2S_PHILIPS_MODE; // I2S decoder is needed
// i2s_mode_t mode = ADC_DAC_MODE; // Audio amplifier is needed
//i2s_mode_t mode = ADC_DAC_MODE; // Audio amplifier is needed

// Mono channel input
// This is ESP specific implementation -
@@ -66,13 +68,8 @@ void loop() {
sample = -1 * sample;
}

if(mode == I2S_PHILIPS_MODE || mode == ADC_DAC_MODE){ // write the same sample twice, once for Right and once for Left channel
I2S.write(sample); // Right channel
I2S.write(sample); // Left channel
}else if(mode == I2S_RIGHT_JUSTIFIED_MODE || mode == I2S_LEFT_JUSTIFIED_MODE){
// write the same only once - it will be automatically copied to the other channel
I2S.write(sample);
}
I2S.write(sample); // Right channel
I2S.write(sample); // Left channel

// increment the counter for the next sample
count++;
803 changes: 526 additions & 277 deletions libraries/I2S/src/I2S.cpp

Large diffs are not rendered by default.

448 changes: 395 additions & 53 deletions libraries/I2S/src/I2S.h

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions libraries/Ticker/src/Ticker.cpp
Original file line number Diff line number Diff line change
@@ -31,9 +31,9 @@ Ticker::~Ticker() {
detach();
}

void Ticker::_attach_ms(uint32_t milliseconds, bool repeat, callback_with_arg_t callback, uint32_t arg) {
void Ticker::_attach_ms(uint32_t milliseconds, bool repeat, callback_with_arg_t callback) {
esp_timer_create_args_t _timerConfig;
_timerConfig.arg = reinterpret_cast<void*>(arg);
_timerConfig.arg = NULL;
_timerConfig.callback = callback;
_timerConfig.dispatch_method = ESP_TIMER_TASK;
_timerConfig.name = "Ticker";
562 changes: 562 additions & 0 deletions tests/i2s/i2s.ino

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions tests/i2s/test_i2s.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
def test_i2s(dut):
dut.expect_unity_test_output(timeout=120)
10 changes: 5 additions & 5 deletions tools/sdk/esp32/include/driver/include/driver/i2s.h
Original file line number Diff line number Diff line change
@@ -140,11 +140,11 @@ typedef intr_handle_t i2s_isr_handle_t; // for backward compatible
*/
typedef enum {
I2S_EVENT_DMA_ERROR,
I2S_EVENT_TX_DONE, /*!< I2S DMA finish sent 1 buffer*/
I2S_EVENT_RX_DONE, /*!< I2S DMA finish received 1 buffer*/
I2S_EVENT_TX_Q_OVF, /*!< I2S DMA sent queue overflow*/
I2S_EVENT_RX_Q_OVF, /*!< I2S DMA receive queue overflow*/
I2S_EVENT_MAX, /*!< I2S event max index*/
I2S_EVENT_TX_DONE, /*!< 1 I2S DMA finish sent 1 buffer*/
I2S_EVENT_RX_DONE, /*!< 2 I2S DMA finish received 1 buffer*/
I2S_EVENT_TX_Q_OVF, /*!< 3 I2S DMA sent queue overflow*/
I2S_EVENT_RX_Q_OVF, /*!< 4 I2S DMA receive queue overflow*/
I2S_EVENT_MAX, /*!< 5 I2S event max index*/
} i2s_event_type_t;

/**