I need help creating a custom design to read audio signals from an I2S MEMS sensor by Adafruit (Adafruit I2S MEMS Microphone Breakout - SPH0645LM4H : ID 3421 : $6.95 : Adafruit Industries, Unique & fun DIY electronics and kits). If anyone can provide support, I will definitely make a tutorial, as usual, outlining the entire process
Here’s my current design:
design_I2S_receiver.pdf (74.8 KB)
I’m using a CoraZ7 board (though I think that’s not crucial information).
The PYNQ-side code is as follows:
from pynq import Overlay, allocate import numpy as np ol = Overlay("design_wrapper.bit") adc_ctrl = ol.i2s_receiver_0 adc_dma = ol.axi_dma_1 N=256 * 1000 audio_input_buffer = allocate(shape=(N,), dtype=np.uint32) adc_dma.recvchannel._align = 4 # stop I2S controller adc_ctrl.write(0x08, 0) # redirect all channels to the channel 0-1 CH_SEL = 1 adc_ctrl.write(0x30, CH_SEL ) adc_ctrl.write(0x34, CH_SEL ) adc_ctrl.write(0x38, CH_SEL ) adc_ctrl.write(0x3C, CH_SEL ) # I2S Timing Control (0x20) # This register is used to set the divider value to generate the SCLK. Typically SCLK = 2*24*Fs, where 24 is the I2S data width (this value can also be 16) and Fs is the audio sampling rate. # 200Mhz / 2 * 16 * 16000 = DIVIDER * 2 ---> DIVIDER = ( 200 mHz / 512 kHz ) / 2 ----> DIVIDER = 50 adc_ctrl.write(0x20, 50) # start I2S controller adc_ctrl.write(0x08, 1) adc_dma.recvchannel.transfer(audio_input_buffer) adc_dma.recvchannel.wait()
When I check the clock pins using an oscilloscope, I can see that they generate the correct clock signal. However, on the PYNQ side, when I try to read from the DMA, I don’t get the expected results. Specifically, I read all zeros or “random” values. I followed the IP documentation and tried to extract the bits from the DMA, but I’m still getting the same results. I also added this code:
audio = np.copy(audio_input_buffer) f_audio = np.zeros(N, dtype=np.uint16) f_audio2 = np.zeros(N, dtype=np.int32) def extract_number(num, start_bit, end_bit): mask = (1 << (end_bit - start_bit + 1)) - 1 extracted_number = (num >> start_bit) & mask return extracted_number for i in range(N): f_audio[i] = extract_number(audio[i], 12, 27) # convert audio word according to Adafruit documentation for i in range(N): if f_audio[i] == 0 or f_audio[i] == -1: f_audio2[i] = 0 continue __a = f_audio[i] __a >>= 14 f_audio2[i] = __a
Does anyone have experience with this I2S IP and/or Adafruit MEMS? Have I missed something in my setup?
Also, I see that PYNQ has custom IPs for audio controlling (Audio codec controller & Audio direct), is it possible to use them for the same purposes? If yes, can you provide an example?