Hello,
As Pyboard lacks the parallel interface, I'd like to use GPI bit-bang mode to read the 16-bit register value stored in external FPGA.
Following steps need to done in sequence.
1.react to external I/O interrupt.
2.bit-bang sequential read on 16 GPI pins.
3.convert 16 single bit into two byte integer.
4.compare the integer with a predefined constant.
5.toggle an output pin based on comparison result.
I don't know how fast the whole process could be done?
Any chance this could be done within 100us?
Thanks in advance.
How fast can 16 input pins be read in sequence?
Re: How fast can 16 input pins be read in sequence?
You should be able to do it in C in 100 usec, not sure about python.
You would be better off to use SPI and send the data serially.
You would be better off to use SPI and send the data serially.
Re: How fast can 16 input pins be read in sequence?
I experimented with timer callback at 10Khz (= 100 us), but I'm not sure how much I/O you can put in it...
Re: How fast can 16 input pins be read in sequence?
You can definitely run a callback at 10kHz. To read 16 pins at once, quickly, the best thing to do is read the GPIO input-data-register directly using the stm module. Eg:
Since pins X1-X8 map directly to PA0-PA7 it's easy to do this for 8 bits. For 16 bits at once you'll need to look at the pyboard pinout to find 8 other pins that you can use that are on a single port (probably port B). Then you can do 2 reads (one from port A, one from port B) then a few bit manipulations to construct the 16 bit value.
You can put @micropython.native before the callback function to make it run about 2 times faster, which might help in your case.
Code: Select all
import pyb, stm
# callback to read pins X1-X8 at once, and store into the variable xvalue
xvalue = 0
def read_cb(tim):
global xvalue
xvalue = stm.mem32[stm.GPIOA + stm.GPIO_IDR] & 0xff # read pins X1-X8 directly
# init pins X1-X8 to input
for pin in range(1, 9):
pyb.Pin('X%d' % i, pyb.Pin.IN)
# start the timer at 10kHz doing the read
tim = pyb.Timer(1, freq=10000, callback=read_cb)
You can put @micropython.native before the callback function to make it run about 2 times faster, which might help in your case.
Re: How fast can 16 input pins be read in sequence?
Just did a small test: reading 8 bit samples into an array runs at 47 Khz. A bit slow for a logic analyzer...
Maybe a small assembler loop could bring this to 10 or 20 MHz?
Maybe a small assembler loop could bring this to 10 or 20 MHz?
Code: Select all
N=1000.0
a=array.array('B')
start = pyb.micros()
for i in range(N):
a.append(stm.mem32[stm.GPIOA + stm.GPIO_IDR])
dt = pyb.micros() - start
Re: How fast can 16 input pins be read in sequence?
For logic analyzer type functionality, I would code something up that uses timed DMA (off the top of my head - I haven't actually tried this).
Any SW solution is going to have jitter. The DMA solution will have none.
Any SW solution is going to have jitter. The DMA solution will have none.
Re: How fast can 16 input pins be read in sequence?
Using native Python code I get 110kHz, and assembler gives 12.9MHz:
If you disable interrupts during the burst read then it'll be very stable (ie no jitter). But note that you can't time the function when interrupts are disabled because the systick won't tick
To disable in asm use cpsid(i) at the start of the function and to enable use cpsie(i) at the end.
Code: Select all
import pyb, stm
@micropython.native
def burst_read_native(buf):
for i in range(len(buf)):
buf[i] = stm.mem32[stm.GPIOA + stm.GPIO_IDR]
@micropython.asm_thumb
def burst_read_asm(r0, r1):
movwt(r2, stm.GPIOA + stm.GPIO_IDR) # r2 points to GPIOA.IDR
label(LOOP)
ldr(r3, [r2, 0]) # r3 = GPIOA value
strb(r3, [r0, 0]) # store r3 into bytearray
add(r0, 1) # increase bytearray pointer
sub(r1, 1) # decrease length counter
bne(LOOP) # keep going while length non-zero
a = bytearray(20000)
start = pyb.micros()
burst_read_native(a)
dt = pyb.elapsed_micros(start)
print('native reads per second:', len(a) / dt * 1e6)
start = pyb.micros()
burst_read_asm(a, len(a))
dt = pyb.elapsed_micros(start)
print('asm reads per second:', len(a) / dt * 1e6)
To disable in asm use cpsid(i) at the start of the function and to enable use cpsie(i) at the end.