diff --git a/README.md b/README.md index 424d5a8..3dc07d7 100644 --- a/README.md +++ b/README.md @@ -14,8 +14,8 @@ ![WiringMax9814](doc/wiring_MAX9814.jpg) The SD card wiring is the same as above (for my sd card adapter, pullup resistors weren't necessary) -MAX9814 Wiring: -MAX9814 | ESP32 +MAX9814 Wiring: +MAX9814 | ESP32 GND - GND Vdd - 3V3 Out - VP (GPIO36) diff --git a/esp32_I2S_recorder_SPIFFS/I2S.cpp b/esp32_I2S_recorder_SPIFFS/I2S.cpp new file mode 100644 index 0000000..9bf07ad --- /dev/null +++ b/esp32_I2S_recorder_SPIFFS/I2S.cpp @@ -0,0 +1,44 @@ +#include "I2S.h" + +void I2S_Init(i2s_mode_t MODE, i2s_bits_per_sample_t BPS) { + i2s_config_t i2s_config = { + .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN | I2S_MODE_ADC_BUILT_IN), + .sample_rate = SAMPLE_RATE, + .bits_per_sample = BPS, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB), + .intr_alloc_flags = 0, + .dma_buf_count = 16, + .dma_buf_len = 60 + }; + if (MODE == I2S_MODE_RX || MODE == I2S_MODE_TX) { + i2s_pin_config_t pin_config; + Serial.println("using i2c_RX_TX"); + pin_config.bck_io_num = PIN_I2S_BCLK; + pin_config.ws_io_num = PIN_I2S_LRC; + if (MODE == I2S_MODE_RX) { + pin_config.data_out_num = I2S_PIN_NO_CHANGE; + pin_config.data_in_num = PIN_I2S_DIN; + } else if (MODE == I2S_MODE_TX) { + pin_config.data_out_num = PIN_I2S_DOUT; + pin_config.data_in_num = I2S_PIN_NO_CHANGE; + } + + i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL); + i2s_set_pin(I2S_NUM_0, &pin_config); + i2s_set_clk(I2S_NUM_0, SAMPLE_RATE, BPS, I2S_CHANNEL_STEREO); + } else if (MODE == I2S_MODE_DAC_BUILT_IN || MODE == I2S_MODE_ADC_BUILT_IN) { + Serial.println("using ADC_builtin"); + i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL); + // GPIO36, VP + i2s_set_adc_mode(ADC_UNIT_1, ADC1_CHANNEL_0); + } +} + +int I2S_Read(char *data, int numData) { + return i2s_read_bytes(I2S_NUM_0, (char *)data, numData, portMAX_DELAY); +} + +void I2S_Write(char *data, int numData) { + i2s_write_bytes(I2S_NUM_0, (const char *)data, numData, portMAX_DELAY); +} diff --git a/esp32_I2S_recorder_SPIFFS/I2S.h b/esp32_I2S_recorder_SPIFFS/I2S.h new file mode 100644 index 0000000..b22720f --- /dev/null +++ b/esp32_I2S_recorder_SPIFFS/I2S.h @@ -0,0 +1,38 @@ +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "driver/i2s.h" +#include "esp_system.h" +#define SAMPLE_RATE (44100) +#define PIN_I2S_BCLK 26 +#define PIN_I2S_LRC 22 +#define PIN_I2S_DIN 34 +#define PIN_I2S_DOUT 25 + +// This I2S specification : +// - LRC high is channel 2 (right). +// - LRC signal transitions once each word. +// - DATA is valid on the CLOCK rising edge. +// - Data bits are MSB first. +// - DATA bits are left-aligned with respect to LRC edge. +// - DATA bits are right-shifted by one with respect to LRC edges. +// It's valid for ADMP441 (microphone) and MAX98357A (speaker). +// It's not valid for SPH0645LM4H(microphone) and WM8960(microphon/speaker). +// +// - 44100Hz +// - stereo + +/// @parameter MODE : I2S_MODE_RX or I2S_MODE_TX +/// @parameter BPS : I2S_BITS_PER_SAMPLE_16BIT or I2S_BITS_PER_SAMPLE_32BIT +void I2S_Init(i2s_mode_t MODE, i2s_bits_per_sample_t BPS); + +/// I2S_Read() for I2S_MODE_RX +/// @parameter data: pointer to buffer +/// @parameter numData: buffer size +/// @return Number of bytes read +int I2S_Read(char* data, int numData); + +/// I2S_Write() for I2S_MODE_TX +/// @param data: pointer to buffer +/// @param numData: buffer size +void I2S_Write(char* data, int numData); diff --git a/esp32_I2S_recorder_SPIFFS/Wav.cpp b/esp32_I2S_recorder_SPIFFS/Wav.cpp new file mode 100644 index 0000000..7d63603 --- /dev/null +++ b/esp32_I2S_recorder_SPIFFS/Wav.cpp @@ -0,0 +1,50 @@ +#include "Wav.h" + +void CreateWavHeader(byte* header, int waveDataSize){ + header[0] = 'R'; + header[1] = 'I'; + header[2] = 'F'; + header[3] = 'F'; + unsigned int fileSizeMinus8 = waveDataSize + 44 - 8; + header[4] = (byte)(fileSizeMinus8 & 0xFF); + header[5] = (byte)((fileSizeMinus8 >> 8) & 0xFF); + header[6] = (byte)((fileSizeMinus8 >> 16) & 0xFF); + header[7] = (byte)((fileSizeMinus8 >> 24) & 0xFF); + header[8] = 'W'; + header[9] = 'A'; + header[10] = 'V'; + header[11] = 'E'; + header[12] = 'f'; + header[13] = 'm'; + header[14] = 't'; + header[15] = ' '; + header[16] = 0x10; // linear PCM + header[17] = 0x00; + header[18] = 0x00; + header[19] = 0x00; + header[20] = 0x01; // linear PCM + header[21] = 0x00; + header[22] = 0x01; // monoral + header[23] = 0x00; + header[24] = 0x44; // sampling rate 44100 + header[25] = 0xAC; + header[26] = 0x00; + header[27] = 0x00; + header[28] = 0x88; // Byte/sec = 44100x2x1 = 88200 + header[29] = 0x58; + header[30] = 0x01; + header[31] = 0x00; + header[32] = 0x02; // 16bit monoral + header[33] = 0x00; + header[34] = 0x10; // 16bit + header[35] = 0x00; + header[36] = 'd'; + header[37] = 'a'; + header[38] = 't'; + header[39] = 'a'; + header[40] = (byte)(waveDataSize & 0xFF); + header[41] = (byte)((waveDataSize >> 8) & 0xFF); + header[42] = (byte)((waveDataSize >> 16) & 0xFF); + header[43] = (byte)((waveDataSize >> 24) & 0xFF); +} + diff --git a/esp32_I2S_recorder_SPIFFS/Wav.h b/esp32_I2S_recorder_SPIFFS/Wav.h new file mode 100644 index 0000000..579893a --- /dev/null +++ b/esp32_I2S_recorder_SPIFFS/Wav.h @@ -0,0 +1,4 @@ +#include + +// 16bit, monoral, 44100Hz, linear PCM +void CreateWavHeader(byte* header, int waveDataSize); // size of header is 44 diff --git a/esp32_I2S_recorder_SPIFFS/esp32_I2S_recorder_SPIFFS.ino b/esp32_I2S_recorder_SPIFFS/esp32_I2S_recorder_SPIFFS.ino new file mode 100644 index 0000000..15fa20a --- /dev/null +++ b/esp32_I2S_recorder_SPIFFS/esp32_I2S_recorder_SPIFFS.ino @@ -0,0 +1,87 @@ +#include "Arduino.h" +#include +#include "Wav.h" +#include "I2S.h" +#include "SPIFFS.h" +#define FORMAT_SPIFFS_IF_FAILED true + +//comment the first line and uncomment the second if you use MAX9814 +//#define I2S_MODE I2S_MODE_RX +#define I2S_MODE I2S_MODE_ADC_BUILT_IN + +const int record_time = 5; // second +const char filename[] = "/sound.wav"; + +const int headerSize = 44; +const int waveDataSize = record_time * 88000; +const int numCommunicationData = 8000; +const int numPartWavData = numCommunicationData/4; +byte header[headerSize]; +char communicationData[numCommunicationData]; +char partWavData[numPartWavData]; +File file; + +//https://github.com/espressif/arduino-esp32/blob/master/libraries/SPIFFS/examples/SPIFFS_Test/SPIFFS_Test.ino +void listDir(fs::FS& fs, const char* dirname, uint8_t levels) { + // Serial.printf("Listing directory: %s\r\n", dirname); + + File root = fs.open(dirname); + if (!root) { + // Serial.println("- failed to open directory"); + return; + } + if (!root.isDirectory()) { + // Serial.println(" - not a directory"); + return; + } + + File file = root.openNextFile(); + while (file) { + if (file.isDirectory()) { + Serial.print(" DIR : "); + Serial.println(file.name()); + if (levels) { + listDir(fs, file.name(), levels - 1); + } + } else { + Serial.print(" FILE: "); + Serial.print(file.name()); + Serial.print("\tSIZE: "); + Serial.println(file.size()); + } + file = root.openNextFile(); + } +} + +void setup() { + Serial.begin(115200); + if (!SPIFFS.begin(FORMAT_SPIFFS_IF_FAILED)) { + Serial.println("SPIFFS Mount Failed"); + return; + } + // https://gitter.im/espressif/arduino-esp32?at=5dffa2c7260751301cf1455b + // do NOT remove the following line SPIFFS.format(); + CreateWavHeader(header, waveDataSize); + SPIFFS.remove(filename); + file = SPIFFS.open(filename, FILE_WRITE); + if (!file) return; + Serial.println("start recording"); + file.write(header, headerSize); + I2S_Init(I2S_MODE, I2S_BITS_PER_SAMPLE_32BIT); + for (int j = 0; j < waveDataSize/numPartWavData; ++j) { + I2S_Read(communicationData, numCommunicationData); + for (int i = 0; i < numCommunicationData/8; ++i) { + partWavData[2*i] = communicationData[8*i + 2]; + partWavData[2*i + 1] = communicationData[8*i + 3]; + } + file.write((const byte*)partWavData, numPartWavData); + } + file.close(); + Serial.println("finish recording"); + Serial.println("test SPIFFS recording file"); + listDir(SPIFFS, "/", 0); + +} + +void loop() { +}