I have a successfully working MDIO PIO interface (in MicroPython), based on oscilloscope waveform.
But it creates some questions, such as:
1. Use two PIOs in order to split the number of instructions (as total of 32 for one PIO, for all 4 SM per PIO):
I have a clock generator SM and a SM to wait for 32 clock cycles (to make sure, each transaction has 32bit clocks before data frame). I was thinking to move this SM code to another PIO (to gain more space for instructions, some SM code is independent of the PIO).
BTW: if you select the sm_id as 4 in MicroPython, it should go to the next PIO1 (sm_id 0..3 = PIO0 SM, sm_id 4..7 = PIO1 SM).
And it seems to do so: now I have not the OOMEM error anymore when moving code to another PIO. But moving SM code to another PIO does not work (in a simple way).
It is NOT possible to use IRQ signals between PIO0 and PIO1. Just a GPIO might work. IRQ signals are NOT shared between different PIOs (just inside the 4 SM of the same PIO).
So, running my clock generator (and/or my "wait for 32 clocks" SM) on a different PIO (e.g. PIO1) where the main SM code is on PIO0 - does not work (because "IRQs are not shared").
2. Can PIO0 generate a GPIO signal (OUT) which is an input GPIO (IN) on PIO1?
Due to fact that IRQs do not work across different PIOs - the only way is to use a "shared" GPIO. So, if my clock generator would provide a clock on GPIO0, using PIO1, and I want to WAIT for this same GPIO, as input on PIO0 - would it work?
It means:
Is it possible to generate GPIO0 as OUT on PIO0 and PIO1 uses the same GPIO0 as in IN (for WAIT)?
(or: "which config would win?", if PIO1 configures GPIO0 as IN, but PIO0 wants to use as out - it would fail)
Remarks:
To have means to synchronize PIO0 and PIO1 SMs which each other would be cool.
Here the code for my MDIO implementation:
But it creates some questions, such as:
1. Use two PIOs in order to split the number of instructions (as total of 32 for one PIO, for all 4 SM per PIO):
I have a clock generator SM and a SM to wait for 32 clock cycles (to make sure, each transaction has 32bit clocks before data frame). I was thinking to move this SM code to another PIO (to gain more space for instructions, some SM code is independent of the PIO).
BTW: if you select the sm_id as 4 in MicroPython, it should go to the next PIO1 (sm_id 0..3 = PIO0 SM, sm_id 4..7 = PIO1 SM).
And it seems to do so: now I have not the OOMEM error anymore when moving code to another PIO. But moving SM code to another PIO does not work (in a simple way).
It is NOT possible to use IRQ signals between PIO0 and PIO1. Just a GPIO might work. IRQ signals are NOT shared between different PIOs (just inside the 4 SM of the same PIO).
So, running my clock generator (and/or my "wait for 32 clocks" SM) on a different PIO (e.g. PIO1) where the main SM code is on PIO0 - does not work (because "IRQs are not shared").
2. Can PIO0 generate a GPIO signal (OUT) which is an input GPIO (IN) on PIO1?
Due to fact that IRQs do not work across different PIOs - the only way is to use a "shared" GPIO. So, if my clock generator would provide a clock on GPIO0, using PIO1, and I want to WAIT for this same GPIO, as input on PIO0 - would it work?
It means:
Is it possible to generate GPIO0 as OUT on PIO0 and PIO1 uses the same GPIO0 as in IN (for WAIT)?
(or: "which config would win?", if PIO1 configures GPIO0 as IN, but PIO0 wants to use as out - it would fail)
Remarks:
- the max. 32 instructions (per PIO) is very at the lowest limit. It would be cool to have a bit more space for instructions (in future versions of the RP2350)
- that the IRQ does not work across several PIOs is a "missing feature" (for my feeling). It would be cool to be able to move some instructions to another PIO (e.g. my clock generator) and to synchronize both PIOs (via IRQ)
- not sure if possible to use a "shared" GPIO: one PIO generates as OUT and other PIO can use WAIT on the same GPIO (but as IN).
If so: it would solve "my" problem (PIO1 generates clock, PIO0 uses wait for CLK edges, even without IRQ). Just not sure if possible to have a "shared" GPIO signal this way.
To have means to synchronize PIO0 and PIO1 SMs which each other would be cool.
Here the code for my MDIO implementation:
Code:
import timeimport rp2from machine import Pinimport time#clock generator - free running clock, INTs for rising (read) and falling edge (write)@rp2.asm_pio(sideset_init=rp2.PIO.OUT_LOW)def clk(): #this results in 25MHz clock #trim this so that other SM changes bits on falling edge when sending #it divides freq by 6 wrap_target() irq(4)[1].side(1)#1 irq(clear, 4)[0]#2 irq(5)[1].side(0)#3 irq(clear, 5)[0]#4 wrap() @rp2.asm_pio()def pre(): wrap_target() pull()#5 : just wait for trigger (any value) set(x, 31)#6 label("preloop") irq(block, 4)#7 irq(block, 4)#8 : why do we need 2x?, otherwise too short! jmp(x_dec, "preloop")#9 push(x)#10 : just trigger main() (any value) wrap() #generate a 32bit write transaction: 2bit (START) 2bit (CMD) 10bit (ADDR) 2bit (TA) 16bit (DATA write)@rp2.asm_pio(out_shiftdir=0, pull_thresh=32, out_init=rp2.PIO.OUT_LOW, set_init=rp2.PIO.OUT_LOW, sideset_init=rp3.PIO.OUT_LOW)def dataWrite(): wrap_target() pull()#11 set(x, 32)#12 label("loop") irq(block, 4)#13 out(pins, 1).side(1)#14 jmp(x_dec, "loop")#15 irq(block, 4)#16 set(pins, 1).side(1)#17 wrap() #generate a 16bit read transaction: 2bit (START) 2bit (CMD) 10bit (ADDR), 2bit (TA), 16bit (DATA read) - read with rising edge!@rp2.asm_pio(out_shiftdir=0, pull_thresh=14, push_thresh=16, out_init=rp2.PIO.OUT_LOW, set_init=rp2.PIO.OUT_LOW, sideset_init=rp2.PIO.OUT_LOW)def dataRead(): wrap_target() pull()#18 set(x, 13)#19 label("loop") irq(block, 4)#20 out(pins, 1)#21 jmp(x_dec, "loop")#22 irq(block, 4)#23 set(pindirs, 0).side(0)#24 : set the OEN signal low (for DIRection control) irq(block, 4)#25 set(x, 15)#26 irq(block, 5)#27 label("rx") irq(block, 5)#28 in_(pins, 1)#29 jmp(x_dec, "rx")#30 push()#31 set(pindirs, 1).side(1)#32 - full 32 instructions on PIO0, set OEN signal high wrap() FREQ = 25000000#CLK generator SM0sm0 = rp2.StateMachine(0, clk, freq=FREQ * 6, sideset_base=Pin(2))sm0.active(1)#read cycle SM2sm2 = rp2.StateMachine(2, dataRead, out_base=Pin(3), in_base=Pin(3), set_base=Pin(3), sideset_base=Pin(4))sm2.active(1)#write cycle SM1sm1 = rp2.StateMachine(1, dataWrite, out_base=Pin(3), in_base=Pin(3), set_base=Pin(3), sideset_base=Pin(4))sm1.active(1)sm3 = rp2.StateMachine(3, pre)sm3.active(1) prevR = 0while True: sm3.put(0) sm3.get() sm2.put(0x1A440000)#generate 13bits of frame start, 2bit TA and read 16bit r = sm2.get()#get the read result if prevR != r: prevR = r#print just if changed (otherwise slows down too much) print(hex(r)) sm3.put(0) sm3.get() sm1.put(0x01A44C084)#generate a write, 2bit (START) + 2bit (CMD) + 10bit (ADDR) + 2bit (TA) + 16bit (DATA write)
Statistics: Posted by tjaekel — Mon Aug 26, 2024 1:54 am