Need some help here.
Running an ESP32 WROOM and using 2 x I2S interfaces (In (Microphone) & Out (Amplifier))), I2C interface and SPI interface. The I2C controls a Texas Instruments Class D Amplifier, while the SPI connects to an SD card for WAV & MP3 files.
This functionality all works and I can play MP3 tracks or switch to the I2S microphone all satisfactorily.
However, I need to enable ESP NOW and as soon as I do, I get a boot loop when the setup function calls:
Code: Select all
// Initialise WiFi ESP Now
if (esp_now_init() != ESP_OK) {
Serial.println("Error initializing ESP-NOW");
return;
}
else Serial.println("ESP initialized succesfully");
Code: Select all
Guru Meditation Error: Core 1 panic'ed (LoadProhibited). Exception was unhandled.
Core 1 register dump:
PC : 0x400f3228 PS : 0x00060830 A0 : 0x800d556b A1 : 0x3ffb2130
A2 : 0x3ffc3df4 A3 : 0x3ffc0a84 A4 : 0x3ffc3df4 A5 : 0x00000000
A6 : 0x00000080 A7 : 0x000000d1 A8 : 0x800d975c A9 : 0x3ffb2110
A10 : 0x000007d0 A11 : 0x3ffbf448 A12 : 0x00000006 A13 : 0x00000001
A14 : 0x0000001e A15 : 0x3ffb5ba0 SAR : 0x00000011 EXCCAUSE: 0x0000001c
EXCVADDR: 0x0000004c LBEG : 0x40087b7d LEND : 0x40087b8d LCOUNT : 0xffffffff
Backtrace: 0x400f3225:0x3ffb2130 0x400d5568:0x3ffb2150 0x400db11a:0x3ffb2290
ELF file SHA256: a0a6f367b418dd65
Code: Select all
// I2S & Amplifier Test Sketch
// Christopher Cooper - December 2023
// Include required libraries
#include "Arduino.h"
#include <esp_now.h>
#include <WiFi.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <FS.h>
#include <AudioConfig.h> // Phil Schatzmann Audio Tools Library
#include <AudioLogger.h> // Phil Schatzmann Audio Tools Library
#include <AudioTools.h> // Phil Schatzmann Audio Tools Library
#include <AudioCodecs/AudioCodecs.h> // Phil Schatzmann Audio Tools Library
// MicroSD Card Reader connections
#define SD_CS 5
#define SPI_MOSI 23
#define SPI_MISO 19
#define SPI_SCK 18
// I2C Connections
#define I2C_SDA 21
#define I2C_SCL 22
// I2S Channle One
#define I2S_DIN_0 13
#define I2S_BCLK_0 14
#define I2S_LRC_0 15
// I2s Channel Two
#define I2S_DOUT_1 16
#define I2S_BCLK_1 4
#define I2S_LRC_1 17
#define I2S_MCLK_1 0
// TAS5760L registers
#define TAS5760L_ADDRESS 0x6C
#define TAS5760L_PWRCTRL 0x01
#define TAS5760L_DIGCTRL 0x02
#define TAS5760L_ANALOGCTRL 0x06
#define TAS5760L_VOLCONFIG 0x30
#define TAS5760L_LEFTVOLCONFIG 0x04
#define TAS5760L_RIGHTVOLCONFIG 0x05
#define TAS5760L_FAULT 0x08
// Transmitter MAC Address. e0:98:06:85:b7:a6
uint8_t broadcastAddress[] = { 0xE0, 0x98, 0x06, 0x85, 0xB7, 0xA6 };
// Struct data set.
typedef struct struct_message_control {
unsigned int soundClip;
} struct_message_control;
// Create a struct_message_control called myData.
struct_message_control myData;
// Create ESP now peering.
esp_now_peer_info_t peerInfo;
// Create Audio object
AudioInfo info(44100, 2, 16);
I2SStream in;
I2SStream out;
EncodedAudioStream decoder(&out, new WAVDecoder()); // Decoding stream
//EncodedAudioStream decoder(&out, new MP3DecoderHelix()); // Decoding stream
StreamCopy mp3;
StreamCopy mic(out, in);
File audioFile;
//Audio audio;
// Define pin outs
#define spkFault 33
// #define spkSleep 15
#define spkShutDown 32
#define redButton 39
#define greenButton 34
#define blueButton 35
#define blackButton 36
#define yellowButtonOne 26
#define yellowButtonTwo 25
#define singleRedButton 27
#define singleGreenButton 2
// Keep alive variables.
int failureCount = 0; // Amount of comms failures before disable.
// Define variables
boolean tas5760lError = HIGH;
boolean amplifierEnabledFlag = LOW;
boolean amplifierEnabledFlagChanged = LOW;
boolean playerControlFlag = LOW;
boolean playerControlFlagChanged = LOW;
boolean micControlFlag = LOW;
boolean micControlFlagChanged = LOW;
boolean redButtonFlag = LOW;
boolean redButtonFlagChanged = LOW;
boolean volumeChangeFlag = LOW;
byte volumeSetting = 0;
byte volumeSettingDisplay = 0;
unsigned int playTrack = 0;
boolean longSong = LOW;
/*-----------------------------------------------------------------*/
// Amplifier control interrupt
void IRAM_ATTR amplifierControlISR() {
static unsigned long last_interrupt_time = 0; // Function to solve debounce.
unsigned long interrupt_time = millis();
if (interrupt_time - last_interrupt_time > 200) {
if (amplifierEnabledFlag == LOW) {
amplifierEnabledFlag = HIGH;
amplifierEnabledFlagChanged = HIGH;
}
else if (amplifierEnabledFlag == HIGH) {
amplifierEnabledFlag = LOW;
amplifierEnabledFlagChanged = HIGH;
}
}
last_interrupt_time = interrupt_time;
}
/*-----------------------------------------------------------------*/
// Player control interrupt
void IRAM_ATTR playerControlISR() {
static unsigned long last_interrupt_time = 0; // Function to solve debounce.
unsigned long interrupt_time = millis();
if (interrupt_time - last_interrupt_time > 200) {
if (playerControlFlag == LOW) {
playerControlFlag = HIGH;
playerControlFlagChanged = HIGH;
micControlFlag = LOW;
}
else if (playerControlFlag == HIGH) {
playerControlFlag = LOW;
playerControlFlagChanged = HIGH;
micControlFlag = LOW;
}
}
last_interrupt_time = interrupt_time;
}
/*-----------------------------------------------------------------*/
// Microphone control interrupt
void IRAM_ATTR micControlISR() {
static unsigned long last_interrupt_time = 0; // Function to solve debounce.
unsigned long interrupt_time = millis();
if (interrupt_time - last_interrupt_time > 200) {
if (micControlFlag == LOW) {
micControlFlag = HIGH;
micControlFlagChanged = HIGH;
playerControlFlag = LOW;
}
else if (micControlFlag == HIGH) {
micControlFlag = LOW;
micControlFlagChanged = HIGH;
playerControlFlag = LOW;
}
}
last_interrupt_time = interrupt_time;
}
/*-----------------------------------------------------------------*/
// Find I2S devices
void i2sAddress() {
byte error, address;
int nDevices = 0;
delay(1000);
Serial.println("Scanning for I2C devices ...");
for (address = 0x01; address < 0x7f; address++) {
Wire.beginTransmission(address);
error = Wire.endTransmission();
if (error == 0) {
Serial.printf("I2C device found at address 0x%02X\n", address);
nDevices++;
}
else if (error != 2) {
Serial.printf("Error %d at address 0x%02X\n", error, address);
}
}
if (nDevices == 0) {
Serial.println("No I2C devices found");
}
delay(1000);
}
/*-----------------------------------------------------------------*/
// Write I2C register function
void writeRegister(uint8_t address, uint8_t reg, int value) {
Wire.beginTransmission(address);
Wire.write(reg);
Wire.write(value);
Wire.endTransmission();
}
/*-----------------------------------------------------------------*/
// Read I2C register function
int readRegister(uint8_t address, uint8_t reg) {
Wire.beginTransmission(address);
Wire.write(reg);
Wire.endTransmission(false);
Wire.requestFrom(static_cast<uint8_t>(address), static_cast<uint8_t>(1)); // Explicit casting
if (Wire.available()) {
return Wire.read();
}
return -1;
}
/*-----------------------------------------------------------------*/
// Display registers
void displayRegisterValues() {
// Read and display the values of specific registers
byte whoAmI = readRegister(TAS5760L_ADDRESS, 0x00);
byte pwrCtrl = readRegister(TAS5760L_ADDRESS, TAS5760L_PWRCTRL);
byte digCtrl = readRegister(TAS5760L_ADDRESS, TAS5760L_DIGCTRL);
byte analogCtrl = readRegister(TAS5760L_ADDRESS, TAS5760L_ANALOGCTRL);
byte volConfig = readRegister(TAS5760L_ADDRESS, TAS5760L_VOLCONFIG);
byte volLeft = readRegister(TAS5760L_ADDRESS, TAS5760L_LEFTVOLCONFIG);
byte volRight = readRegister(TAS5760L_ADDRESS, TAS5760L_RIGHTVOLCONFIG);
byte fault = readRegister(TAS5760L_ADDRESS, TAS5760L_FAULT);
// Print register values to the serial monitor
Serial.println();
Serial.println("Register Values:");
Serial.println();
Serial.print("TAS5760L Who Am I: 0x");
Serial.println(whoAmI, HEX);
Serial.print("TAS5760L Power Control: 0x");
Serial.println(pwrCtrl, HEX);
Serial.print("TAS5760L Digital Control:0x");
Serial.println(digCtrl, HEX);
Serial.print("TAS5760L Analog Control: 0x");
Serial.println(analogCtrl, HEX);
Serial.print("TAS5760L Volume Config: 0x");
Serial.println(volConfig, HEX);
Serial.print("TAS5760L Volume Left : 0x");
Serial.println(volLeft, HEX);
Serial.print("TAS5760L Volume Right : 0x");
Serial.println(volRight, HEX);
Serial.print("TAS5760L Fault: 0x");
Serial.println(fault, HEX);
}
/*-----------------------------------------------------------------*/
// Display amplifier faults
void displayFaultRegister() {
// Read and display the values of specific registers
byte fault = readRegister(TAS5760L_ADDRESS, TAS5760L_FAULT);
// Print register values to the serial monitor
Serial.print("TAS5760L Fault: 0x");
Serial.println(fault, BIN);
}
/*-----------------------------------------------------------------*/
// Configure digital control registers
void configureDigCtrlRegisters() {
// Set FUNC_CFG_ACCESS and PIN_CTRL registers
writeRegister(TAS5760L_ADDRESS, TAS5760L_DIGCTRL, B00010100);
}
/*-----------------------------------------------------------------*/
// Configure analog control registers
void configureAnalogCtrlRegisters() {
// Set FUNC_CFG_ACCESS and PIN_CTRL registers
writeRegister(TAS5760L_ADDRESS, TAS5760L_ANALOGCTRL, B11010001);
}
/*-----------------------------------------------------------------*/
// Configure shutdown registers
void shutDownRegisters() {
// Set FUNC_CFG_ACCESS and PIN_CTRL registers
writeRegister(TAS5760L_ADDRESS, TAS5760L_PWRCTRL, B11111110);
}
/*-----------------------------------------------------------------*/
// Configure start up registers
void startUpRegisters() {
// Set FUNC_CFG_ACCESS and PIN_CTRL registers
writeRegister(TAS5760L_ADDRESS, TAS5760L_PWRCTRL, B11111101);
}
/*-----------------------------------------------------------------*/
// Configure mute registers
void muteRegisters() {
// Set FUNC_CFG_ACCESS and PIN_CTRL registers
writeRegister(TAS5760L_ADDRESS, TAS5760L_VOLCONFIG, B10000011);
}
/*-----------------------------------------------------------------*/
// Configure un-mute registers
void unmuteRegisters() {
// Set FUNC_CFG_ACCESS and PIN_CTRL registers
writeRegister(TAS5760L_ADDRESS, TAS5760L_VOLCONFIG, B10000000);
}
/*-----------------------------------------------------------------*/
// Configure volume control registers
void volumeLowSetRegister() {
// Set FUNC_CFG_ACCESS and PIN_CTRL registers
writeRegister(TAS5760L_ADDRESS, TAS5760L_LEFTVOLCONFIG, B01111001);
writeRegister(TAS5760L_ADDRESS, TAS5760L_RIGHTVOLCONFIG, B01111001);
}
/*-----------------------------------------------------------------*/
// Configure volume control registers
void volumeDefaultSetRegister() {
// Set FUNC_CFG_ACCESS and PIN_CTRL registers
writeRegister(TAS5760L_ADDRESS, TAS5760L_LEFTVOLCONFIG, B11001111);
writeRegister(TAS5760L_ADDRESS, TAS5760L_RIGHTVOLCONFIG, B11001111);
}
/*-----------------------------------------------------------------*/
// spkShutDown to LOW, places the amplifier in shutdown
// spkSleep to HIGH, mutes the output
void setup() {
// Start Serial Port
Serial.begin(115200);
// Set pinmodes
pinMode(redButton, INPUT);
pinMode(greenButton, INPUT);
pinMode(blueButton, INPUT);
pinMode(spkFault, INPUT);
pinMode(blackButton, INPUT);
pinMode(yellowButtonOne, INPUT);
pinMode(yellowButtonTwo, INPUT);
pinMode(spkShutDown, OUTPUT);
// Control Amplifier
digitalWrite(spkShutDown, LOW);
// Set microSD Card CS as OUTPUT and set HIGH
pinMode(SD_CS, OUTPUT);
digitalWrite(SD_CS, HIGH);
// Configure interups
attachInterrupt(digitalPinToInterrupt(blackButton), amplifierControlISR, RISING); // Black button
attachInterrupt(digitalPinToInterrupt(yellowButtonOne), playerControlISR, RISING); // Yellow button
attachInterrupt(digitalPinToInterrupt(yellowButtonTwo), micControlISR, RISING); // Yellow button
// Initialise I2C
if (!Wire.begin()) {
Serial.println("Error accessing I2S Bus");
while (true);
}
// Initialize SPI bus for microSD Card
SPI.begin(SPI_SCK, SPI_MISO, SPI_MOSI);
// Start microSD Card
if (!SD.begin(SD_CS)) {
Serial.println("Error accessing microSD card!");
while (true)
;
}
// start I2S in
AudioLogger::instance().begin(Serial, AudioLogger::Warning);
// setup effects
Serial.println("starting I2S...");
auto config_in = in.defaultConfig(RX_MODE);
config_in.copyFrom(info);
config_in.i2s_format = I2S_STD_FORMAT;
config_in.is_master = true;
config_in.port_no = 0;
config_in.pin_bck = I2S_BCLK_0;
config_in.pin_ws = I2S_LRC_0;
config_in.pin_data = I2S_DIN_0;
//config_in.pin_mck = I2S_MCLK_1;
config_in.fixed_mclk;
// config_in.fixed_mclk = sample_rate * 256
// config_in.pin_mck = 2
in.begin(config_in);
// Setup I2S.
//AudioLogger::instance().begin(Serial, AudioLogger::Warning);
// effects.addEffect(pitchEffect);
auto config_out = out.defaultConfig(TX_MODE);
config_out.copyFrom(info);
config_out.i2s_format = I2S_STD_FORMAT;
config_out.is_master = true;
config_out.port_no = 1;
config_out.pin_bck = I2S_BCLK_1;
config_out.pin_ws = I2S_LRC_1;
config_out.pin_data = I2S_DOUT_1;
config_out.pin_mck = I2S_MCLK_1;
config_out.fixed_mclk;
out.begin(config_out);
//effects.begin(config_out);
// setup I2S based on sampling rate provided by decoder
decoder.setNotifyAudioChange(out);
decoder.begin();
// begin mp3
mp3.begin(decoder, audioFile);
// Load initia audio file into I2S
audioFile = SD.open("/0001.wav");
delay(50);
// Read amplifier error register
tas5760lError = digitalRead(spkFault);
delay(50);
// Print initial settings
Serial.println();
Serial.print("Player control flag = ");
Serial.print(playerControlFlag);
Serial.println();
Serial.print("Mic control flag = ");
Serial.print(micControlFlag);
Serial.println();
// Scan for I2S addresses
i2sAddress();
// Display Amplifier registers
displayRegisterValues();
delay(50);
// Enable amplifier
configureDigCtrlRegisters();
configureAnalogCtrlRegisters();
digitalWrite(spkShutDown, HIGH);
startUpRegisters();
unmuteRegisters();
volumeLowSetRegister();
//volumeDefaultSetRegister();
delay(50);
displayRegisterValues();
amplifierEnabledFlag = HIGH;
amplifierEnabledFlagChanged = HIGH;
Serial.println();
Serial.print("OK to here!");
Serial.println();
//Serial.println("Free Heap Memory: " + String(ESP.getFreeHeap()) + " bytes");
//Serial.println();
delay(2000);
// Initialise WiFi ESP Now
if (esp_now_init() != ESP_OK) {
Serial.println("Error initializing ESP-NOW");
return;
}
else Serial.println("ESP initialized succesfully");
delay(2000);
// Register for a callback function that will be called when data is sent
//esp_now_register_send_cb(OnDataSent);
// Register peer.
//memcpy(peerInfo.peer_addr, broadcastAddress, 6);
//peerInfo.channel = 0;
//peerInfo.encrypt = false;
// Add peer.
//if (esp_now_add_peer(&peerInfo) != ESP_OK) {
// Serial.println("Failed to add peer");
// return;
//}
//else Serial.println("Peer added succesfully");
// Register for a callback function that will be called when data is received
//esp_now_register_recv_cb(OnDataRecv);
//delay(250);
//myData.soundClip = 0;
//Serial.print("Sound Clip: ");
//Serial.print(myData.soundClip);
//Serial.print(" : ");
//Serial.println(playTrack);
}
/*-----------------------------------------------------------------*/
void loop() {
// Enable amplifier IC
if (amplifierEnabledFlag == HIGH && amplifierEnabledFlagChanged == HIGH) {
//digitalWrite(ledGreenPin, HIGH);
amplifierEnabledFlagChanged = LOW;
Serial.println();
Serial.println("Amplifer Enabled");
digitalWrite(spkShutDown, HIGH);
startUpRegisters();
unmuteRegisters();
displayRegisterValues();
}
// Disable amplifier IC
else if (amplifierEnabledFlag == LOW && amplifierEnabledFlagChanged == HIGH) {
//digitalWrite(ledGreenPin, LOW);
amplifierEnabledFlagChanged = LOW;
Serial.println();
Serial.println("Amplifer Disabled");
muteRegisters();
shutDownRegisters();
digitalWrite(spkShutDown, LOW);
displayRegisterValues();
}
// Player enabled / disabled indication
if (playerControlFlag == HIGH && playerControlFlagChanged == HIGH) {
micControlFlag = LOW;
mic.end();
in.end();
decoder.setNotifyAudioChange(out);
decoder.begin();
mp3.begin(decoder, audioFile);
Serial.println("Player Enabled");
volumeLowSetRegister();
//volumeDefaultSetRegister();
playerControlFlagChanged = LOW;
}
else if (playerControlFlag == LOW && playerControlFlagChanged == HIGH) {
micControlFlag = LOW;
mic.end();
in.end();
decoder.end();
mp3.end();
Serial.println("Player Disabled");
playerControlFlagChanged = LOW;
}
// Mic enabled / disabled indication
if (micControlFlag == HIGH && micControlFlagChanged == HIGH) {
playerControlFlag = LOW;
decoder.end();
mp3.end();
// start I2S in
AudioLogger::instance().begin(Serial, AudioLogger::Warning);
Serial.println("starting I2S...");
auto config_in = in.defaultConfig(RX_MODE);
config_in.copyFrom(info);
config_in.i2s_format = I2S_STD_FORMAT;
config_in.is_master = true;
config_in.port_no = 0;
config_in.pin_bck = I2S_BCLK_0;
config_in.pin_ws = I2S_LRC_0;
config_in.pin_data = I2S_DIN_0;
config_in.fixed_mclk;
in.begin(config_in);
// Setup I2S out
auto config_out = out.defaultConfig(TX_MODE);
config_out.copyFrom(info);
config_out.i2s_format = I2S_STD_FORMAT;
config_out.is_master = true;
config_out.port_no = 1;
config_out.pin_bck = I2S_BCLK_1;
config_out.pin_ws = I2S_LRC_1;
config_out.pin_data = I2S_DOUT_1;
config_out.pin_mck = I2S_MCLK_1;
config_out.fixed_mclk;
out.begin(config_out);
mic.begin(out, in);
Serial.println("Mic Enabled");
volumeDefaultSetRegister();
micControlFlagChanged = LOW;
}
else if (micControlFlag == LOW && micControlFlagChanged == HIGH) {
playerControlFlag = LOW;
mic.end();
in.end();
decoder.end();
mp3.end();
Serial.println("Mic Disabled");
//volumeLowSetRegister();
volumeLowSetRegister();
micControlFlagChanged = LOW;
}
// Play chosen inputs
if (playerControlFlag == HIGH && micControlFlag == LOW) {
mp3.copy();
}
if (micControlFlag == HIGH && playerControlFlag == LOW) {
mic.copy();
}
// Read amplifier error register & error handling
tas5760lError = digitalRead(spkFault);
//if (tas5760lError == LOW) {
// digitalWrite(ledRedPin, HIGH);
// displayFaultRegister();
//}
//else digitalWrite(ledRedPin, LOW);
//if (buttonOneFlag == HIGH) {
// displayRegisterValues();
// buttonOneFlag = LOW;
//}
// Play clip
if (playTrack > 0) {
if (playTrack == 30 && longSong == HIGH) {
// Insert clip
longSong = LOW;
}
else if (playTrack == 30 && longSong == LOW) {
// Insert special clip
}
else {
// Insert clip
audioFile = SD.open("/0002.wav");
}
}
playTrack = 0;
}
/*-----------------------------------------------------------------*/