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.

Committer:
Mawrk
Date:
Fri Jul 15 14:11:14 2016 +0000
Revision:
0:dcefe9e5ec82
works

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Mawrk 0:dcefe9e5ec82 1 /*
Mawrk 0:dcefe9e5ec82 2 MICROPHONE RECORDER for the DISCOVERY STM32L476 dev board
Mawrk 0:dcefe9e5ec82 3
Mawrk 0:dcefe9e5ec82 4 Records audio and sends it via UART as text-encoded samples
Mawrk 0:dcefe9e5ec82 5 sample rate: 25600 Hz
Mawrk 0:dcefe9e5ec82 6 sample format: 8bit signed (0-255)
Mawrk 0:dcefe9e5ec82 7
Mawrk 0:dcefe9e5ec82 8 can record up to 31744 samples
Mawrk 0:dcefe9e5ec82 9 press the UP and DOWN keys to set the recording size
Mawrk 0:dcefe9e5ec82 10 press RIGHT to perform recording. The result is sent via UART after it is recorded
Mawrk 0:dcefe9e5ec82 11
Mawrk 0:dcefe9e5ec82 12
Mawrk 0:dcefe9e5ec82 13 you can deode the recording into a .wav file in matlab, by doing this:
Mawrk 0:dcefe9e5ec82 14
Mawrk 0:dcefe9e5ec82 15 wavedata = wavedata - 128;
Mawrk 0:dcefe9e5ec82 16 wavedata = wavedata / 256;
Mawrk 0:dcefe9e5ec82 17 audiowrite('wave.wav', wavedata, 25600);
Mawrk 0:dcefe9e5ec82 18
Mawrk 0:dcefe9e5ec82 19
Mawrk 0:dcefe9e5ec82 20 */
Mawrk 0:dcefe9e5ec82 21
Mawrk 0:dcefe9e5ec82 22
Mawrk 0:dcefe9e5ec82 23 #include "mbed.h"
Mawrk 0:dcefe9e5ec82 24
Mawrk 0:dcefe9e5ec82 25 DigitalOut led_red(LED2);
Mawrk 0:dcefe9e5ec82 26 DigitalOut mic_clk(PE_9);
Mawrk 0:dcefe9e5ec82 27 DigitalIn mic_data(PE_7);
Mawrk 0:dcefe9e5ec82 28
Mawrk 0:dcefe9e5ec82 29 InterruptIn right(JOYSTICK_RIGHT);
Mawrk 0:dcefe9e5ec82 30 InterruptIn up(JOYSTICK_UP);
Mawrk 0:dcefe9e5ec82 31 InterruptIn down(JOYSTICK_DOWN);
Mawrk 0:dcefe9e5ec82 32
Mawrk 0:dcefe9e5ec82 33 Serial pc(USBTX, USBRX); // tx, rx
Mawrk 0:dcefe9e5ec82 34
Mawrk 0:dcefe9e5ec82 35 int recsize = 16384;
Mawrk 0:dcefe9e5ec82 36
Mawrk 0:dcefe9e5ec82 37 void record() {
Mawrk 0:dcefe9e5ec82 38
Mawrk 0:dcefe9e5ec82 39 unsigned int i;
Mawrk 0:dcefe9e5ec82 40 uint8_t j;
Mawrk 0:dcefe9e5ec82 41 uint8_t k;
Mawrk 0:dcefe9e5ec82 42
Mawrk 0:dcefe9e5ec82 43 uint8_t *readouts;
Mawrk 0:dcefe9e5ec82 44 volatile uint8_t sum;
Mawrk 0:dcefe9e5ec82 45 volatile int readout;
Mawrk 0:dcefe9e5ec82 46 uint16_t properSample;
Mawrk 0:dcefe9e5ec82 47
Mawrk 0:dcefe9e5ec82 48 uint8_t integratingBuffer[7];
Mawrk 0:dcefe9e5ec82 49 uint8_t bufferPointer = 6;
Mawrk 0:dcefe9e5ec82 50
Mawrk 0:dcefe9e5ec82 51 readouts = (uint8_t*)malloc(recsize);
Mawrk 0:dcefe9e5ec82 52 if (readouts == NULL){
Mawrk 0:dcefe9e5ec82 53 pc.printf("FAILED TO ALLOCATE MEMORY!\n\r");
Mawrk 0:dcefe9e5ec82 54 return;
Mawrk 0:dcefe9e5ec82 55 }
Mawrk 0:dcefe9e5ec82 56
Mawrk 0:dcefe9e5ec82 57 pc.printf("RECORDING!\n\r");
Mawrk 0:dcefe9e5ec82 58
Mawrk 0:dcefe9e5ec82 59 //Step 1: pre-heat the microphone with 10ms+ of stable clocks
Mawrk 0:dcefe9e5ec82 60 //otherwise the microphone returns GARBAGE (see datasheet)
Mawrk 0:dcefe9e5ec82 61 for(i=0; i<80000; i++){
Mawrk 0:dcefe9e5ec82 62 mic_clk = 0;
Mawrk 0:dcefe9e5ec82 63 readout = mic_data; //fake smapling to keep the clock rythm
Mawrk 0:dcefe9e5ec82 64 mic_clk = 1;
Mawrk 0:dcefe9e5ec82 65 }
Mawrk 0:dcefe9e5ec82 66
Mawrk 0:dcefe9e5ec82 67 //Step 2: pre-fill the cyclyc integrating buffer
Mawrk 0:dcefe9e5ec82 68 for(i=0; i<7; i++){
Mawrk 0:dcefe9e5ec82 69 sum = 0;
Mawrk 0:dcefe9e5ec82 70 for(j=0; j<32; j++){
Mawrk 0:dcefe9e5ec82 71 mic_clk = 1;
Mawrk 0:dcefe9e5ec82 72 readout = mic_data;
Mawrk 0:dcefe9e5ec82 73 mic_clk = 0;
Mawrk 0:dcefe9e5ec82 74 sum += readout;
Mawrk 0:dcefe9e5ec82 75 }
Mawrk 0:dcefe9e5ec82 76 bufferPointer = (bufferPointer+1)%7;
Mawrk 0:dcefe9e5ec82 77 integratingBuffer[bufferPointer] = sum;
Mawrk 0:dcefe9e5ec82 78 }
Mawrk 0:dcefe9e5ec82 79
Mawrk 0:dcefe9e5ec82 80 //step 3: Actual sampling
Mawrk 0:dcefe9e5ec82 81 led_red = 1;
Mawrk 0:dcefe9e5ec82 82 for(i=0; i<recsize; i++){
Mawrk 0:dcefe9e5ec82 83 //collect a 64x downsampled sample by summing the 1-bit input
Mawrk 0:dcefe9e5ec82 84 sum = 0;
Mawrk 0:dcefe9e5ec82 85 for(j=0; j<64; j++){
Mawrk 0:dcefe9e5ec82 86 mic_clk = 1;
Mawrk 0:dcefe9e5ec82 87 readout = mic_data;
Mawrk 0:dcefe9e5ec82 88 mic_clk = 0;
Mawrk 0:dcefe9e5ec82 89 sum += readout;
Mawrk 0:dcefe9e5ec82 90 }
Mawrk 0:dcefe9e5ec82 91
Mawrk 0:dcefe9e5ec82 92 //push it into the cyclic integrating buffer
Mawrk 0:dcefe9e5ec82 93 bufferPointer = (bufferPointer+1)%7;
Mawrk 0:dcefe9e5ec82 94 integratingBuffer[bufferPointer] = sum;
Mawrk 0:dcefe9e5ec82 95
Mawrk 0:dcefe9e5ec82 96 //sum the current content of the buffer to create one proper sample
Mawrk 0:dcefe9e5ec82 97 properSample = 0;
Mawrk 0:dcefe9e5ec82 98 for(k=0; k<7; k++){
Mawrk 0:dcefe9e5ec82 99 properSample += integratingBuffer[k];
Mawrk 0:dcefe9e5ec82 100 }
Mawrk 0:dcefe9e5ec82 101
Mawrk 0:dcefe9e5ec82 102 //the sample taken 3 samples ago is counted TWICE, as the middle key sample
Mawrk 0:dcefe9e5ec82 103 if(bufferPointer>=3){
Mawrk 0:dcefe9e5ec82 104 properSample+=integratingBuffer[bufferPointer-3];
Mawrk 0:dcefe9e5ec82 105 }else{
Mawrk 0:dcefe9e5ec82 106 properSample+=integratingBuffer[bufferPointer+4];
Mawrk 0:dcefe9e5ec82 107 }
Mawrk 0:dcefe9e5ec82 108
Mawrk 0:dcefe9e5ec82 109 //proper sample is now a sum of 8 numbers from the range 0-64
Mawrk 0:dcefe9e5ec82 110 //this can be up to 512, so we need to devide this by 2 to fit into 0-255
Mawrk 0:dcefe9e5ec82 111 readouts[i] = (uint8_t)(properSample>>1);
Mawrk 0:dcefe9e5ec82 112 }
Mawrk 0:dcefe9e5ec82 113 led_red = 0;
Mawrk 0:dcefe9e5ec82 114 mic_clk=1;
Mawrk 0:dcefe9e5ec82 115
Mawrk 0:dcefe9e5ec82 116 //step 4: serial print
Mawrk 0:dcefe9e5ec82 117 for(i=0; i<recsize; i++){
Mawrk 0:dcefe9e5ec82 118 pc.printf("%u\n\r", readouts[i]);
Mawrk 0:dcefe9e5ec82 119 }
Mawrk 0:dcefe9e5ec82 120
Mawrk 0:dcefe9e5ec82 121 //step 5: clean
Mawrk 0:dcefe9e5ec82 122 free(readouts);
Mawrk 0:dcefe9e5ec82 123 pc.printf("DONE!\n\r");
Mawrk 0:dcefe9e5ec82 124 }
Mawrk 0:dcefe9e5ec82 125
Mawrk 0:dcefe9e5ec82 126 void up_released() {
Mawrk 0:dcefe9e5ec82 127 recsize+=1024;
Mawrk 0:dcefe9e5ec82 128 pc.printf("recording size: %d\n\r", recsize);
Mawrk 0:dcefe9e5ec82 129 }
Mawrk 0:dcefe9e5ec82 130
Mawrk 0:dcefe9e5ec82 131
Mawrk 0:dcefe9e5ec82 132 void down_released() {
Mawrk 0:dcefe9e5ec82 133 if(recsize>1024){
Mawrk 0:dcefe9e5ec82 134 recsize-=1024;
Mawrk 0:dcefe9e5ec82 135 }
Mawrk 0:dcefe9e5ec82 136 pc.printf("recording size: %d\n\r", recsize);
Mawrk 0:dcefe9e5ec82 137 }
Mawrk 0:dcefe9e5ec82 138
Mawrk 0:dcefe9e5ec82 139 void right_released() {
Mawrk 0:dcefe9e5ec82 140 record();
Mawrk 0:dcefe9e5ec82 141 }
Mawrk 0:dcefe9e5ec82 142
Mawrk 0:dcefe9e5ec82 143 int main()
Mawrk 0:dcefe9e5ec82 144 {
Mawrk 0:dcefe9e5ec82 145 right.fall(&right_released);
Mawrk 0:dcefe9e5ec82 146 up.fall(&up_released);
Mawrk 0:dcefe9e5ec82 147 down.fall(&down_released);
Mawrk 0:dcefe9e5ec82 148
Mawrk 0:dcefe9e5ec82 149 right.mode(PullDown);
Mawrk 0:dcefe9e5ec82 150 up.mode(PullDown);
Mawrk 0:dcefe9e5ec82 151 down.mode(PullDown);
Mawrk 0:dcefe9e5ec82 152
Mawrk 0:dcefe9e5ec82 153
Mawrk 0:dcefe9e5ec82 154 pc.baud(115200);
Mawrk 0:dcefe9e5ec82 155 pc.printf("booting\n\r");
Mawrk 0:dcefe9e5ec82 156
Mawrk 0:dcefe9e5ec82 157
Mawrk 0:dcefe9e5ec82 158 while(1){
Mawrk 0:dcefe9e5ec82 159 ;
Mawrk 0:dcefe9e5ec82 160 }
Mawrk 0:dcefe9e5ec82 161
Mawrk 0:dcefe9e5ec82 162 }