mems microphone test on the STM32L4 DISCOVERY dev board using bit banging. very primitive and not recommended, but works.
Dependencies: BSP_DISCO_L476VG mbed
a shitty MICROPHONE RECORDER for the DISCOVERY STM32L476 dev board
Records audio and sends it via UART (to the PC) as text-encoded samples sample rate: 25600 Hz (ish) sample format: 8 bit unsigned (0-255) uart baud rate: 115,200
press the UP and DOWN keys to set the recording size press RIGHT to perform recording. The result is sent via UART after it is recorded can record up to 31744 samples, doesn't want to allocate more memory (I don't know why though)
you can encode the recording from the UART text dump into a .wav file in Matlab, by doing this:
wavedata = wavedata - 128; wavedata = wavedata / 256; audiowrite('wave.wav', wavedata, 25600);
where "wavedata" is a vector containing just the NUMBERS from the imported UART log
PRINCIPAL OF OPERATION:
The microphone is read by bit-banning it's clock pin (PE_9) and reading it's data pin (PE_7). The hardware PDM decoder should have been used for this, but was not. The hardware SPI or I2C would also be a good choice, but there happens to be no such hardware functionality on that specific set of pins.
The microphone returns PDM encoded audio data. This is a 1-bit format. The data is more likely to be a "1" the higher the current readout from the microphone. In practice this means that if we sample this fast enough and then low-pass it in a 8 or 16 bit format, we should get an audio waveform.
Method of filtering
The MCU collects 64 1-bit samples and adds them. This returns a value between 0 and 64 (a 6 bit sample). The 1-bit sampling is at a clock of about 1.64Mhz. Therefore, the 6bit samples are produced at 1,700,000 / 64 = 25,600 Hz
Theese 6bit samples are stored in a 7-slot cyclic buffer. The content of this buffer is summed whenever a new 6bit sample is added. The "middle" sample is counted twice.
This produces a 9-bit sample, which is halved to produce the final 8bit sample that is stored in RAM
After the recording is finished, the content of the RAM is sent over UART in text form.
This is a silly implementation of the microphone, but you may find some of it useful.
main.cpp
- Committer:
- Mawrk
- Date:
- 2016-07-15
- Revision:
- 0:dcefe9e5ec82
File content as of revision 0:dcefe9e5ec82:
/* MICROPHONE RECORDER for the DISCOVERY STM32L476 dev board Records audio and sends it via UART as text-encoded samples sample rate: 25600 Hz sample format: 8bit signed (0-255) can record up to 31744 samples press the UP and DOWN keys to set the recording size press RIGHT to perform recording. The result is sent via UART after it is recorded you can deode the recording into a .wav file in matlab, by doing this: wavedata = wavedata - 128; wavedata = wavedata / 256; audiowrite('wave.wav', wavedata, 25600); */ #include "mbed.h" DigitalOut led_red(LED2); DigitalOut mic_clk(PE_9); DigitalIn mic_data(PE_7); InterruptIn right(JOYSTICK_RIGHT); InterruptIn up(JOYSTICK_UP); InterruptIn down(JOYSTICK_DOWN); Serial pc(USBTX, USBRX); // tx, rx int recsize = 16384; void record() { unsigned int i; uint8_t j; uint8_t k; uint8_t *readouts; volatile uint8_t sum; volatile int readout; uint16_t properSample; uint8_t integratingBuffer[7]; uint8_t bufferPointer = 6; readouts = (uint8_t*)malloc(recsize); if (readouts == NULL){ pc.printf("FAILED TO ALLOCATE MEMORY!\n\r"); return; } pc.printf("RECORDING!\n\r"); //Step 1: pre-heat the microphone with 10ms+ of stable clocks //otherwise the microphone returns GARBAGE (see datasheet) for(i=0; i<80000; i++){ mic_clk = 0; readout = mic_data; //fake smapling to keep the clock rythm mic_clk = 1; } //Step 2: pre-fill the cyclyc integrating buffer for(i=0; i<7; i++){ sum = 0; for(j=0; j<32; j++){ mic_clk = 1; readout = mic_data; mic_clk = 0; sum += readout; } bufferPointer = (bufferPointer+1)%7; integratingBuffer[bufferPointer] = sum; } //step 3: Actual sampling led_red = 1; for(i=0; i<recsize; i++){ //collect a 64x downsampled sample by summing the 1-bit input sum = 0; for(j=0; j<64; j++){ mic_clk = 1; readout = mic_data; mic_clk = 0; sum += readout; } //push it into the cyclic integrating buffer bufferPointer = (bufferPointer+1)%7; integratingBuffer[bufferPointer] = sum; //sum the current content of the buffer to create one proper sample properSample = 0; for(k=0; k<7; k++){ properSample += integratingBuffer[k]; } //the sample taken 3 samples ago is counted TWICE, as the middle key sample if(bufferPointer>=3){ properSample+=integratingBuffer[bufferPointer-3]; }else{ properSample+=integratingBuffer[bufferPointer+4]; } //proper sample is now a sum of 8 numbers from the range 0-64 //this can be up to 512, so we need to devide this by 2 to fit into 0-255 readouts[i] = (uint8_t)(properSample>>1); } led_red = 0; mic_clk=1; //step 4: serial print for(i=0; i<recsize; i++){ pc.printf("%u\n\r", readouts[i]); } //step 5: clean free(readouts); pc.printf("DONE!\n\r"); } void up_released() { recsize+=1024; pc.printf("recording size: %d\n\r", recsize); } void down_released() { if(recsize>1024){ recsize-=1024; } pc.printf("recording size: %d\n\r", recsize); } void right_released() { record(); } int main() { right.fall(&right_released); up.fall(&up_released); down.fall(&down_released); right.mode(PullDown); up.mode(PullDown); down.mode(PullDown); pc.baud(115200); pc.printf("booting\n\r"); while(1){ ; } }