|
7 | 7 | * 获取更多资料请访问:https://docs.m5stack.com/zh_CN/unit/pdm
|
8 | 8 | *
|
9 | 9 | * describe: pdm. 麦克风
|
10 |
| -* date:2021/8/27 |
| 10 | +* date:2022/2/22 |
11 | 11 | *******************************************************************************
|
12 |
| - Please connect to Port A,Read the microphone data of the PDM Unit and display the audio frequency spectrum. |
13 |
| - 请连接端口A,读取PDM Unit的麦克风数据,显示音频频谱。 |
14 |
| - Note: Remove the M5GO base when using this example, otherwise it will not work properly |
15 |
| - 注意:在使用本示例时删除M5GO base,否则它将无法正常工作 |
| 12 | + Please connect to Port A,Read the microphone data of the PDM Unit and display |
| 13 | +the audio frequency spectrum. 请连接端口A,读取PDM |
| 14 | +Unit的麦克风数据,显示音频频谱。 Note: Remove the M5GO base when using this |
| 15 | +example, otherwise it will not work properly 注意:在使用本示例时删除M5GO |
| 16 | +base,否则它将无法正常工作 |
16 | 17 | */
|
17 | 18 |
|
18 | 19 | #include <M5Stack.h>
|
19 | 20 | #include <driver/i2s.h>
|
| 21 | + |
20 | 22 | #include "fft.h"
|
21 | 23 |
|
22 | 24 | #define PIN_CLK 22
|
23 | 25 | #define PIN_DATA 21
|
24 | 26 |
|
25 | 27 | #define MODE_MIC 0
|
26 | 28 |
|
27 |
| -TFT_eSprite DisFFTbuff = TFT_eSprite(&M5.Lcd); |
| 29 | +TFT_eSprite DisFFTbuff = TFT_eSprite(&M5.Lcd); |
28 | 30 | static QueueHandle_t fftvalueQueue = nullptr;
|
29 | 31 | static QueueHandle_t i2sstateQueue = nullptr;
|
30 | 32 |
|
31 |
| -typedef struct{ |
32 |
| - uint8_t state; |
33 |
| - void* audioPtr; |
34 |
| - uint32_t audioSize; |
35 |
| -}i2sQueueMsg_t; |
36 |
| - |
37 |
| -bool InitI2SSpakerOrMic(int mode){ |
38 |
| - i2s_config_t i2s_config = { |
39 |
| - .mode = (i2s_mode_t)(I2S_MODE_MASTER), // Set the I2S operating mode. 设置I2S工作模式 |
40 |
| - .sample_rate = 44100, // Set the I2S sampling rate. 设置I2S采样率 |
41 |
| - .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, // Fixed 12-bit stereo MSB. 固定为12位立体声MSB |
42 |
| - .channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT, // Set the channel format. 设置频道格式 |
43 |
| - .communication_format = I2S_COMM_FORMAT_I2S, // Set the format of the communication. 设置通讯格式 |
44 |
| - .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // Set the interrupt flag. 设置中断的标志 |
45 |
| - .dma_buf_count = 2, //DMA buffer count. DMA缓冲区计数 |
46 |
| - .dma_buf_len = 128, //DMA buffer length. DMA缓冲区长度 |
47 |
| - }; |
48 |
| - if (mode == MODE_MIC) |
49 |
| - { |
50 |
| - i2s_config.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_PDM); |
51 |
| - } |
52 |
| - |
53 |
| - i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL); // Install and drive I2S. 安装并驱动I2S |
54 |
| - i2s_pin_config_t pin_config; |
55 |
| - pin_config.bck_io_num = I2S_PIN_NO_CHANGE; |
56 |
| - pin_config.ws_io_num = PIN_CLK; |
57 |
| - pin_config.data_out_num = I2S_PIN_NO_CHANGE; |
58 |
| - pin_config.data_in_num = PIN_DATA; |
59 |
| - |
60 |
| - i2s_set_pin(I2S_NUM_0, &pin_config); |
61 |
| - i2s_set_clk(I2S_NUM_0, 44100, I2S_BITS_PER_SAMPLE_16BIT, I2S_CHANNEL_MONO); |
62 |
| - |
63 |
| - return true; |
64 |
| -} |
65 |
| - |
66 |
| -static void i2sMicroFFTtask(void *arg) |
67 |
| -{ |
68 |
| - uint8_t FFTDataBuff[128]; |
69 |
| - uint8_t FFTValueBuff[24]; |
70 |
| - uint8_t* microRawData = (uint8_t*)calloc(2048,sizeof(uint8_t)); |
71 |
| - size_t bytesread; |
72 |
| - int16_t* buffptr; |
73 |
| - double data = 0; |
74 |
| - float adc_data; |
75 |
| - uint16_t ydata; |
76 |
| - uint32_t subData; |
77 |
| - |
78 |
| - uint8_t state = MODE_MIC; |
79 |
| - i2sQueueMsg_t QueueMsg; |
80 |
| - while(1) |
81 |
| - { |
82 |
| - if( xQueueReceive(i2sstateQueue,&QueueMsg,(TickType_t)0) == pdTRUE) |
83 |
| - { |
84 |
| - //Serial.println("Queue Now"); |
85 |
| - if( QueueMsg.state == MODE_MIC ) |
86 |
| - { |
87 |
| - InitI2SSpakerOrMic(MODE_MIC); |
88 |
| - state = MODE_MIC; |
89 |
| - } |
| 33 | +typedef struct { |
| 34 | + uint8_t state; |
| 35 | + void* audioPtr; |
| 36 | + uint32_t audioSize; |
| 37 | +} i2sQueueMsg_t; |
| 38 | + |
| 39 | +bool InitI2SSpakerOrMic(int mode) { |
| 40 | + i2s_config_t i2s_config = { |
| 41 | + .mode = (i2s_mode_t)(I2S_MODE_MASTER), // Set the I2S operating mode. |
| 42 | + // 设置I2S工作模式 |
| 43 | + .sample_rate = 44100, // Set the I2S sampling rate. 设置I2S采样率 |
| 44 | + .bits_per_sample = |
| 45 | + I2S_BITS_PER_SAMPLE_16BIT, // Fixed 12-bit stereo MSB. |
| 46 | + // 固定为12位立体声MSB |
| 47 | + .channel_format = |
| 48 | + I2S_CHANNEL_FMT_ONLY_RIGHT, // Set the channel format. 设置频道格式 |
| 49 | + .communication_format = |
| 50 | + I2S_COMM_FORMAT_STAND_I2S, // Set the format of the communication. |
| 51 | + // 设置通讯格式 |
| 52 | + .intr_alloc_flags = |
| 53 | + ESP_INTR_FLAG_LEVEL1, // Set the interrupt flag. 设置中断的标志 |
| 54 | + .dma_buf_count = 2, // DMA buffer count. DMA缓冲区计数 |
| 55 | + .dma_buf_len = 128, // DMA buffer length. DMA缓冲区长度 |
| 56 | + }; |
| 57 | + if (mode == MODE_MIC) { |
| 58 | + i2s_config.mode = |
| 59 | + (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_PDM); |
90 | 60 | }
|
91 |
| - else if( state == MODE_MIC ) |
92 |
| - { |
93 |
| - fft_config_t *real_fft_plan = fft_init(1024, FFT_REAL, FFT_FORWARD, NULL, NULL); |
94 |
| - i2s_read(I2S_NUM_0, (char *)microRawData, 2048, &bytesread, (100 / portTICK_RATE_MS)); |
95 |
| - buffptr = ( int16_t*)microRawData; |
96 |
| - |
97 |
| - for ( int count_n = 0; count_n < real_fft_plan->size; count_n++) |
98 |
| - { |
99 |
| - adc_data = (float)map(buffptr[count_n], INT16_MIN, INT16_MAX, -2000, 2000); |
100 |
| - real_fft_plan->input[count_n] = adc_data; |
101 |
| - } |
102 |
| - fft_execute(real_fft_plan); |
103 |
| - |
104 |
| - for ( int count_n = 1; count_n < real_fft_plan->size / 4; count_n++) |
105 |
| - { |
106 |
| - 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]); |
107 |
| - if ((count_n - 1) < 128) |
108 |
| - { |
109 |
| - data = ( data > 2000 ) ? 2000 : data; |
110 |
| - ydata = map(data, 0, 2000, 0, 255); |
111 |
| - FFTDataBuff[128 - count_n] = ydata; |
112 |
| - } |
113 |
| - } |
114 | 61 |
|
115 |
| - for( int count = 0; count < 24; count++ ) |
116 |
| - { |
117 |
| - subData = 0; |
118 |
| - for( int count_i = 0; count_i < 5; count_i++ ) |
119 |
| - { |
120 |
| - subData += FFTDataBuff[count * 5 + count_i ]; |
121 |
| - } |
122 |
| - subData /= 5; |
123 |
| - FFTValueBuff[count] = map(subData,0,255,0,8); |
| 62 | + i2s_driver_install(I2S_NUM_0, &i2s_config, 0, |
| 63 | + NULL); // Install and drive I2S. 安装并驱动I2S |
| 64 | + i2s_pin_config_t pin_config; |
| 65 | +#if (ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(4, 3, 0)) |
| 66 | + pin_config.mck_io_num = I2S_PIN_NO_CHANGE; |
| 67 | +#endif |
| 68 | + pin_config.bck_io_num = I2S_PIN_NO_CHANGE; |
| 69 | + pin_config.ws_io_num = PIN_CLK; |
| 70 | + pin_config.data_out_num = I2S_PIN_NO_CHANGE; |
| 71 | + pin_config.data_in_num = PIN_DATA; |
| 72 | + |
| 73 | + i2s_set_pin(I2S_NUM_0, &pin_config); |
| 74 | + i2s_set_clk(I2S_NUM_0, 44100, I2S_BITS_PER_SAMPLE_16BIT, I2S_CHANNEL_MONO); |
| 75 | + |
| 76 | + return true; |
| 77 | +} |
| 78 | + |
| 79 | +static void i2sMicroFFTtask(void* arg) { |
| 80 | + uint8_t FFTDataBuff[128]; |
| 81 | + uint8_t FFTValueBuff[24]; |
| 82 | + uint8_t* microRawData = (uint8_t*)calloc(2048, sizeof(uint8_t)); |
| 83 | + size_t bytesread; |
| 84 | + int16_t* buffptr; |
| 85 | + double data = 0; |
| 86 | + float adc_data; |
| 87 | + uint16_t ydata; |
| 88 | + uint32_t subData; |
| 89 | + |
| 90 | + uint8_t state = MODE_MIC; |
| 91 | + i2sQueueMsg_t QueueMsg; |
| 92 | + while (1) { |
| 93 | + if (xQueueReceive(i2sstateQueue, &QueueMsg, (TickType_t)0) == pdTRUE) { |
| 94 | + // Serial.println("Queue Now"); |
| 95 | + if (QueueMsg.state == MODE_MIC) { |
| 96 | + InitI2SSpakerOrMic(MODE_MIC); |
| 97 | + state = MODE_MIC; |
| 98 | + } |
| 99 | + } else if (state == MODE_MIC) { |
| 100 | + fft_config_t* real_fft_plan = |
| 101 | + fft_init(1024, FFT_REAL, FFT_FORWARD, NULL, NULL); |
| 102 | + i2s_read(I2S_NUM_0, (char*)microRawData, 2048, &bytesread, |
| 103 | + (100 / portTICK_RATE_MS)); |
| 104 | + buffptr = (int16_t*)microRawData; |
| 105 | + |
| 106 | + for (int count_n = 0; count_n < real_fft_plan->size; count_n++) { |
| 107 | + adc_data = (float)map(buffptr[count_n], INT16_MIN, INT16_MAX, |
| 108 | + -2000, 2000); |
| 109 | + real_fft_plan->input[count_n] = adc_data; |
| 110 | + } |
| 111 | + fft_execute(real_fft_plan); |
| 112 | + |
| 113 | + for (int count_n = 1; count_n < real_fft_plan->size / 4; |
| 114 | + count_n++) { |
| 115 | + data = sqrt(real_fft_plan->output[2 * count_n] * |
| 116 | + real_fft_plan->output[2 * count_n] + |
| 117 | + real_fft_plan->output[2 * count_n + 1] * |
| 118 | + real_fft_plan->output[2 * count_n + 1]); |
| 119 | + if ((count_n - 1) < 128) { |
| 120 | + data = (data > 2000) ? 2000 : data; |
| 121 | + ydata = map(data, 0, 2000, 0, 255); |
| 122 | + FFTDataBuff[128 - count_n] = ydata; |
| 123 | + } |
| 124 | + } |
| 125 | + |
| 126 | + for (int count = 0; count < 24; count++) { |
| 127 | + subData = 0; |
| 128 | + for (int count_i = 0; count_i < 5; count_i++) { |
| 129 | + subData += FFTDataBuff[count * 5 + count_i]; |
| 130 | + } |
| 131 | + subData /= 5; |
| 132 | + FFTValueBuff[count] = map(subData, 0, 255, 0, 8); |
| 133 | + } |
| 134 | + xQueueSend(fftvalueQueue, (void*)&FFTValueBuff, 0); |
| 135 | + fft_destroy(real_fft_plan); |
| 136 | + } else { |
| 137 | + delay(10); |
124 | 138 | }
|
125 |
| - xQueueSend( fftvalueQueue, (void * )&FFTValueBuff, 0 ); |
126 |
| - fft_destroy(real_fft_plan); |
127 |
| - } |
128 |
| - else |
129 |
| - { |
130 |
| - delay(10); |
131 | 139 | }
|
132 |
| - } |
133 | 140 | }
|
134 | 141 |
|
135 |
| -void microPhoneSetup() |
136 |
| -{ |
137 |
| - fftvalueQueue = xQueueCreate(5, 24 * sizeof(uint8_t)); |
138 |
| - if( fftvalueQueue == 0 ) |
139 |
| - { |
140 |
| - return; |
141 |
| - } |
| 142 | +void microPhoneSetup() { |
| 143 | + fftvalueQueue = xQueueCreate(5, 24 * sizeof(uint8_t)); |
| 144 | + if (fftvalueQueue == 0) { |
| 145 | + return; |
| 146 | + } |
142 | 147 |
|
143 |
| - i2sstateQueue = xQueueCreate(5, sizeof(i2sQueueMsg_t)); |
144 |
| - if( i2sstateQueue == 0 ) |
145 |
| - { |
146 |
| - return; |
147 |
| - } |
| 148 | + i2sstateQueue = xQueueCreate(5, sizeof(i2sQueueMsg_t)); |
| 149 | + if (i2sstateQueue == 0) { |
| 150 | + return; |
| 151 | + } |
148 | 152 |
|
149 |
| - InitI2SSpakerOrMic(MODE_MIC); |
150 |
| - xTaskCreatePinnedToCore(i2sMicroFFTtask, "microPhoneTask", 4096, NULL, 3, NULL, 0); |
| 153 | + InitI2SSpakerOrMic(MODE_MIC); |
| 154 | + xTaskCreatePinnedToCore(i2sMicroFFTtask, "microPhoneTask", 4096, NULL, 3, |
| 155 | + NULL, 0); |
151 | 156 |
|
152 |
| - DisFFTbuff.createSprite(320,54); |
| 157 | + DisFFTbuff.createSprite(320, 54); |
153 | 158 | }
|
154 | 159 |
|
155 |
| -void MicroPhoneFFT() |
156 |
| -{ |
157 |
| - uint8_t FFTValueBuff[24]; |
158 |
| - xQueueReceive( fftvalueQueue, (void * )&FFTValueBuff, portMAX_DELAY ); |
159 |
| - DisFFTbuff.fillRect(0,0,320,54,DisFFTbuff.color565(0x00,0x00,0x00)); |
160 |
| - uint32_t colorY = DisFFTbuff.color565(0xff,0x9c,0x00); |
161 |
| - uint32_t colorG = DisFFTbuff.color565(0x66,0xff,0x00); |
162 |
| - uint32_t colorRect; |
163 |
| - for( int x = 0; x < 24; x++ ) |
164 |
| - { |
165 |
| - for( int y = 0; y < 9; y++ ) |
166 |
| - { |
167 |
| - if( y < FFTValueBuff[23-x] ){ |
168 |
| - colorRect = colorY; |
169 |
| - }else if( y == FFTValueBuff[23-x] ){ |
170 |
| - colorRect = colorG; |
171 |
| - }else{ |
172 |
| - continue; |
173 |
| - } |
174 |
| - DisFFTbuff.fillRect(x*12,54-y*6 - 5,5,5,colorRect); |
| 160 | +void MicroPhoneFFT() { |
| 161 | + uint8_t FFTValueBuff[24]; |
| 162 | + xQueueReceive(fftvalueQueue, (void*)&FFTValueBuff, portMAX_DELAY); |
| 163 | + DisFFTbuff.fillRect(0, 0, 320, 54, DisFFTbuff.color565(0x00, 0x00, 0x00)); |
| 164 | + uint32_t colorY = DisFFTbuff.color565(0xff, 0x9c, 0x00); |
| 165 | + uint32_t colorG = DisFFTbuff.color565(0x66, 0xff, 0x00); |
| 166 | + uint32_t colorRect; |
| 167 | + for (int x = 0; x < 24; x++) { |
| 168 | + for (int y = 0; y < 9; y++) { |
| 169 | + if (y < FFTValueBuff[23 - x]) { |
| 170 | + colorRect = colorY; |
| 171 | + } else if (y == FFTValueBuff[23 - x]) { |
| 172 | + colorRect = colorG; |
| 173 | + } else { |
| 174 | + continue; |
| 175 | + } |
| 176 | + DisFFTbuff.fillRect(x * 12, 54 - y * 6 - 5, 5, 5, colorRect); |
| 177 | + } |
175 | 178 | }
|
176 |
| - } |
177 |
| - DisFFTbuff.pushSprite(20, 120); |
| 179 | + DisFFTbuff.pushSprite(20, 120); |
178 | 180 | }
|
179 | 181 |
|
180 |
| - |
181 | 182 | void setup() {
|
182 |
| - M5.begin(true, true, true, true); |
183 |
| - M5.Lcd.fillScreen(BLACK); |
184 |
| - M5.Lcd.setTextSize(1); |
185 |
| - M5.Lcd.setTextColor(WHITE, BLACK); |
186 |
| - M5.Lcd.fillRect(0, 0, 320, 30, BLACK); |
187 |
| - M5.Lcd.setTextDatum(TC_DATUM); |
188 |
| - M5.Lcd.drawString("PDM Unit", 160, 3, 4); |
189 |
| - microPhoneSetup(); |
| 183 | + M5.begin(true, true, true, true); |
| 184 | + M5.Lcd.fillScreen(BLACK); |
| 185 | + M5.Lcd.setTextSize(1); |
| 186 | + M5.Lcd.setTextColor(WHITE, BLACK); |
| 187 | + M5.Lcd.fillRect(0, 0, 320, 30, BLACK); |
| 188 | + M5.Lcd.setTextDatum(TC_DATUM); |
| 189 | + M5.Lcd.drawString("PDM Unit", 160, 3, 4); |
| 190 | + microPhoneSetup(); |
190 | 191 | }
|
191 | 192 |
|
192 |
| -void loop() { |
193 |
| - MicroPhoneFFT(); |
194 |
| -} |
| 193 | +void loop() { MicroPhoneFFT(); } |
0 commit comments