Read a binary file with a clock

The official PYBD running MicroPython, and its accessories.
Target audience: Users with a PYBD
Post Reply
fredb
Posts: 7
Joined: Mon Apr 27, 2020 2:30 pm

Read a binary file with a clock

Post by fredb » Fri May 01, 2020 12:20 pm

Hi, everybody,

I start in this forum with a problem, but I would have preferred to come up with a solution...
I spent a whole week looking for a solution before posting the following :

I have a project to read the bytes of a binary file and present them on a port (port A) of Pyboard_D_SF6W.
I have to do this every 100µs and read a datafile in binary mode.
At first, i want to measure the reading time of one byte of the file on an oscilloscope, so i wrote this code :

Code: Select all

from pyb import Pin, Timer

#----------
#  INIT
#----------
strobe = Pin(Pin.cpu.A0, Pin.OUT_PP)
strobe.low()

# Timer 10KHz, period=100µs
flag=0
def tim1_isr(timer):
    global flag
    flag=1

tim1=Timer(1, freq=10000)
tim1.callback(tim1_isr)

i=300000  # File of 30 sec (300 Kb)

#----------------
# MAIN
#----------------
fi = open("/flash/data.bin", "rb")
print("Start")
while i>0:
    if flag==1:
        strobe.high()
        octet = fi.read(1)  # read next byte
        strobe.low()
        i-=1
        flag=0

tim1.callback(None)
fi.close()

print("Complete")

#---- END OF SRC ----------------------------
I measured the time of the strobe signal staying at a high level: 17µs every 100µs, I thought it was good for the next development but when I analyzed the whole reading, I found a glitch in the curve of the oscilloscope.

About every second, the strobe signal stays at a high level for 230µs and it was no good for me...

I tried this code without reading a file, and the problem doesn't appear. So it looks like it comes from reading the file.
It looks like a pause created by reading a block of data or resetting a buffer. Do you think this problem is solvable?

Thank you for your help.
Last edited by fredb on Wed May 27, 2020 12:57 pm, edited 1 time in total.

User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: Read a bynary file with a clock

Post by pythoncoder » Fri May 01, 2020 6:10 pm

The .read() method is a blocking method. It usually returns fast, but every time a sector is read it can block for a long time: I have observed 4ms but this will depend on the storage medium (Flash, SD card or other). File I/O is not fast. Options are to buffer data in RAM or, if the data is constant, it can be stored in Flash as a frozen bytes instance.
Peter Hinch
Index to my micropython libraries.

OutoftheBOTS_
Posts: 847
Joined: Mon Nov 20, 2017 10:18 am

Re: Read a bynary file with a clock

Post by OutoftheBOTS_ » Fri May 01, 2020 9:49 pm

Why do you want to read a byte from a file during this timed loop??

User avatar
Roberthh
Posts: 3667
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: Read a bynary file with a clock

Post by Roberthh » Sat May 02, 2020 6:11 am

Can you pre-buffer the content of the file? What is the size of the file?

fredb
Posts: 7
Joined: Mon Apr 27, 2020 2:30 pm

Re: Read a bynary file with a clock

Post by fredb » Sat May 02, 2020 2:00 pm

Thank you for your comments.
I also noticed a latency of 3.8ms every 1.2 seconds when playing my file.
Finally, I will test a solution with a 16MB external flash memory accessible by SPI (S25FL128S).
The size of the file I need to read is 10MB maximum, so I will read it from the sd card and copy it to the SPI flash. Then I read the SPI flash memory at a speed of 10000 bytes per second. I hope there will be no latency when the memory changes sectors.
I'm playing with the limits of MicroPython but it's interesting...

fredb
Posts: 7
Joined: Mon Apr 27, 2020 2:30 pm

Re: Read a bynary file with a clock

Post by fredb » Fri May 08, 2020 12:10 pm

