Bug - I2S communication disrupted by arbitrary function call following I2C initialization.
Discussed in https://github.com/orgs/micropython/discussions/14009
<div type='discussions-op-text'>
<sup>Originally posted by ajbradburn March 3, 2024</sup>
Bug - I2S communication disrupted by arbitrary function call following I2C initialization.
I have discovered that I2S communication is somehow disrupted by initializing I2C, and then calling any function.
A work-around is to do something as simple a call ‘print’ after the arbitrary function call.
Here is an example of a script that demonstrates the bug:
from machine import I2C, Pin, I2S
def emptyFunction():
return
i2c = I2C(0, scl=3, sda=8)
ser = emptyFunction()
print('Safety Print') # CRITICALLY IMPORTANT. This print statement enables I2S to work properly. Some combination of the i2c assignment, and then a function call afterwards makes the I2S sound terrible. Simply printing something resolves the issue… Comment this print call to experience bug.
bclk = Pin(5) # Clock Pin
lrc = Pin(6) # Channel Select Pin
din = Pin(4) # Data Pin
audio_out = I2S(
1,
sck=bclk, ws=lrc, sd=din,
mode=I2S.TX,
bits=16,
format=I2S.MONO,
rate=44100,
ibuf=1024
)
def playAudio(file):
print(file)
if True:
wav_file = file
wav = open(wav_file,'rb')
pos = wav.seek(44)
wav_samples = bytearray(1024)
wav_samples_mv = memoryview(wav_samples)
audio_out.shift
while True:
num_read = wav.readinto(wav_samples_mv)
if num_read == 0:
break
num_written = 0
# Increase the volume.
#I2S.shift(buf=wav_samples_mv, bits=16, shift=1)
while num_written < num_read:
num_written += audio_out.write(wav_samples_mv[num_written:num_read])
wav.close()
playAudio('snake.wav')
audio_out.deinit()
I have tested this with blocking, and non blocking I2S implementation with the same result.
I discovered this while trying to operate a PCA9685 and a Max98357 on an ESP32-S3-WROOM-1 using Micropython v1.22.2 (2024-02-22).
Files can be found here:
https://github.com/ajbradburn/ESP32-PuppetRemote/blob/main/code/sound_test.py
https://github.com/ajbradburn/ESP32-PuppetRemote/blob/main/code/sound_test2.py
https://github.com/ajbradburn/ESP32-PuppetRemote/blob/main/code/snake.wav</div>
i2s bug?
Port, board and/or hardware
esp32
MicroPython version
E (151878) i2s_common: i2s_alloc_dma_desc(417): allocate DMA buffer failed
E (151878) i2s_std: i2s_std_set_slot(103): allocate memory for dma descriptor failed
E (151878) i2s_std: i2s_channel_init_std_mode(217): initialize channel failed while setting slot
E (151888) i2s_common: i2s_channel_enable(966): the channel has already enabled or not initialized
Reproduction
def _play_i2s_dac(self, name):
if self.is_play:
return False
self.is_play = True
if isinstance(name, str):
name = self.buildpath(name)
with wav_open(name) as f:
total = f.getnframes()
# print('total: ', total)
print('rate: ', f.getframerate())
try:
i2s = I2S(
0,
# sck=Pin(14), ws=Pin(13), sd=Pin(12),
sck=Pin(CONF['i2sBCLK']),
ws=Pin(CONF['i2sLRC']),
sd=Pin(CONF['i2sDIN']),
mode=I2S.TX,
bits=16,
format=I2S.MONO,
rate=f.getframerate(),
ibuf=1024
)
except Exception as e:
print('''
E (35978) i2s_common: i2s_alloc_dma_desc(417): allocate DMA buffer failed
E (35978) i2s_std: i2s_std_set_slot(103): allocate memory for dma descriptor failed
E (35988) i2s_std: i2s_channel_init_std_mode(217): initialize channel failed while setting slot
E (35998) i2s_common: i2s_channel_enable(966): the channel has already enabled or not initialized
?''')
print(e)
self.is_play = False
return False
while 1:
read_size = min(total, self.buffer_size)
tmp = f.readframes(read_size)
tmp = bytearray(tmp)
I2S.shift(buf=tmp, bits=16, shift=self.dB)
i2s.write(tmp)
total -= read_size
if total <= 0:
break
i2s.deinit()
self.is_play = False
return True
Expected behaviour
No response
Observed behaviour
E (151878) i2s_common: i2s_alloc_dma_desc(417): allocate DMA buffer failed
E (151878) i2s_std: i2s_std_set_slot(103): allocate memory for dma descriptor failed
E (151878) i2s_std: i2s_channel_init_std_mode(217): initialize channel failed while setting slot
E (151888) i2s_common: i2s_channel_enable(966): the channel has already enabled or not initialized
Additional Information
No, I've provided everything above.
Code of Conduct
Yes, I agree