tinygo.org/x/drivers@v0.27.1-0.20240509133757-7dbca2a54349/hd44780/gpio.go (about) 1 package hd44780 2 3 import ( 4 "errors" 5 6 "machine" 7 ) 8 9 type GPIO struct { 10 dataPins []machine.Pin 11 en machine.Pin 12 rw machine.Pin 13 rs machine.Pin 14 15 write func(data byte) 16 read func() byte 17 } 18 19 func newGPIO(dataPins []machine.Pin, en, rs, rw machine.Pin, mode byte) Device { 20 pins := make([]machine.Pin, len(dataPins)) 21 for i := 0; i < len(dataPins); i++ { 22 dataPins[i].Configure(machine.PinConfig{Mode: machine.PinOutput}) 23 pins[i] = dataPins[i] 24 } 25 en.Configure(machine.PinConfig{Mode: machine.PinOutput}) 26 rs.Configure(machine.PinConfig{Mode: machine.PinOutput}) 27 rw.Configure(machine.PinConfig{Mode: machine.PinOutput}) 28 rw.Low() 29 30 gpio := GPIO{ 31 dataPins: pins, 32 en: en, 33 rs: rs, 34 rw: rw, 35 } 36 37 if mode == DATA_LENGTH_4BIT { 38 gpio.write = gpio.write4BitMode 39 gpio.read = gpio.read4BitMode 40 } else { 41 gpio.write = gpio.write8BitMode 42 gpio.read = gpio.read8BitMode 43 } 44 45 return Device{ 46 bus: &gpio, 47 datalength: mode, 48 } 49 } 50 51 // SetCommandMode sets command/instruction mode 52 func (g *GPIO) SetCommandMode(set bool) { 53 if set { 54 g.rs.Low() 55 } else { 56 g.rs.High() 57 } 58 } 59 60 // WriteOnly is true if you passed rw in as machine.NoPin 61 func (g *GPIO) WriteOnly() bool { 62 return g.rw == machine.NoPin 63 } 64 65 // Write writes len(data) bytes from data to display driver 66 func (g *GPIO) Write(data []byte) (n int, err error) { 67 if !g.WriteOnly() { 68 g.rw.Low() 69 } 70 for _, d := range data { 71 g.write(d) 72 n++ 73 } 74 return n, nil 75 } 76 77 func (g *GPIO) write8BitMode(data byte) { 78 g.en.High() 79 g.setPins(data) 80 g.en.Low() 81 } 82 83 func (g *GPIO) write4BitMode(data byte) { 84 g.en.High() 85 g.setPins(data >> 4) 86 g.en.Low() 87 88 g.en.High() 89 g.setPins(data) 90 g.en.Low() 91 } 92 93 // Read reads len(data) bytes from display RAM to data starting from RAM address counter position 94 // Ram address can be changed by writing address in command mode 95 func (g *GPIO) Read(data []byte) (n int, err error) { 96 if len(data) == 0 { 97 return 0, errors.New("length greater than 0 is required") 98 } 99 if g.WriteOnly() { 100 return 0, errors.New("Read not supported if RW not wired") 101 } 102 g.rw.High() 103 g.reconfigureGPIOMode(machine.PinInput) 104 for i := 0; i < len(data); i++ { 105 data[i] = g.read() 106 n++ 107 } 108 g.rw.Low() 109 g.reconfigureGPIOMode(machine.PinOutput) 110 return n, nil 111 } 112 113 func (g *GPIO) read4BitMode() byte { 114 g.en.High() 115 data := (g.pins() << 4 & 0xF0) 116 g.en.Low() 117 118 g.en.High() 119 data |= (g.pins() & 0x0F) 120 g.en.Low() 121 return data 122 } 123 124 func (g *GPIO) read8BitMode() byte { 125 g.en.High() 126 data := g.pins() 127 g.en.Low() 128 return data 129 } 130 131 func (g *GPIO) reconfigureGPIOMode(mode machine.PinMode) { 132 for i := 0; i < len(g.dataPins); i++ { 133 g.dataPins[i].Configure(machine.PinConfig{Mode: mode}) 134 } 135 } 136 137 // setPins sets high or low state on all data pins depending on data 138 func (g *GPIO) setPins(data byte) { 139 mask := byte(1) 140 for i := 0; i < len(g.dataPins); i++ { 141 if (data & mask) != 0 { 142 g.dataPins[i].High() 143 } else { 144 g.dataPins[i].Low() 145 } 146 mask = mask << 1 147 } 148 } 149 150 // pins returns current state of data pins. MSB is D7 151 func (g *GPIO) pins() byte { 152 bits := byte(0) 153 for i := uint8(0); i < uint8(len(g.dataPins)); i++ { 154 if g.dataPins[i].Get() { 155 bits |= (1 << i) 156 } 157 } 158 return bits 159 }