Description
Summary: I have been trying to playback music using Micropython but buffering results in choppy playback. Playback 'seems' to be about half the expected speed (Kim Wild singing Cambodia has a deep voice, LOL)
Note: Using Circuitpython (developed from Micropython?) using the same hardware and SD card plays music perfectly. So I decided to investigate.
Hardware: Cytron Maker Pi Pico pcb (includes SDCard), Waveshare I2S audio HAT, Sandisk Ultra 16Gb sd card , Pico 2W/Pico Software: Pico 2: MicroPython v1.25.0-preview.393.gf1018ee5c on 2025-03-17; Raspberry Pi Pico 2 W with RP2350 Pico: MicroPython v1.24.1 on 2024-11-29; Raspberry Pi Pico with RP2040 I have tried as far back as MicroPython v1.16 on 2021-06-18; Raspberry Pi Pico with RP2040 - the timing results are very similar but there's no I2S so I can't even try playing music.
The following program ,that I wrote, opens a music WAV file and reads a number of 512 byte blocks from it, timing as it goes.
# SDCardSpeed.py import sdcard, os import time from machine import Pin,SPI print("machine freq",machine.freq()) ##### SD Card setup ############ # SPI Pins are as per Cytron Maker Pi Pico pcb # spi=SPI(1,sck=Pin(10),mosi=Pin(11),miso=Pin(12)) cs= Pin(15,Pin.OUT) sd = sdcard.SDCard(spi,cs) os.mount(sd, '/sd') #print(os.listdir('/sd')) try: wav_samples_mv = memoryview(bytearray(512)) with open("/sd/Cambodia.wav","rb") as wav: for count in range(4): start=time.ticks_us() num_read=wav.readinto(wav_samples_mv) print("File Read took ",time.ticks_diff(time.ticks_us(),start)) except Exception as e: print(f"EXCEPTION {e}") spi.deinit()
In sdcard.py readinto() I wrapped the spi write_readinto() call to time the SPI transfer like this:-
start=time.ticks_us() self.spi.write_readinto(mv, buf) print(f"sdcard readinto took {time.ticks_diff(time.ticks_us(),start)}")
After running SDCardSpeed.py with the default baudrate I got this output:-
machine freq 150000000 sdcard __init__ baudrate=1320000 sdcard readinto took 1537 sdcard readinto took 3898 sdcard readinto took 3882 sdcard readinto took 3883 sdcard readinto took 3888 sdcard readinto took 3882 sdcard readinto took 3892 File Read took 7915 sdcard readinto took 3893 File Read took 6882 sdcard readinto took 3892 File Read took 6879 sdcard readinto took 3892 File Read took 6906
It shows that the file reading, by the OS, is close to twice the time taken to read a 512 byte block from the card. But it gets worse...
Increasing the SD card baudrate to 20000000 by changing the sdcard instantiation with :-
sd = sdcard.SDCard(spi,cs,baudrate=20_000_000)
the SPI write_readinto() call took ~450us (great) BUT the file read took ~3900us. That's nearly 10x the time taken to read the card sectors.
machine freq 150000000 sdcard __init__ baudrate=20000000 sdcard readinto took 1538 sdcard readinto took 453 sdcard readinto took 441 sdcard readinto took 438 sdcard readinto took 438 sdcard readinto took 435 sdcard readinto took 444 File Read took 3905 sdcard readinto took 443 File Read took 3852 sdcard readinto took 441 File Read took 3845 sdcard readinto took 444 File Read took 3906
Therefore I conclude that slow SDcard handling on a Pico/Pico2 is NOT in sdcard.py but in the filesystem file handling. Or am I wrong?
This is a shame - my hobby project was going to involve sound recording and playback using an I2S microphone.
Who else needs to know this info?
Can anyone verify my results because right now I cant use micropython for this on Pico and Ciruitpython doesn't support I2S audio in (at this time)
Thanks