pimoroni-pico/drivers/pwm/pwm_cluster.pio

72 lines
2.5 KiB
Plaintext

; --------------------------------------------------
; 32-Channel PWM using PIO
; by Christopher (@ZodiusInfuser) Parrott
; --------------------------------------------------
;
; Outputs PWM signals to up to 32 pins using a single
; state-machine. This is achieved by representing the
; problem as a sequence of state changes and time delays.
;
; This requires the use of DMA or a very fast loop to
; provide data at a sufficient rate to prevent stalling.
;
; The program pulls in two words:
; - The first is a 32-bit pin mask of the states to
; change the pins to. Only the pins configured for
; use by this SM will be affected.
; - The second is the time delay to wait before
; pulling in the next states.
;
; Each loop of the program takes 5 cycles, including an
; initial 5 cycles when new data is loaded in. As such,
; the time delay should be set to your "intended_delay - 1".
;
; To aid in debugging there is a variant program that uses
; a sideset pin to show when new data is pulled in, as well
; as when each loop has elapsed.These look like:
;
; New Data Loop
; ._|‾|_._._ |‾.‾.‾.‾|_
; 1 2 3 4 5 1 2 3 4 5
; Debounce Constants
; --------------------------------------------------
.define public PWM_CLUSTER_CYCLES 5
; PWM Program
; --------------------------------------------------
.program pwm_cluster
.wrap_target
pull ; Pull in the new pin states
out pins, 32 ; Immediately set the pins to their new state
pull ; Pull in the delay counter
out y, 32 ; Set the counter
count_check:
jmp y-- delay ; Check if the counter is 0, and if so wrap around.
; If not decrement the counter and jump to the delay
.wrap
delay:
jmp count_check [3] ; Wait a few cycles then jump back to the loop
; Debug PWM Program
; --------------------------------------------------
.program debug_pwm_cluster
.side_set 1
.wrap_target
pull side 0 ; Pull in the new pin states
out pins, 32 side 1 ; Immediately set the pins to their new state
pull side 0 ; Pull in the delay counter
out y, 32 side 0 ; Set the counter
count_check:
jmp y-- delay side 0 ; Check if the counter is 0, and if so wrap around.
;If not decrement the counter and jump to the delay
.wrap
delay:
jmp count_check [3] side 1 ; Wait a few cycles then jump back to the loop