Skip to content

Instantly share code, notes, and snippets.

@mongonta0716
Created February 4, 2022 15:21
Show Gist options
  • Save mongonta0716/0227dc91827998c5be2bde73a535c59d to your computer and use it in GitHub Desktop.
Save mongonta0716/0227dc91827998c5be2bde73a535c59d to your computer and use it in GitHub Desktop.
M5Core2のPort.AにPDMUnitを繋いで、スピーカーとマイクを同時に使えるようにするサンプル。
// The source of the following link has been modified
// https://github.com/m5stack/M5-ProductExampleCodes/tree/master/Unit/PDM
#include <M5Core2.h>
#include <driver/i2s.h>
#include "fft.h"
#define PIN_CLK 33
#define PIN_DATA 32
#define MODE_MIC 0
#define CONFIG_I2S_BCK_PIN 12 //定义I2S相关端口
#define CONFIG_I2S_LRCK_PIN 0
#define CONFIG_I2S_DATA_PIN 2
#define CONFIG_I2S_DATA_IN_PIN 34
#define Speak_I2S_NUMBER I2S_NUM_1 //定义扬声器端口
TFT_eSprite DisFFTbuff = TFT_eSprite(&M5.Lcd);
static QueueHandle_t fftvalueQueue = nullptr;
static QueueHandle_t i2sstateQueue = nullptr;
void header(const char *string, uint16_t color)
{
M5.Lcd.fillScreen(color);
M5.Lcd.setTextSize(1);
M5.Lcd.setTextColor(WHITE, BLACK);
M5.Lcd.fillRect(0, 0, 320, 30, BLACK);
M5.Lcd.setTextDatum(TC_DATUM);
M5.Lcd.drawString(string, 160, 3, 4);
}
typedef struct
{
uint8_t state;
void* audioPtr;
uint32_t audioSize;
}i2sQueueMsg_t;
void InitI2SPDMUnit()
{
i2s_driver_uninstall(I2S_NUM_0);
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_PDM),
.sample_rate = 44100,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, // is fixed at 12bit, stereo, MSB
.channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT,
.communication_format = I2S_COMM_FORMAT_I2S,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 8,
.dma_buf_len = 512,
};
i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);
i2s_pin_config_t pin_config;
pin_config.bck_io_num = I2S_PIN_NO_CHANGE;
pin_config.ws_io_num = PIN_CLK;
pin_config.data_out_num = I2S_PIN_NO_CHANGE;
pin_config.data_in_num = PIN_DATA;
i2s_set_pin(I2S_NUM_0, &pin_config);
i2s_set_clk(I2S_NUM_0, 44100, I2S_BITS_PER_SAMPLE_16BIT, I2S_CHANNEL_MONO);
}
void InitI2SSpeaker(){ //Init I2S. 初始化I2S
esp_err_t err = ESP_OK;
i2s_driver_uninstall(Speak_I2S_NUMBER); // Uninstall the I2S driver. 卸载I2S驱动
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX),
.sample_rate = 44100, // Set the I2S sampling rate. 设置I2S采样率
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, // Fixed 12-bit stereo MSB. 固定为12位立体声MSB
.channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT, // Set the channel format. 设置频道格式
.communication_format = I2S_COMM_FORMAT_I2S, // Set the format of the communication. 设置通讯格式
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // Set the interrupt flag. 设置中断的标志
.dma_buf_count = 8, //DMA buffer count. DMA缓冲区计数
.dma_buf_len = 512, //DMA buffer length. DMA缓冲区长度
.use_apll = false, //I2S clock setup. I2S时钟设置
.tx_desc_auto_clear = true // Enables auto-cleanup descriptors for understreams. 开启欠流自动清除描述符
};
// Install and drive I2S. 安装并驱动I2S
err += i2s_driver_install(Speak_I2S_NUMBER, &i2s_config, 0, NULL);
i2s_pin_config_t tx_pin_config;
tx_pin_config.bck_io_num = CONFIG_I2S_BCK_PIN; // Link the BCK to the CONFIG_I2S_BCK_PIN pin. 将BCK链接至CONFIG_I2S_BCK_PIN引脚
tx_pin_config.ws_io_num = CONFIG_I2S_LRCK_PIN; // ...
tx_pin_config.data_out_num = CONFIG_I2S_DATA_PIN; // ...
tx_pin_config.data_in_num = CONFIG_I2S_DATA_IN_PIN; // ...
err += i2s_set_pin(Speak_I2S_NUMBER, &tx_pin_config); // Set the I2S pin number. 设置I2S引脚编号
err += i2s_set_clk(Speak_I2S_NUMBER, 44100, I2S_BITS_PER_SAMPLE_16BIT, I2S_CHANNEL_MONO); // Set the clock and bitwidth used by I2S Rx and Tx. 设置I2S RX、Tx使用的时钟和位宽
return;
}
static void i2sMicroFFTtask(void *arg)
{
uint8_t FFTDataBuff[128];
uint8_t FFTValueBuff[24];
uint8_t* microRawData = (uint8_t*)calloc(2048,sizeof(uint8_t));
size_t bytesread;
int16_t* buffptr;
double data = 0;
float adc_data;
uint16_t ydata;
uint32_t subData;
uint8_t state = MODE_MIC;
i2sQueueMsg_t QueueMsg;
while(1)
{
if( xQueueReceive(i2sstateQueue,&QueueMsg,(TickType_t)0) == pdTRUE)
{
//Serial.println("Queue Now");
if( QueueMsg.state == MODE_MIC )
{
InitI2SPDMUnit();
state = MODE_MIC;
}
}
else if( state == MODE_MIC )
{
fft_config_t *real_fft_plan = fft_init(1024, FFT_REAL, FFT_FORWARD, NULL, NULL);
i2s_read(I2S_NUM_0, (char *)microRawData, 2048, &bytesread, (100 / portTICK_RATE_MS));
i2s_write(I2S_NUM_1, (char *)microRawData, 2048, &bytesread, (100 / portTICK_RATE_MS));
buffptr = ( int16_t*)microRawData;
for ( int count_n = 0; count_n < real_fft_plan->size; count_n++)
{
adc_data = (float)map(buffptr[count_n], INT16_MIN, INT16_MAX, -2000, 2000);
real_fft_plan->input[count_n] = adc_data;
}
fft_execute(real_fft_plan);
for ( int count_n = 1; count_n < real_fft_plan->size / 4; count_n++)
{
data = sqrt(real_fft_plan->output[2 * count_n] * real_fft_plan->output[2 * count_n] + real_fft_plan->output[2 * count_n + 1] * real_fft_plan->output[2 * count_n + 1]);
if ((count_n - 1) < 128)
{
data = ( data > 2000 ) ? 2000 : data;
ydata = map(data, 0, 2000, 0, 255);
FFTDataBuff[128 - count_n] = ydata;
}
}
for( int count = 0; count < 24; count++ )
{
subData = 0;
for( int count_i = 0; count_i < 5; count_i++ )
{
subData += FFTDataBuff[count * 5 + count_i ];
}
subData /= 5;
FFTValueBuff[count] = map(subData,0,255,0,8);
}
xQueueSend( fftvalueQueue, (void * )&FFTValueBuff, 0 );
fft_destroy(real_fft_plan);
//Serial.printf("mmp\r\n");
}
else
{
delay(10);
}
}
}
void microPhoneSetup()
{
fftvalueQueue = xQueueCreate(5, 24 * sizeof(uint8_t));
if( fftvalueQueue == 0 )
{
return;
}
i2sstateQueue = xQueueCreate(5, sizeof(i2sQueueMsg_t));
if( i2sstateQueue == 0 )
{
return;
}
InitI2SPDMUnit();
xTaskCreatePinnedToCore(i2sMicroFFTtask, "microPhoneTask", 4096, NULL, 3, NULL, 0);
DisFFTbuff.createSprite(320,54);
}
void MicroPhoneFFT()
{
uint8_t FFTValueBuff[24];
xQueueReceive( fftvalueQueue, (void * )&FFTValueBuff, portMAX_DELAY );
DisFFTbuff.fillRect(0,0,320,54,DisFFTbuff.color565(0x00,0x00,0x00));
uint32_t colorY = DisFFTbuff.color565(0xff,0x9c,0x00);
uint32_t colorG = DisFFTbuff.color565(0x66,0xff,0x00);
uint32_t colorRect;
for( int x = 0; x < 24; x++ )
{
for( int y = 0; y < 9; y++ )
{
if( y < FFTValueBuff[23-x] )
{
colorRect = colorY;
}
else if( y == FFTValueBuff[23-x] )
{
colorRect = colorG;
}
else
{
continue;
}
DisFFTbuff.fillRect(x*12,54-y*6 - 5,5,5,colorRect);
}
}
DisFFTbuff.pushSprite(20, 120);
}
void setup() {
M5.begin(true, true, true, false);
M5.Axp.SetSpkEnable(true);
InitI2SSpeaker();
header("PDM Unit", BLACK);
microPhoneSetup();
}
void loop() {
MicroPhoneFFT();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment