diff --git a/display/mt-12864a.go b/display/mt-12864a.go index 7b28c68..641dd25 100644 --- a/display/mt-12864a.go +++ b/display/mt-12864a.go @@ -1,253 +1,43 @@ package display import ( + "fmt" "image" "log" - "time" + "gitea.unprism.ru/yotia/display-test/pkg/mt12864a" "github.com/stianeikeland/go-rpio/v4" ) -const ( - adressWriteTimeout = 140 * time.Nanosecond - dataStrobeTimeout = 250 * time.Nanosecond // (Data transfer) -) - -type mt12864a struct { +type displayMt12864a struct { logger *log.Logger // GPIO pins - pinA0 rpio.Pin - pinRW rpio.Pin - pinE rpio.Pin - pinDB0 rpio.Pin - pinDB1 rpio.Pin - pinDB2 rpio.Pin - pinDB3 rpio.Pin - pinDB4 rpio.Pin - pinDB5 rpio.Pin - pinDB6 rpio.Pin - pinDB7 rpio.Pin - pinE1 rpio.Pin - pinE2 rpio.Pin - pinRES rpio.Pin + dev mt12864a.Device } func newMt12864a(logger *log.Logger) (Display, error) { - rpio.Open() - - d := mt12864a{ - logger: logger, - pinA0: rpio.Pin(7), - pinRW: rpio.Pin(11), - pinE: rpio.Pin(13), - pinDB0: rpio.Pin(15), - pinDB1: rpio.Pin(19), - pinDB2: rpio.Pin(21), - pinDB3: rpio.Pin(23), - pinDB4: rpio.Pin(27), - pinDB5: rpio.Pin(29), - pinDB6: rpio.Pin(31), - pinDB7: rpio.Pin(33), - pinE1: rpio.Pin(35), - pinE2: rpio.Pin(37), - pinRES: rpio.Pin(40), + dev, err := mt12864a.New(log.New(logger.Writer(), "display-mt12864 : ", log.LstdFlags)) + if err != nil { + return nil, fmt.Errorf("mt12864 create: %w", err) } - d.initLCD() + dev.PowerOn() + d := displayMt12864a{ + logger: logger, + dev: dev, + } return &d, nil } -func (d *mt12864a) GetBounds() image.Rectangle { +func (d *displayMt12864a) GetBounds() image.Rectangle { return image.Rectangle{} } -func (d *mt12864a) Flush(img *image.Gray) error { +func (d *displayMt12864a) Flush(img *image.Gray) error { return nil } -func (d *mt12864a) Close() error { +func (d *displayMt12864a) Close() error { return rpio.Close() } - -func (d *mt12864a) initLCD() { - // Set All to output - d.pinA0.Output() - d.pinRW.Output() - d.pinE.Output() - d.pinE1.Output() - d.pinE2.Output() - d.pinRES.Output() - d.busOutput() - d.logger.Println("sdljfsldkf") - // d.pinA0.Low() - // d.logger.Println("pinA0 set low") - // d.pinRW.Low() - // d.logger.Println("pinRW set low") - // d.pinE.Low() - // d.logger.Println("pinE set low") - // d.pinDB0.Low() - // d.logger.Println("pinDB0 set low") - // d.pinDB1.Low() - // d.logger.Println("pinDB1 set low") - // d.pinDB2.Low() - // d.logger.Println("pinDB2 set low") - // d.pinDB3.Low() - // d.logger.Println("pinDB3 set low") - // d.pinDB4.Low() - // d.logger.Println("pinDB4 set low") - // d.pinDB5.Low() - // d.logger.Println("pinDB5 set low") - // d.pinDB6.Low() - // d.logger.Println("pinDB6 set low") - // d.pinDB7.Low() - // d.logger.Println("pinDB7 set low") - // d.pinE1.Low() - // d.logger.Println("pinE1 set low") - // d.pinE2.Low() - // d.logger.Println("pinE2 set low") - // d.pinRES.Low() - // d.logger.Println("pinRES set low") - - // d.pinE.Low() - // d.pinRES.Low() - // time.Sleep(time.Microsecond) - // d.pinRES.High() - // time.Sleep(10 * time.Microsecond) - // d.writeCodeL(0xC0) // Top line to 0 - // d.writeCodeR(0xC0) - // d.writeCodeL(0x3F) // Display on - // d.writeCodeR(0x3F) -} - -func (d *mt12864a) writeCodeL(c byte) { - d.writeByte(c, 0, 1, 0) -} - -func (d *mt12864a) writeCodeR(c byte) { - d.writeByte(c, 0, 0, 1) -} - -func (d *mt12864a) writeDataL(b byte) { - d.writeByte(b, 1, 1, 0) -} - -func (d *mt12864a) writeDataR(b byte) { - d.writeByte(b, 1, 0, 1) -} - -func (d *mt12864a) readDataL() byte { - return d.readByte(1, 1, 0) -} - -func (d *mt12864a) readDataR() byte { - return d.readByte(1, 0, 1) -} - -func (d *mt12864a) writeByte(b byte, cd, l, r rpio.State) { - if l == rpio.High && r == rpio.High { - d.logger.Println("L and R are high!!!") - return - } - d.waitReady(l, r) - d.busOutput() - d.pinRW.Low() // We write - d.pinA0.Write(cd) - d.pinE1.Write(l) // Select cristals - d.pinE2.Write(r) // Select cristals - - // Write bus - d.pinDB0.Write(rpio.State((b >> 0) & 1)) - d.pinDB1.Write(rpio.State((b >> 1) & 1)) - d.pinDB2.Write(rpio.State((b >> 2) & 1)) - d.pinDB3.Write(rpio.State((b >> 3) & 1)) - d.pinDB4.Write(rpio.State((b >> 4) & 1)) - d.pinDB5.Write(rpio.State((b >> 5) & 1)) - d.pinDB6.Write(rpio.State((b >> 6) & 1)) - d.pinDB7.Write(rpio.State((b >> 7) & 1)) - - // Strobe start - d.pinE.High() - time.Sleep(dataStrobeTimeout) - // Strobe end - d.pinE.Low() - time.Sleep(time.Millisecond - dataStrobeTimeout - adressWriteTimeout) -} - -func (d *mt12864a) readByte(cd, l, r rpio.State) byte { - if l == rpio.High && r == rpio.High { - d.logger.Println("L and R are high!!!") - return 0 - } - var b byte - - d.waitReady(l, r) - d.busOutput() - d.pinRW.High() // We write - d.pinA0.Write(cd) - d.pinE1.Write(l) // Select cristals - d.pinE2.Write(r) // Select cristals - - // Strobe start - d.pinE.High() - time.Sleep(dataStrobeTimeout) - - // Read - b = uint8(d.pinDB0.Read()) | - (uint8(d.pinDB1.Read()) << 1) | - (uint8(d.pinDB2.Read()) << 2) | - (uint8(d.pinDB3.Read()) << 3) | - (uint8(d.pinDB4.Read()) << 4) | - (uint8(d.pinDB5.Read()) << 5) | - (uint8(d.pinDB6.Read()) << 6) | - (uint8(d.pinDB7.Read()) << 7) - - // Strobe end - d.pinE.Low() - time.Sleep(time.Millisecond - dataStrobeTimeout - adressWriteTimeout) - return b -} - -// Wait, checking status byte -func (d *mt12864a) waitReady(l, r rpio.State) { - d.busInput() // Set bus to input - d.pinRW.High() // We read - d.pinA0.Low() // Data - d.pinE1.Write(l) // Select cristals - d.pinE2.Write(r) // Select cristals - time.Sleep(adressWriteTimeout) - // Strobe start - d.pinE.High() - time.Sleep(dataStrobeTimeout) - // Wait status flag drop - counter := 0 - for d.pinDB7.Read() == rpio.High && counter < 100 { - counter++ - } - // Strobe end - d.pinE.Low() - time.Sleep(time.Millisecond - dataStrobeTimeout - adressWriteTimeout) -} - -// Set bus pins to output -func (d *mt12864a) busOutput() { - d.pinDB0.Output() - d.pinDB1.Output() - d.pinDB2.Output() - d.pinDB3.Output() - d.pinDB4.Output() - // d.pinDB5.Output() - d.pinDB6.Output() - d.pinDB7.Output() -} - -func (d *mt12864a) busInput() { - d.pinDB0.Input() - d.pinDB1.Input() - d.pinDB2.Input() - d.pinDB3.Input() - d.pinDB4.Input() - d.pinDB5.Input() - d.pinDB6.Input() - d.pinDB7.Input() -} diff --git a/display/ssd1336.go b/display/ssd1306.go similarity index 100% rename from display/ssd1336.go rename to display/ssd1306.go diff --git a/drawer/drawer.go b/drawer/drawer.go index 4ab035b..58a0428 100644 --- a/drawer/drawer.go +++ b/drawer/drawer.go @@ -1,10 +1,11 @@ package drawer import ( - "display-test/display" "image" "sync" + "gitea.unprism.ru/yotia/display-test/display" + "golang.org/x/image/font" "golang.org/x/image/font/inconsolata" ) diff --git a/go.mod b/go.mod index f9d4dcf..e82ddb3 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module display-test +module gitea.unprism.ru/yotia/display-test go 1.22.5 diff --git a/main.go b/main.go index 643919f..360a994 100644 --- a/main.go +++ b/main.go @@ -2,8 +2,6 @@ package main import ( "context" - "display-test/display" - "display-test/drawer" "fmt" "log" "os" @@ -11,6 +9,9 @@ import ( "syscall" "time" + "gitea.unprism.ru/yotia/display-test/display" + "gitea.unprism.ru/yotia/display-test/drawer" + "gitea.unprism.ru/KRBL/sim-modem/api/modem" ) @@ -162,6 +163,7 @@ func mainE(ctx context.Context) error { logger = log.New(os.Stdout, "main : ", log.LstdFlags) // disp, _ := display.New(logger, display.MT12864A) + time.Sleep(2 * time.Second) defer disp.Close() // if err := Init(ctx); err != nil { // return err diff --git a/pkg/mt12864a/mt12864a.go b/pkg/mt12864a/mt12864a.go new file mode 100644 index 0000000..afc9a48 --- /dev/null +++ b/pkg/mt12864a/mt12864a.go @@ -0,0 +1,414 @@ +package mt12864a + +import ( + "io" + "log" + "time" + + "github.com/stianeikeland/go-rpio/v4" +) + +const ( + adressWriteTimeout = 140 * time.Nanosecond + dataStrobeTimeout = 250 * time.Nanosecond // (Data transfer) + maxWaitCycles = 100 +) + +type mt12864a struct { + logger *log.Logger + + // GPIO pins + pinA0 rpio.Pin + pinRW rpio.Pin + pinE rpio.Pin + pinDB0 rpio.Pin + pinDB1 rpio.Pin + pinDB2 rpio.Pin + pinDB3 rpio.Pin + pinDB4 rpio.Pin + pinDB5 rpio.Pin + pinDB6 rpio.Pin + pinDB7 rpio.Pin + pinE1 rpio.Pin + pinE2 rpio.Pin + pinRES rpio.Pin +} + +type Device interface { + PowerOn() + + WriteCodeL(c byte) + WriteCodeR(c byte) + + WriteDataL(b byte) + WriteDataR(b byte) + + WriteDataArrayL(b []byte) + WriteDataArrayR(b []byte) + + ReadDataL() byte + ReadDataR() byte + + ReadDataArrayL() []byte + ReadDataArrayR() []byte + + io.Closer +} + +func New(logger *log.Logger) (Device, error) { + rpio.Open() + + d := mt12864a{ + logger: logger, + pinA0: rpio.Pin(7), + pinRW: rpio.Pin(11), + pinE: rpio.Pin(13), + + pinDB0: rpio.Pin(15), + pinDB1: rpio.Pin(19), + pinDB2: rpio.Pin(21), + pinDB3: rpio.Pin(23), + pinDB4: rpio.Pin(27), + pinDB5: rpio.Pin(32), + pinDB6: rpio.Pin(31), + pinDB7: rpio.Pin(33), + + // Reverted + // pinDB7: rpio.Pin(15), + // pinDB6: rpio.Pin(19), + // pinDB5: rpio.Pin(21), + // pinDB4: rpio.Pin(23), + // pinDB3: rpio.Pin(27), + // pinDB2: rpio.Pin(32), + // pinDB1: rpio.Pin(31), + // pinDB0: rpio.Pin(33), + + pinE1: rpio.Pin(35), + pinE2: rpio.Pin(37), + pinRES: rpio.Pin(40), + } + d.AllOutput() + d.PrintPins() + + return &d, nil +} + +func (d *mt12864a) Close() error { + return rpio.Close() +} + +func (d *mt12864a) PowerOn() { + d.pinA0.PullOff() + d.pinRW.PullOff() + d.pinE.PullOff() + d.pinDB0.PullOff() + d.pinDB1.PullOff() + d.pinDB2.PullOff() + d.pinDB3.PullOff() + d.pinDB4.PullOff() + d.pinDB5.PullOff() + d.pinDB6.PullOff() + d.pinDB7.PullOff() + d.pinE1.PullOff() + d.pinE2.PullOff() + d.pinRES.PullOff() + + d.pinA0.Low() + d.pinRW.Low() + d.pinE.Low() + d.pinDB0.Low() + d.pinDB1.Low() + d.pinDB2.Low() + d.pinDB3.Low() + d.pinDB4.Low() + d.pinDB5.Low() + d.pinDB6.Low() + d.pinDB7.Low() + d.pinE1.Low() + d.pinE2.Low() + d.pinRES.Low() + + d.PrintPins() + d.logger.Println("Power on") + d.PrintPins() + d.pinE.Low() + d.PrintPins() + d.pinRES.Low() + d.PrintPins() + time.Sleep(time.Microsecond) + d.pinRES.High() + time.Sleep(10 * time.Microsecond) + d.PrintPins() + d.logger.Println("Display on") + d.WriteCodeL(0x3F) // Display on + d.PrintPins() + d.logger.Println("Top line to 0") + d.WriteCodeL(0xC0) // Top line to 0 + d.PrintPins() +} + +// Write codes + +func (d *mt12864a) WriteCodeL(c byte) { + d.writeByte(c, 0, 1, 0) +} + +func (d *mt12864a) WriteCodeR(c byte) { + d.writeByte(c, 0, 0, 1) +} + +// Write data as byte + +func (d *mt12864a) WriteDataL(b byte) { + d.writeByte(b, 1, 1, 0) +} + +func (d *mt12864a) WriteDataR(b byte) { + d.writeByte(b, 1, 0, 1) +} + +// Write data as byte array + +func (d *mt12864a) WriteDataArrayL(b []byte) { + d.writeByteArray(b, 1, 1, 0) +} + +func (d *mt12864a) WriteDataArrayR(b []byte) { + d.writeByteArray(b, 1, 0, 1) +} + +// Read data + +func (d *mt12864a) ReadDataL() byte { + return d.readByte(1, 1, 0) +} + +func (d *mt12864a) ReadDataR() byte { + return d.readByte(1, 0, 1) +} + +// Read data array + +func (d *mt12864a) ReadDataArrayL() []byte { + return d.readByteArray(1, 1, 0) +} + +func (d *mt12864a) ReadDataArrayR() []byte { + return d.readByteArray(1, 0, 1) +} + +// Low level functions + +func (d *mt12864a) writeByte(b byte, cd, l, r rpio.State) { + d.logger.Println("Write byte", b, cd, l, r) + if l == rpio.High && r == rpio.High { + d.logger.Println("L and R are high!!!") + return + } + d.waitReady(l, r) + d.busOutput() + d.pinRW.Low() // We write + d.pinA0.Write(cd) + d.pinE1.Write(l) // Select cristals + d.pinE2.Write(r) // Select cristals + + // Write bus + d.pinDB0.Write(rpio.State((b >> 0) & 1)) + d.pinDB1.Write(rpio.State((b >> 1) & 1)) + d.pinDB2.Write(rpio.State((b >> 2) & 1)) + d.pinDB3.Write(rpio.State((b >> 3) & 1)) + d.pinDB4.Write(rpio.State((b >> 4) & 1)) + d.pinDB5.Write(rpio.State((b >> 5) & 1)) + d.pinDB6.Write(rpio.State((b >> 6) & 1)) + d.pinDB7.Write(rpio.State((b >> 7) & 1)) + + // Strobe start + d.pinE.High() + time.Sleep(dataStrobeTimeout) + // Strobe end + d.pinE.Low() + time.Sleep(time.Millisecond - dataStrobeTimeout - adressWriteTimeout) +} + +func (d *mt12864a) writeByteArray(b []byte, cd, l, r rpio.State) { + d.logger.Println("Write byte", b, cd, l, r) + if len(b) != 8 { + d.logger.Println("invalid b len") + return + } + if l == rpio.High && r == rpio.High { + d.logger.Println("L and R are high!!!") + return + } + d.waitReady(l, r) + d.busOutput() + d.pinRW.Low() // We write + d.pinA0.Write(cd) + d.pinE1.Write(l) // Select cristals + d.pinE2.Write(r) // Select cristals + + // Write bus + d.pinDB0.Write(rpio.State(b[0])) + d.pinDB1.Write(rpio.State(b[1])) + d.pinDB2.Write(rpio.State(b[2])) + d.pinDB3.Write(rpio.State(b[3])) + d.pinDB4.Write(rpio.State(b[4])) + d.pinDB5.Write(rpio.State(b[5])) + d.pinDB6.Write(rpio.State(b[6])) + d.pinDB7.Write(rpio.State(b[7])) + + // Strobe start + d.pinE.High() + time.Sleep(dataStrobeTimeout) + // Strobe end + d.pinE.Low() + time.Sleep(time.Millisecond - dataStrobeTimeout - adressWriteTimeout) +} + +func (d *mt12864a) readByte(cd, l, r rpio.State) byte { + if l == rpio.High && r == rpio.High { + d.logger.Println("L and R are high!!!") + return 0 + } + var b byte + + d.waitReady(l, r) + d.busOutput() + d.pinRW.High() // We write + d.pinA0.Write(cd) + d.pinE1.Write(l) // Select cristals + d.pinE2.Write(r) // Select cristals + + // Strobe start + d.pinE.High() + time.Sleep(dataStrobeTimeout) + + // Read + b = uint8(d.pinDB0.Read()) | + (uint8(d.pinDB1.Read()) << 1) | + (uint8(d.pinDB2.Read()) << 2) | + (uint8(d.pinDB3.Read()) << 3) | + (uint8(d.pinDB4.Read()) << 4) | + (uint8(d.pinDB5.Read()) << 5) | + (uint8(d.pinDB6.Read()) << 6) | + (uint8(d.pinDB7.Read()) << 7) + + // Strobe end + d.pinE.Low() + time.Sleep(time.Millisecond - dataStrobeTimeout - adressWriteTimeout) + return b +} + +func (d *mt12864a) readByteArray(cd, l, r rpio.State) []byte { + if l == rpio.High && r == rpio.High { + d.logger.Println("L and R are high!!!") + return nil + } + b := make([]byte, 8) + + d.waitReady(l, r) + d.busOutput() + d.pinRW.High() // We write + d.pinA0.Write(cd) + d.pinE1.Write(l) // Select cristals + d.pinE2.Write(r) // Select cristals + + // Strobe start + d.pinE.High() + time.Sleep(dataStrobeTimeout) + + // Read + b[0] = (uint8(d.pinDB0.Read()) << 0) + b[1] = (uint8(d.pinDB1.Read()) << 1) + b[2] = (uint8(d.pinDB2.Read()) << 2) + b[3] = (uint8(d.pinDB3.Read()) << 3) + b[4] = (uint8(d.pinDB4.Read()) << 4) + b[5] = (uint8(d.pinDB5.Read()) << 5) + b[6] = (uint8(d.pinDB6.Read()) << 6) + b[7] = (uint8(d.pinDB7.Read()) << 7) + + // Strobe end + d.pinE.Low() + time.Sleep(time.Millisecond - dataStrobeTimeout - adressWriteTimeout) + return nil +} + +// Wait, checking status byte +func (d *mt12864a) waitReady(l, r rpio.State) { + d.logger.Println("Wait ready", l, r) + d.busInput() // Set bus to input + d.pinRW.High() // We read + d.pinA0.Low() // Data + d.pinE1.Write(l) // Select cristals + d.pinE2.Write(r) // Select cristals + time.Sleep(adressWriteTimeout) + // Strobe start + d.pinE.High() + time.Sleep(dataStrobeTimeout) + // Wait status flag drop + counter := 0 + for counter < maxWaitCycles { + d.busInput() // Set bus to input + if d.pinDB7.Read() != rpio.High { + break + } + d.PrintPins() + counter++ + } + if counter == maxWaitCycles { + log.Println("TIMEOUT!!!!!!!!!!!!!") + } + // Strobe end + d.pinE.Low() + time.Sleep(time.Millisecond - dataStrobeTimeout - adressWriteTimeout) + d.logger.Println("Ready") +} + +func (d *mt12864a) PrintPins() { + d.AllInput() + d.logger.Printf("A0:%d RW:%d E:%d BUS:%d%d%d%d%d%d%d%d E1:%d E2:%d RES:%d\n", d.pinA0.Read(), d.pinRW.Read(), d.pinE.Read(), d.pinDB0.Read(), d.pinDB1.Read(), d.pinDB2.Read(), d.pinDB3.Read(), d.pinDB4.Read(), d.pinDB5.Read(), d.pinDB6.Read(), d.pinDB7.Read(), d.pinE1.Read(), d.pinE2.Read(), d.pinRES.Read()) + d.AllOutput() +} + +func (d *mt12864a) AllOutput() { + d.pinA0.Output() + d.pinRW.Output() + d.pinE.Output() + d.pinE1.Output() + d.pinE2.Output() + d.pinRES.Output() + d.busOutput() +} + +func (d *mt12864a) AllInput() { + d.pinA0.Input() + d.pinRW.Input() + d.pinE.Input() + d.pinE1.Input() + d.pinE2.Input() + d.pinRES.Input() + d.busInput() +} + +// Set bus pins to output +func (d *mt12864a) busOutput() { + d.pinDB0.Output() + d.pinDB1.Output() + d.pinDB2.Output() + d.pinDB3.Output() + d.pinDB4.Output() + d.pinDB5.Output() + d.pinDB6.Output() + d.pinDB7.Output() +} + +func (d *mt12864a) busInput() { + d.pinDB0.Input() + d.pinDB1.Input() + d.pinDB2.Input() + d.pinDB3.Input() + d.pinDB4.Input() + d.pinDB5.Input() + d.pinDB6.Input() + d.pinDB7.Input() +} diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..546b907 --- /dev/null +++ b/readme.md @@ -0,0 +1,35 @@ +## ssd1306 +res: 128x32 +iface: i2c +u: 3v +pins: + 1. VCC => 1 + 2. GND => 9 + 3. SCK => 3 + 4. SDA => 5 + +## MT-12864A +[Doc](https://www.melt.com.ru/docs/MT-12864A.pdf) +res: 128x64 +u: 3v +pins: + 1. GND => 9 + 2. UCC => 17 + 3. U0 -W + 4. A0 => 7 + 5. R/W => 11 + 6. E => 13 + 7. DB0 => 15 + 8. DB1 => 19 + 9. DB2 => 21 + 10. DB3 => 23 + 11. DB4 => 27 + 12. DB5 => (29 does not work) => + 13. DB6 => 31 + 14. DB7 => 33 + 15. E1 => 35 + 16. E2 => 37 + 17. RES => 40 + 18. Uee => rheostat => U0 (contrast settings) + 19. A (light+) ?? + 20. K (light-) ??