Some news : it works !
First, the 10MB binary file is read and bytes are copied to the S25FL128S flash memory by page of 512 bytes in a single command for each page. This copy takes about 16 seconds.
The next step is the reading of the flash memory. It takes 76µs for each byte.
There is no latency when the flash changes sectors of 256 kB.
It should be noted that I had to run the SPI used to program the flash memory at its maximum clock speed: 18MHz.

Jurjen
Posts: 5
Joined: Sun Apr 19, 2020 10:54 am

Re: Read a bynary file with a clock

Post by Jurjen » Fri May 08, 2020 4:42 pm

Hi, would it be possible for you to publish the code? Thanks!

fredb
Posts: 7
Joined: Mon Apr 27, 2020 2:30 pm

Re: Read a binary file with a clock

Post by fredb » Wed May 27, 2020 1:32 pm

Here is the source code to read memory à 10KHz. I can't publish the entire source code because it doesn't belong to me.

Code: Select all

'''
Read Flash memory (S25FL128S) at 10KHz with external interrupt on PB1 (external clock)
The memory already contains data
'''

from pyb import Pin, SPI
import machine


#----- SPI to read S25FL128S
spi = SPI(2, SPI.MASTER, baudrate=18000000, polarity=0, phase=0, bits=8, firstbit=SPI.MSB)
print(spi)
cs = Pin(Pin.cpu.B12, Pin.OUT_PP) # C4
cs.high()

#----- Resets the chip
rst = Pin(Pin.cpu.C5, Pin.OUT_PP) # A10
rst.high()
rst.low()
rst.high()

#----- External clock Interrupt 10kHz -------------
clkflag=0
ocxo = Pin(Pin.cpu.B1, Pin.IN, Pin.PULL_UP)

def clk_isr(param):
    global clkflag
    clkflag=1

#----- Strobe line to validate the data put on PORTA
strobe = Pin(Pin.cpu.B0, Pin.OUT_PP)
strobe.low()

# PA0..PA7 bits
machine.mem16[stm.GPIOA+stm.GPIO_MODER]=0x5555  # PA0..PA7 in output (0b01) 
machine.mem16[stm.GPIOA+stm.GPIO_OTYPER]=0x0000  # PA0..PA7 in Push-Pull (0b0) 
machine.mem16[stm.GPIOA+stm.GPIO_OSPEEDR]=0xFFFF  # PA0..PA7 in high speed (100MHz)
machine.mem8[stm.GPIOA+stm.GPIO_ODR]=0x00 # PA0..PA7 to 0

#------ S25FL128S command codes
RDID = 0x9F
RES = 0xAB
RDSR1 = 0x05
READ = 0x03
PP = 0x02
WREN = 0x06
WRDI = 0x04


#--- First byte reading
cmd = bytearray(4)
rec = bytearray(1)
cmd[0] = READ
cmd[1] = 0x00
cmd[2] = 0x00
cmd[3] = 0x00
cs.low()
spi.send(cmd)
spi.readinto(rec)
cs.high()

#----- Variables init
mem_addr = 0
mem_size = 10485760 

#----- Enable clock interrupt
ocxo.irq(trigger=Pin.IRQ_FALLING, handler=clk_isr)


#----- Main loop
print("Start")
while mem_addr<mem_size:
    if clkflag==1:
        machine.mem8[stm.GPIOA+stm.GPIO_ODR]=rec[0]  # Write data on PortA
        strobe.high()  # Validate data
        strobe.low()
        #  Increments the address in the memory command
        cmd[3] += 1
        if cmd[3]==0:
            cmd[2] += 1
            if cmd[2]==0:
                cmd[1] += 1
        
        mem_addr += 1  #  increments the address counter
        
        # Memory reading operation on SPI
        cs.low()
        spi.send(cmd)
        spi.readinto(rec)
        cs.high()
 
        clkflag=0  # Interrupt flag reset

#----- Disable clock interrupt
ocxo.irq(handler=None)
print("Stop")

Post Reply