class PIOBeep: def __init__(self, sm_id, pin): self.square_sm = StateMachine(0, square_prog, freq=freq, sideset_base=Pin(pin)) #pre-load the isr with the value of max_count self.square_sm.put(max_count) self.square_sm.exec("pull()") self.square_sm.exec("mov(isr, osr)") #note - based on current values of max_count and freq # this will be slightly out because of the initial mov instructions, #but that should only have an effect at very high frequencies def calc_pitch(self, hertz): return int(-1 * (((1000000 / hertz) - 20000) / 4)) def play_value(self, note_len, pause_len, val): self.square_sm.active(1) self.square_sm.put(val) sleep(note_len) self.square_sm.active(0) sleep(pause_len) def play_pitch(self, note_len, pause_len, pitch): self.play_value(note_len, pause_len, self.calc_pitch(pitch))
class SquareOscillator: def __init__(self, sm_id, pin, max_count, count_freq): self._sm = StateMachine(sm_id, square_prog, freq=2 * count_freq, sideset_base=Pin(pin)) # Use exec() to load max count into ISR self._sm.put(max_count) self._sm.exec("pull()") self._sm.exec("mov(isr, osr)") self._sm.active(1) self._max_count = max_count self._count_freq = count_freq def set(self, value): # Minimum value is -1 (completely turn off), 0 actually still # produces a narrow pulse value = clamp(value, -1, self._max_count) self._sm.put(value) # Converts Hertz to the value the state machine running the PIO # program needs def get_pitch(self, hertz): return int(-1 * (((self._count_freq / hertz) - (self._max_count * 4)) / 4))
class PIOPWM: def __init__(self, sm_id, pin, count_freq, max_count=(1 << 16) - 1): print(pin) self._sm = StateMachine(sm_id, pwm_prog, freq=2 * count_freq, sideset_base=Pin(pin)) # Use exec() to load max count into ISR self._sm.put(max_count) self._sm.exec("pull()") self._sm.exec("mov(isr, osr)") self._sm.active(1) self._max_count = max_count self._pin = pin def _set(self, value): # Minimum value is -1 (completely turn off), 0 actually still produces narrow pulse if value>self._max_count: self._sm.active(0) print("off: ", value) Pin(self._pin, Pin.OUT).value(1) else: if not(self._sm.active()): self._sm.put(self._max_count) self._sm.exec("pull()") self._sm.exec("mov(isr, osr)") self._sm.active(1) print("on: ", value) value = max(value, -1) value = min(value, self._max_count) self._sm.put(value) def set(self, value): # Minimum value is -1 (completely turn off), 0 actually still produces narrow pulse value = max(value, -1) value = min(value, self._max_count) print(value) self._sm.put(value)
class PIOPWM: def __init__(self, sm_id, pin, max_count, count_freq): self._sm = StateMachine(sm_id, pwm_prog, freq=2 * count_freq, sideset_base=Pin(pin)) # Use exec() to load max count into ISR self._sm.put(max_count) self._sm.exec("pull()") self._sm.exec("mov(isr, osr)") self._sm.active(1) self._max_count = max_count def set(self, value): # Minimum value is -1 (completely turn off), 0 actually still produces narrow pulse value = max(value, -1) value = min(value, self._max_count) self._sm.put(value)
mov(y, osr) # step pattern pull() mov(x, osr) # num steps jmp(not_x, "end") label("loop") jmp(not_osre, "step") # loop pattern if exhausted mov(osr, y) label("step") out(pins, 4)[31] nop()[31] nop()[31] nop()[31] jmp(x_dec, "loop") label("end") set(pins, 8)[31] # 8 sm = StateMachine(0, prog, freq=10000, set_base=Pin(2), out_base=Pin(2)) sm.active(1) sm.put(2216789025) #1000 0100 0010 0001 1000010000100001 sm.put(1000) sleep(5) sm.active(0) sm.exec("set(pins,0)")
# Y gets a value of 500. Say a value of 200 is put to the OSR (then X) # via the put() command. In each instance of the asm codeexecution, # the asm code will first set the pin low, then decrement Y by 1 in a loop # until y matches x. When y = x = 200, line 14 is called once, setting # the pin high. With the pin set high, y continues to decrement by 1 until 0. # Then the asm is repeated and the pin is set to low again. Therefore, # setting x to 200 will result the pin to be high 200/500 of the times, # corresponding to a 40% duty cycle. # State Machine init pwm_sm = StateMachine(0, pwm_prog, freq=10000000, sideset_base=Pin(16)) # State Machine pwm_sm.put(max_count) # Put data in output FIFO pwm_sm.exec("pull()") pwm_sm.exec("mov(isr, osr)") # Load val into ISR pwm_sm.active(1) # PWM Test #while True: # for i in range(max_count): # pwm_sm.put(i) # sleep(0.001) # for i in range(max_count): # pwm_sm.put(max_count - i) # sleep(0.001) # Jerkky Motion # pwm_sm.put(0) # sleep(1)
@asm_pio(sideset_init=PIO.OUT_LOW) def pwm_prog(): pull(noblock).side(0) mov(x, osr) mov(y, isr) label("pwmloop") jmp(x_not_y, "skip") nop().side(1) label("skip") jmp(y_dec, "pwmloop") pwm_sm = StateMachine(0, pwm_prog, freq=10000000, sideset_base=Pin(25)) pwm_sm.put(max_count) pwm_sm.exec("pull()") pwm_sm.exec("mov(isr, osr)") pwm_sm.active(1) def sweep_up(): for i in range(500): pwm_sm.put(i) sleep(0.001) def sweep_down(): for i in range(500, 0, -1): pwm_sm.put(i) sleep(0.001)
#mirror the above loop, but with the pin high to form the second #half of the square wave label("down") mov(y, isr) label("down_loop") jmp(x_not_y, "skip_down") nop() .side(0) jmp("restart") label("skip_down") jmp(y_dec, "down_loop") square_sm = StateMachine(0, square_prog, freq=freq, sideset_base=Pin(0)) #pre-load the isr with the value of max_count square_sm.put(max_count) square_sm.exec("pull()") square_sm.exec("mov(isr, osr)") #note - based on current values of max_count and freq # this will be slightly out because of the initial mov instructions, #but that should only have an effect at very high frequencies def calc_pitch(hertz): return int( -1 * (((1000000/hertz) -20000)/4)) notes = [392, 440, 494, 523, 587, 659, 698, 784] notes_val = [] for note in notes: notes_val.append(calc_pitch(note))