Created
February 4, 2022 15:21
-
-
Save mongonta0716/0227dc91827998c5be2bde73a535c59d to your computer and use it in GitHub Desktop.
M5Core2のPort.AにPDMUnitを繋いで、スピーカーとマイクを同時に使えるようにするサンプル。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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