Page 1 of 3

i2s compatibility

Posted: Thu Jan 31, 2019 7:47 pm
by vitocosmic
it is posible to use i2s protocol to communicate a mic to esp32 board? i'm working with a heltec esp32 wifi lora, datasheet of esp32 shows that is posible to use i2s but in micropython there are not module for achieve this, if someone knows other way of doing this please let me know

Re: i2s compatibility

Posted: Fri Feb 01, 2019 3:39 pm
by Mike Teachman
I'm not aware of a uPy I2S module for the ESP32. For a project that requires an I2S microphone I ended up writing a uPy module that uses the I2S interface in the ESP-IDF. I'll be finishing that work in a couple of days, then submitting a pull request to the main uPy repo. A few things left to do, like rebase my github branch with uPy V1.10, test, and provide some example usage code.

If you are comfortable to make your own ESP32 build you will be able to pull in this work and have a uPy I2S module to try out.

the work-in-progress is on this github branch:
https://github.com/miketeachman/micropy ... /esp32-i2s

For I2S receive, I'm testing with the Adafruit I2S MEMS microphone breakout... the python interface looks like this

Code: Select all

from machine import I2S

audio_mic=I2S(I2S.NUM0,bck=bck_mic_pin,ws=ws_mic_pin,sdin=sdin_mic_pin,mode=I2S.MASTER_RX,
samplerate=SAMPLES_PER_SECOND, dataformat=I2S.B32,
channelformat=I2S.RIGHT_LEFT,standard=I2S.PHILIPS,
dmacount=64,dmalen=128)

samples = bytearray(SAMPLE_BLOCK_SIZE)

numread = audio_mic.readinto(samples)
I'll post again when the pull request is done

Re: i2s compatibility

Posted: Fri Feb 01, 2019 11:34 pm
by mattyt
Hey Mike, that'd be great - the lack of an I2S module is one of the large holes in the ESP32 port. I'll be sure to take a look!

Re: i2s compatibility

Posted: Sun Feb 03, 2019 11:47 pm
by vitocosmic
thanks a lot! that's the same mic I'm using. i want to introduce myself into this subject, do you know any documentation on adding modules to upy? i mean i know how to achieve this but i want to acquire a deeper knowledge to integrate other drivers in the future to the platform, i found a document made by Radomir Dopieralski and is my only source beside forums and github discussions

Re: i2s compatibility

Posted: Mon Feb 04, 2019 2:05 am
by dhylands
I put together an example over here: https://github.com/dhylands/micropython ... /c_sample3
It's a little dated (about a year old) but has most of the elements.

Re: i2s compatibility

Posted: Wed Feb 06, 2019 8:18 pm
by Mike Teachman
update: PR for I2S support is submitted:
https://github.com/micropython/micropython/pull/4471

usage guide and examples describing how to use this new I2S class:
https://github.com/miketeachman/micropy ... s-examples

It would be great if a few enthusiasts could try out this PR and report back.

feedback welcome !

Re: i2s compatibility

Posted: Wed Feb 06, 2019 8:59 pm
by OutoftheBOTS_
Lobo port has had some I2S stuff for a while. I did play with it a bit back when it was first released.

He had a couple of nice features like using the I2S to feed the DAC via DMA to pay a WAV file with a simple amp and speaker, this is the amp that I used https://www.ebay.com/sch/i.html?_from=R ... =1&_sop=15

He also had the ability to do the opposite and record to a buffer sampling from the ADC via I2S
I used https://www.ebay.com/itm/MAX9814-Electr ... 3877416550 and it worked well.

Re: i2s compatibility

Posted: Wed Feb 06, 2019 9:46 pm
by Mike Teachman
Thanks for mentioning this work and listing those devices - I'll have to order some and try them out.

The PR I submitted addresses a gap in the functionality of the LoBo port. It is missing a core I2S piece, which is about interfacing to external I2S hardware devices via the ESP32 pins, using the I2S protocol. It would be great if Loboris could integrate this PR, or some derivative, into his port. I already do this on my local LoBo build - it's a clean integration. Then, we'd have I2S protocol support on his amazing port.

The LoBo port uses some of the I2S capabilities to bring very powerful enhancements to the existing machine.ADC and machine.DAC classes. By levering the DMA capabilities of I2S, the DAC and ADC hardware on the ESP32 can "run in the background" - it's an excellent addition to the ADC and DAC classes. This work would be a welcome addition to the mainline of uPy.

Re: i2s compatibility

Posted: Fri Feb 08, 2019 4:58 pm
by Dogostyle
Mike Teachman wrote:
Wed Feb 06, 2019 8:18 pm
update: PR for I2S support is submitted:
https://github.com/micropython/micropython/pull/4471

usage guide and examples describing how to use this new I2S class:
https://github.com/miketeachman/micropy ... s-examples

It would be great if a few enthusiasts could try out this PR and report back.

feedback welcome !
I tested your SD example using the same mic, and it works perfect !!. Thanks a lot for your effort, along with @vitocosmic, we had a lot of trouble trying to make it work.
I have some questions though, why you decimate or prune your samples before saving into the SD?. And, how can I achieve full resolution (18bits) from the mic (https://cdn-shop.adafruit.com/product-f ... asheet.PDF)?

Re: i2s compatibility

Posted: Sun Feb 10, 2019 4:12 am
by Mike Teachman
thanks for trying it out. Really glad to know it works on someone else's build !

For the pruning part, I reduced the sample size to 16 bits to reduce the time to copy the samples to the SDCard (which should help to support a higher sampling rate), and to reduce the space used on the SDCard. In my application I will be continuously recording audio to SDCard for 8 hours or more.

To use 32 bit samples (to get all 18 bits of resolution), the prune() function might be changed to something like this:

Code: Select all

def prune(samples_out, samples_in):
    for i in range(SAMPLE_BLOCK_SIZE // 8):
        samples_out[4*i] = samples_in[8*i]
        samples_out[4*i + 1] = samples_in[8*i + 1]    
        samples_out[4*i + 2] = samples_in[8*i + 2]
        samples_out[4*i + 3] = samples_in[8*i + 3]    
and the definitions at the top:

Code: Select all

SDCARD_SECTOR_SIZE = 512 # bytes
SAMPLE_BLOCK_SIZE = SDCARD_SECTOR_SIZE * 2
BYTES_PER_SAMPLE = 4
SAMPLES_PER_SECOND = 16000
BITS_PER_SAMPLE = 32
That will pick out the 32bit samples from the left channel. There is likely a more efficient way to implement this operation. Perhaps an implementation based on the ustruct module? Making my python code efficient is still a work-in-progress.