tinygo.org/x/drivers@v0.27.1-0.20240509133757-7dbca2a54349/encoders/quadrature_interrupt.go (about) 1 //go:build tinygo && (rp2040 || stm32 || k210 || esp32c3 || nrf || sam || (avr && (atmega328p || atmega328pb))) 2 3 // Implementation based on: 4 // https://gist.github.com/aykevl/3fc1683ed77bb0a9c07559dfe857304a 5 6 // Note: build constraints in this file list targets that define machine.PinToggle. 7 // If this is supported for additional targets in the future, they can be added above. 8 9 package encoders 10 11 import ( 12 "machine" 13 "runtime/volatile" 14 ) 15 16 var ( 17 states = []int8{0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0} 18 ) 19 20 // NewQuadratureViaInterrupt returns a rotary encoder device that uses GPIO 21 // interrupts and a lookup table to keep track of quadrature state changes. 22 // 23 // This constructur is only available for TinyGo targets for which machine.PinToggle 24 // is defined as a valid interrupt type. 25 func NewQuadratureViaInterrupt(pinA, pinB machine.Pin) *QuadratureDevice { 26 return &QuadratureDevice{impl: &quadInterruptImpl{pinA: pinA, pinB: pinB, oldAB: 0b00000011}} 27 } 28 29 type quadInterruptImpl struct { 30 pinA machine.Pin 31 pinB machine.Pin 32 33 // precision int 34 35 oldAB int 36 value volatile.Register32 37 } 38 39 func (enc *quadInterruptImpl) configure(cfg QuadratureConfig) error { 40 enc.pinA.Configure(machine.PinConfig{Mode: machine.PinInputPullup}) 41 enc.pinA.SetInterrupt(machine.PinToggle, enc.interrupt) 42 43 enc.pinB.Configure(machine.PinConfig{Mode: machine.PinInputPullup}) 44 enc.pinB.SetInterrupt(machine.PinToggle, enc.interrupt) 45 46 return nil 47 } 48 49 func (enc *quadInterruptImpl) interrupt(pin machine.Pin) { 50 aHigh, bHigh := enc.pinA.Get(), enc.pinB.Get() 51 enc.oldAB <<= 2 52 if aHigh { 53 enc.oldAB |= 1 << 1 54 } 55 if bHigh { 56 enc.oldAB |= 1 57 } 58 enc.writeValue(enc.readValue() + int(states[enc.oldAB&0x0f])) 59 } 60 61 // readValue gets the value using volatile operations and returns it as an int 62 func (enc *quadInterruptImpl) readValue() int { 63 return int(enc.value.Get()) 64 } 65 66 // writeValue set the value to the specified int using volatile operations 67 func (enc *quadInterruptImpl) writeValue(v int) { 68 enc.value.Set(uint32(v)) 69 }