-
Notifications
You must be signed in to change notification settings - Fork 7.7k
Description
Board
ESP32-C3-WROOM-02
Device Description
The module is mounted on a custom PCB, along with 3 i2C sensors, a OLED display and a i2S based SPH0645 microphone. All GPIO are being used.
Hardware Configuration
i2C pins: SDA=1; SCL=0
i2S pins: SCK=3; WS=21; SD=20
i2C devices
QMC5883L compass
LTR-553ALS light sensor
LSM6DSL 6-DoF acc/gyro
SSD1306
i2S device:
SPH0645 MEMS Microphone
Version
v2.0.6
IDE Name
PlatformIO Core: 6.1.5, Home: 3.4.3
Operating System
Ubuntu
Flash frequency
40MHz
PSRAM enabled
no
Upload speed
921600
Description
initializing a i2C bus and device before the i2s_set_pin function is called will cause the buses to stop working (i2C bus has to time out before code will continue). i2S bus doesn't seem to return proper data.
I would expect there would be no dependency on the order of initialization.
Sketch
//////////////////////////////////////////////////////////
/*
Minimal code for a ESP32-C3-WROOM-02 based i2S SPH0645 MEMS microphone and a i2C SSD1306 OLED display mounted on a custom PCB.
If I remark out the i2C code, the i2S code seems to work ok. If I remark out the i2S code, then the display works ok.
In fact, I have 3 other i2C based sensors: QMC5883, LTR-553 and a LSM6DSL all working ok with the OLED display and WiFi.
Only when I turn on the i2S and any one i2C based item, does i2C stall (stops working and times out after some seconds)
when the "i2s_set_pin" function is called.
Resolution:
Place the i2S init code BEFORE any i2C init code, then both i2S and i2C work ok.
i2C pins: SDA=1; SCL=0
i2S pins: SCK=3; WS=21; SD=20
Notes:
* Red LED blinks at the end of a loop
* Yellow LED lights up near the end of the code Setup
* Blue LED lights up depending on the sound level
* Green PWR LED lights up when power is applied
*/
/////////////////////////////////////////////////////////////////
#include <Arduino.h>
#include <driver/i2s.h>
#include "SSD1306Wire.h"
// i2C GPIO pin assignments:
#define i2C_SDA 1
#define i2C_SCL 0
// i2S Microphone GPIO assignments
#define I2S_SCK_RX 3
#define I2S_WS_RX 21
#define I2S_SD_RX 20
#define I2S_PORT_RX I2S_NUM_0
#define ledXpin 7 // for USB LED String PCB
#define ledYpin 6 // for USB LED String PCB
#define ledSNDpin 4 // for USB LED String PCB
#define ledChannelX 1 // X LED
#define ledChannelY 2 // Y LED
#define ledChannelSND 4 // SND LED
#define ledPWMFreq 500 // Frequency specified in Hz
#define resolution 8
#define SAMPLE_BUFFER_SIZE 512
#define SAMPLE_RATE 16000
#define SAMPLE_BITS 32
#define DMA_BANKS 4
#define DMA_BANK_SIZE 1024
esp_err_t i2Serr;
SSD1306Wire display(0x3c, i2C_SDA, i2C_SCL); // ADDRESS, SDA, SCL
TaskHandle_t i2sReadTaskHandler = NULL;
const i2s_config_t i2s_config_rx = {
.mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_RX),
.sample_rate = SAMPLE_RATE,
.bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT,
.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT, // SPH0645 is wired for Rightside, but need to call for LEFT
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
.intr_alloc_flags = i2s_comm_format_t(I2S_COMM_FORMAT_STAND_I2S),
.dma_buf_count = DMA_BANKS,
.dma_buf_len = DMA_BANK_SIZE,
.use_apll = false,
.tx_desc_auto_clear = false,
.fixed_mclk = 0};
const i2s_pin_config_t pin_config_rx = {
.bck_io_num = I2S_SCK_RX,
.ws_io_num = I2S_WS_RX,
.data_out_num = I2S_PIN_NO_CHANGE,
.data_in_num = I2S_SD_RX};
void i2s_RX_init()
{
i2Serr = i2s_driver_install(I2S_PORT_RX, &i2s_config_rx, 0, NULL);
if (i2Serr != ESP_OK)
{
// Serial.printf("Failed installing i2S driver: %d\n", i2Serr);
while (true)
;
}
display.drawString(2, 12, "This does work");
display.display(); // now the display times out with no updated text
i2Serr = i2s_set_pin(I2S_PORT_RX, &pin_config_rx);
if (i2Serr != ESP_OK)
{
// Serial.printf("Failed setting i2S pin: %d\n", i2Serr);
while (true)
;
}
display.drawString(2, 24, "This doesn't work");
display.display(); // now the display times out with no updated text
}
void i2s_reader_task(void *parameter)
{
while (1)
{
uint8_t dutyCycle = 0;
int32_t samples[DMA_BANK_SIZE];
size_t num_bytes_read = 0;
i2s_read(I2S_PORT_RX, &samples, DMA_BANK_SIZE, &num_bytes_read, portMAX_DELAY); // read microphone data into buffer
int samples_read = num_bytes_read / 8;
if (samples_read > 0)
{
// Do something with the audio 'samples'...
float mean = 0;
for (int i = 0; i < samples_read; ++i)
{
mean += (samples[i] >> 14);
}
mean /= samples_read;
float maxsample = -1e8, minsample = 1e8;
for (int i = 0; i < samples_read; ++i)
{
minsample = min(minsample, samples[i] - mean);
maxsample = max(maxsample, samples[i] - mean);
}
float result = (maxsample - minsample) / 100000000;
// light up the SND LED - make it fluctuate depending on sound level. could be a funct
if (result > 32)
{
dutyCycle = 255;
}
else if (result > 16)
{
dutyCycle = 255;
}
else if (result > 8)
{
dutyCycle = 180;
}
else if (result > 4)
{
dutyCycle = 100;
}
else if (result > 2)
{
dutyCycle = 64;
}
else
dutyCycle = 0;
ledcWrite(ledChannelSND, dutyCycle); // adjust the Blue SND LED brightness level
display.drawString(2, 36, "this doesn't work");
display.display(); // now the display times out with no updated text
}
// end of loop - flash LEDX to show it's all working ok
ledcWrite(ledChannelX, 100); // adjust LED brightness level
vTaskDelay(100);
ledcWrite(ledChannelX, 0); // adjust LED brightness level
vTaskDelay(100);
}
}
void setup()
{
// setup LED's for visual feedback
ledcSetup(ledChannelX, ledPWMFreq, resolution);
ledcSetup(ledChannelY, ledPWMFreq, resolution);
ledcSetup(ledChannelSND, ledPWMFreq, resolution);
ledcAttachPin(ledXpin, ledChannelX);
ledcAttachPin(ledYpin, ledChannelY);
ledcAttachPin(ledSNDpin, ledChannelSND);
ledcWrite(ledChannelX, 0);
ledcWrite(ledChannelY, 0);
ledcWrite(ledChannelSND, 0);
// setup SSD1306 OLED screen works and text displays ok
Wire.begin(i2C_SDA, i2C_SCL); // not needed as OLED display init does this too, just listing it to show completness
display.init();
display.setFont(ArialMT_Plain_10);
display.drawString(2, 0, "Test code");
display.drawHorizontalLine(1, 11, 127);
display.display();
// setup i2S
ledcWrite(ledChannelX, 100);
vTaskDelay(500);
i2s_RX_init();
vTaskDelay(100);
ledcWrite(ledChannelY, 100);
xTaskCreatePinnedToCore(i2s_reader_task, "i2s_reader_task", 10000, NULL, 1, &i2sReadTaskHandler, 0);
}
void loop()
{
} // not used, as we are using Tasks
Debug Message
Note: LED's are being used for debugging purposes and have no impact on the actual issue
As I don't have access to the serial port, I don't have any error messages being presented. I use the LEDs to note a long many second timeout (with no more data being written to the i2C display) when a i2C bus is used after the i2S bus has been initalized after the i2C bas was initialzed first.
Other Steps to Reproduce
- init i2C first.
- use i2C to display text - all ok;
- Run the i2S initialization. "this does work" is displayed on the screen. "This doesn't work" is not displayed on the screen and no further i2C bus communications work, with a many second pause in code runtime (while the i2C bus times out?). i2S bus doesn't seem to work either.
Steps to make the code work:
A) call the i2S bus initialization first, before the i2C bus init (ie: Wire.begin()) is called. Both i2C and i2S function as expected.
I have checked existing issues, online documentation and the Troubleshooting Guide
- I confirm I have checked existing issues, online documentation and Troubleshooting guide.