# RP2040 - set period square wave on GPIO-26 and count positive edges
# by Anthony Vogelaar, Perth Scotland
# rev 0.10  2025-08-22  Initial release

from	machine		import	Pin
import	time
import	rp2

# ======================= PIO functions ======================

# Frequency on GPIO-26 is determined by value in X
@rp2.asm_pio(set_init=rp2.PIO.OUT_LOW)
def freqY():
    set(x, 0)						# start with GPIO-25 = low
    label('loop')
    pull(noblock)					# OSR := TX_FIFO or X when empty
    mov(x, osr)
    jmp(not_x, 'loop')				# wait until x not 0
    mov(y, x)
    set(pins, 1)					# high for X clocks
    label('l1')
    jmp(y_dec, 'l1')
    mov(y, x)
    set(pins, 0)					# low fro X clocks
    label('l2')
    jmp(y_dec, 'l2')
    jmp('loop')


# Count positive GPIO-26 edges in X, GPIO-16 side output for monitoring
@rp2.asm_pio(sideset_init=rp2.PIO.OUT_LOW)
def countX():
    set(x, 0)							# start X = 0
    label('loop')
    wait(1, pin, 26)	.side(0)		# wait until pin 26 is high
    jmp(x_dec, 'l1')					# X := X - 1
    label('l1')
    wait(0, pin, 26)	.side(1)		# wait until pin 26 is LOW
    jmp('loop')

# ======================= State machine ========================

# helper class for PIO StateMachines
class PioMach:
    
    def  __init__(self, program, freq=125_000_000, id=0, **kwargs):
        self.sm = rp2.StateMachine(id, program, freq, **kwargs)
        self.sm.active(True)


    # put value into sm.TX_FIFO
    def put(self, value):
        self.sm.put(value)
        

    # get contents of X
    # Warning: exec requires a long execution time
    def get(self):
        self.sm.exec('mov(isr,x)')		# 6 mSec
        self.sm.exec('push(noblock)')	# 6 mSec
        res = self.sm.get()				# 75 uSec
        return res
    
# ========================== main ==============================

# set 5000 Hz on GPIO-26 and count positive edges. Print count @ 1 Sec
def main():
    sm1     = PioMach(freqY,        set_base=Pin(26))
    sm2     = PioMach(countX, id=1, sideset_base=Pin(16))
    sm1.put(12495)				# put into TX_FIFO	-->	 5.00 kHz
    while True:
        time.sleep_ms(988)
        print(sm2.get()^0xFFFFFFFF)
        

main()

# =========================== end ==============================
