kopia lustrzana https://github.com/pimoroni/pimoroni-pico
				
				
				
			
		
			
				
	
	
		
			100 wiersze
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Plaintext
		
	
	
			
		
		
	
	
			100 wiersze
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Plaintext
		
	
	
| ; --------------------------------------------------
 | |
| ;        Quadrature Encoder reader using PIO
 | |
| ;      by Christopher (@ZodiusInfuser) Parrott
 | |
| ; --------------------------------------------------
 | |
| ;
 | |
| ; Watches any two pins (i.e. do not need to be
 | |
| ; consecutive) for when their state changes, and
 | |
| ; pushes that new state along with the old state,
 | |
| ; and time since the last change.
 | |
| ;
 | |
| ; - X is used for storing the last state
 | |
| ; - Y is used as a general scratch register
 | |
| ;     and for storing the current state
 | |
| ; - OSR is used for storing the state-change timer
 | |
| ;
 | |
| ; After data is pushed into the system, a long delay
 | |
| ; takes place as a form of switch debounce to deal
 | |
| ; with rotary encoder dials. This is currently set
 | |
| ; to 500 cycles, but can be changed using the debounce
 | |
| ; constants below, as well as adjusting the frequency
 | |
| ; the PIO state machine runs at. E.g. a freq_divider
 | |
| ; of 250 gives a 1ms debounce.
 | |
| 
 | |
| 
 | |
| ; Debounce Constants
 | |
| ; --------------------------------------------------
 | |
| .define SET_CYCLES                  10
 | |
| .define ITERATIONS                  30
 | |
| .define JMP_CYCLES                  16
 | |
| .define public ENC_DEBOUNCE_CYCLES  (SET_CYCLES + (JMP_CYCLES * ITERATIONS))
 | |
| 
 | |
| ; Ensure that ENC_DEBOUNCE_CYCLES is a multiple of the
 | |
| ; number of cycles the wrap takes, which is currently
 | |
| ; 10 cycles, otherwise timing may be inaccurate
 | |
| 
 | |
| 
 | |
| ; Encoder Program
 | |
| ; --------------------------------------------------
 | |
| .program encoder
 | |
| 
 | |
| .wrap_target
 | |
| loop:
 | |
|     ; Copy the state-change timer from OSR,
 | |
|     ; decrement it, and save it back
 | |
|     mov y, osr
 | |
|     jmp y-- osr_dec
 | |
| osr_dec:
 | |
|     mov osr, y
 | |
|     ; takes 3 cycles
 | |
| 
 | |
|     ; Read the state of both encoder pins and check
 | |
|     ; if they are different from the last state
 | |
|     jmp pin enc_a_was_high
 | |
|     mov isr, null
 | |
|     jmp read_enc_b
 | |
| enc_a_was_high:
 | |
|     set y, 1
 | |
|     mov isr, y
 | |
| read_enc_b:
 | |
|     in pins, 1
 | |
|     mov y, isr
 | |
|     jmp x!=y state_changed [1]
 | |
|     ; takes 7 cycles on both paths
 | |
| .wrap
 | |
| 
 | |
| state_changed:
 | |
|     ; Put the last state and the timer value into
 | |
|     ; ISR alongside the current state, and push that
 | |
|     ; state to the system. Then override the last
 | |
|     ; state with the current state
 | |
|     in x, 2
 | |
|     mov x, ~osr     ; invert the timer value to give
 | |
|                     ; a sensible value to the system
 | |
|     in x, 28
 | |
|     push noblock    ; this also clears isr
 | |
|     mov x, y
 | |
| 
 | |
|     ; Perform a delay to debounce switch inputs
 | |
|     set y, (ITERATIONS - 1) [SET_CYCLES - 1]
 | |
| debounce_loop:
 | |
|     jmp y-- debounce_loop [JMP_CYCLES - 1]
 | |
| 
 | |
|     ; Initialise the timer, as an inverse, and decrement
 | |
|     ; it to account for the time this setup takes
 | |
|     mov y, ~null
 | |
|     jmp y-- y_dec
 | |
| y_dec:
 | |
|     mov osr, y
 | |
|     jmp loop [1]
 | |
|     ;takes 10 cycles, not counting whatever the debounce adds
 | |
| 
 | |
| 
 | |
| ; Initialisation Code
 | |
| ; --------------------------------------------------
 | |
| % c-sdk {
 | |
| static const uint8_t ENC_LOOP_CYCLES = encoder_wrap - encoder_wrap_target;
 | |
| 
 | |
| // The time that the debounce takes, as the number of wrap loops that the debounce is equivalent to
 | |
| static const uint8_t ENC_DEBOUNCE_TIME = ENC_DEBOUNCE_CYCLES / ENC_LOOP_CYCLES;
 | |
| %} |