I2S Receive custom design

Hi everyone,

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 :blush:

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?

Thanks!

1 Like