diff --git a/pkg/mt12232a/mt12232a.go b/pkg/mt12232a/mt12232a.go new file mode 100644 index 0000000..e42cafd --- /dev/null +++ b/pkg/mt12232a/mt12232a.go @@ -0,0 +1,205 @@ +package mt12232a + +import ( + "fmt" + "io" + "log" + "time" + + "gitea.unprism.ru/yotia/display-test/pkg/parallel8bit" + "github.com/stianeikeland/go-rpio/v4" +) + +type mt12232a struct { + logger *log.Logger + + dev parallel8bit.Device + + pinCS rpio.Pin + pinRES rpio.Pin +} + +type Device interface { + PowerOn() error + SetPixel(x, y byte, c bool) error + + WriteCodeL(c byte) error + WriteCodeR(c byte) error + WriteDataL(b byte) error + WriteDataR(b byte) error + + ReadDataL() (byte, error) + ReadDataR() (byte, error) + ReadStatus(cs rpio.State) byte + + io.Closer +} + +func New(logger *log.Logger) (Device, error) { + rpio.Open() + + d := mt12232a{ + logger: logger, + + dev: parallel8bit.New(logger, parallel8bit.DevicePins{ + PinA0: rpio.Pin(18), + PinRW: rpio.Pin(17), + PinE: rpio.Pin(27), + + PinDB0: rpio.Pin(22), + PinDB1: rpio.Pin(10), + PinDB2: rpio.Pin(9), // From 21 + PinDB3: rpio.Pin(11), + PinDB4: rpio.Pin(12), + PinDB5: rpio.Pin(16), // From 32 + PinDB6: rpio.Pin(20), // From 31 + PinDB7: rpio.Pin(13), // From 33 + + }), + + pinCS: rpio.Pin(19), + pinRES: rpio.Pin(21), + } + d.pinCS.Output() + d.pinRES.Output() + d.dev.Reset() + + return &d, nil +} + +func (d *mt12232a) Close() error { + return rpio.Close() +} + +func (d *mt12232a) SetPixel(x, y byte, c bool) error { + // var c8 byte + // var mask byte + + // Check bounds + if x > 127 || y > 63 { + return fmt.Errorf("positions out of bounds") + } + + if x < 64 { // Left crystal + d.WriteCodeL(0xB8 | (y >> 3)) // Set page + d.WriteCodeL(0x40 | x) // Set addr + // c8=ReadDataL(); // ?? ok + // c8=ReadDataL(); // Read byte + // m8=1<<(y&0x07);//Вычислить маску нужного бита в байте + // if (c==1) //Зажигать точку? + // c8|=m8//Установить нужный бит в байте + // else //Или гасить точку? + // c8&=~m8;//Сбросить нужный бит в байте + // WriteCodeL(0x40|x);//Снова установить адрес нужного байта + d.WriteDataL(0x34) // Write byte + } + return nil +} + +func (d *mt12232a) PowerOn() error { + d.logger.Println(d.ReadStatus(0)) // Should be 0 + d.logger.Println("Reset") + d.pinRES.Low() + time.Sleep(time.Microsecond) + d.logger.Println(d.ReadStatus(0)) // Should be 48 (power off and reset) + d.pinRES.High() + time.Sleep(10 * time.Microsecond) + d.logger.Println(d.ReadStatus(0)) // Should be 32 (power off) + + // Module is reset and should be turned off + if d.ReadStatus(0) == 0 || d.ReadStatus(1) == 0 { + return fmt.Errorf("no response from display(or it is possible that it is turned on but...)") + } + + d.logger.Println("Power on") + d.WriteCodeL(0xE2) // Reset + d.WriteCodeR(0xE2) // Reset + d.WriteCodeL(0xEE) // ReadModifyWrite off + d.WriteCodeR(0xEE) // ReadModifyWrite off + d.WriteCodeL(0xA4) // Turn on common mode + d.WriteCodeR(0xA4) // Turn on common mode + d.WriteCodeL(0xA9) // Multiplex 1/32 + d.WriteCodeR(0xA9) // Multiplex 1/32 + d.WriteCodeL(0xC0) // Top line to 0 + d.WriteCodeR(0xC0) // Top line to 0 + d.WriteCodeL(0xA1) // Invert scan RAM + d.WriteCodeR(0xA0) // NonInvert scan RAM + + d.logger.Println("Display on") + d.WriteCodeL(0xAF) // Display on + d.WriteCodeR(0xAF) // Display on + + // Check that crystals are turned on + if (d.ReadStatus(0) & (1 << 5)) != 0 { + return fmt.Errorf("Left cristal is still off") + } + if (d.ReadStatus(1) & (1 << 5)) != 0 { + return fmt.Errorf("Right cristal is still off") + } + + return nil +} + +// Write codes + +func (d *mt12232a) WriteCodeL(c byte) error { + return d.writeByte(c, 0, 0) +} + +func (d *mt12232a) WriteCodeR(c byte) error { + return d.writeByte(c, 0, 1) +} + +// Write data as byte + +func (d *mt12232a) WriteDataL(b byte) error { + return d.writeByte(b, 1, 0) +} + +func (d *mt12232a) WriteDataR(b byte) error { + return d.writeByte(b, 1, 1) +} + +// Read data + +func (d *mt12232a) ReadDataL() (byte, error) { + return d.readByte(1, 0) +} + +func (d *mt12232a) ReadDataR() (byte, error) { + return d.readByte(1, 1) +} + +// Low level functions + +func (d *mt12232a) writeByte(b byte, cd, cs rpio.State) error { + // d.logger.Println("Write byte", b, cd, l, r) + if err := d.waitReady(cs); err != nil { + return fmt.Errorf("wait ready: %w", err) + } + d.pinCS.Write(cs) // Select cristals + + d.dev.WriteByte(b, cd) + return nil +} + +func (d *mt12232a) readByte(cd, cs rpio.State) (byte, error) { + // Setup + if err := d.waitReady(cs); err != nil { + return 0, fmt.Errorf("wait ready: %w", err) + } + d.pinCS.Write(cs) // Select cristals + + return d.dev.ReadByte(cd), nil +} + +// Wait, checking status byte +func (d *mt12232a) waitReady(cs rpio.State) error { + d.pinCS.Write(cs) // Select cristals + return d.dev.WaitReady() +} + +func (d *mt12232a) ReadStatus(cs rpio.State) byte { + d.pinCS.Write(cs) // Select cristals + return d.dev.ReadByte(1) +} diff --git a/pkg/mt12864a/mt12864a.go b/pkg/mt12864a/mt12864a.go index 78c762b..0732b8f 100644 --- a/pkg/mt12864a/mt12864a.go +++ b/pkg/mt12864a/mt12864a.go @@ -6,31 +6,15 @@ import ( "log" "time" + "gitea.unprism.ru/yotia/display-test/pkg/parallel8bit" "github.com/stianeikeland/go-rpio/v4" ) -const ( - enablePrintPins = false - 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 + dev parallel8bit.Device + pinE1 rpio.Pin pinE2 rpio.Pin pinRES rpio.Pin @@ -57,34 +41,31 @@ func New(logger *log.Logger) (Device, error) { d := mt12864a{ logger: logger, - pinA0: rpio.Pin(18), - pinRW: rpio.Pin(17), - pinE: rpio.Pin(27), - pinDB0: rpio.Pin(22), - pinDB1: rpio.Pin(10), - pinDB2: rpio.Pin(9), // From 21 - pinDB3: rpio.Pin(11), - pinDB4: rpio.Pin(12), - pinDB5: rpio.Pin(16), // From 32 - pinDB6: rpio.Pin(20), // From 31 - pinDB7: rpio.Pin(13), // From 33 + dev: parallel8bit.New(logger, parallel8bit.DevicePins{ + PinA0: rpio.Pin(18), + PinRW: rpio.Pin(17), + PinE: rpio.Pin(27), - // 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), + PinDB0: rpio.Pin(22), + PinDB1: rpio.Pin(10), + PinDB2: rpio.Pin(9), // From 21 + PinDB3: rpio.Pin(11), + PinDB4: rpio.Pin(12), + PinDB5: rpio.Pin(16), // From 32 + PinDB6: rpio.Pin(20), // From 31 + PinDB7: rpio.Pin(13), // From 33 + + }), pinE1: rpio.Pin(19), pinE2: rpio.Pin(26), pinRES: rpio.Pin(21), } - d.AllOutput() + d.pinE1.Output() + d.pinE2.Output() + d.pinRES.Output() + d.dev.Reset() return &d, nil } @@ -121,7 +102,6 @@ func (d *mt12864a) SetPixel(x, y byte, c bool) error { func (d *mt12864a) PowerOn() error { d.logger.Println(d.ReadStatus(1, 0)) // Should be 0 d.logger.Println("Reset") - d.pinE.Low() d.pinRES.Low() time.Sleep(time.Microsecond) d.logger.Println(d.ReadStatus(1, 0)) // Should be 48 (power off and reset) @@ -135,7 +115,6 @@ func (d *mt12864a) PowerOn() error { } d.logger.Println("Power on") - d.PrintPins() d.logger.Println("Top line to 0") d.WriteCodeL(0xC0) // Top line to 0 d.WriteCodeR(0xC0) // Top line to 0 @@ -195,29 +174,10 @@ func (d *mt12864a) writeByte(b byte, cd, l, r rpio.State) error { if err := d.waitReady(l, r); err != nil { return fmt.Errorf("wait ready: %w", err) } - 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) + d.dev.WriteByte(b, cd) return nil } @@ -228,146 +188,24 @@ func (d *mt12864a) readByte(cd, l, r rpio.State) (byte, error) { } // Setup - var b byte if err := d.waitReady(l, r); err != nil { return 0, fmt.Errorf("wait ready: %w", err) } - 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, nil + return d.dev.ReadByte(cd), nil } // Wait, checking status byte func (d *mt12864a) waitReady(l, r rpio.State) error { - //d.logger.Println("Wait ready", l, r) - d.busInput() // Set bus to input - d.pinRW.High() // We read - d.pinA0.Low() // Status 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 - ok := false - d.busInput() // Set bus to input - for counter := 0; counter < maxWaitCycles; counter++ { - if d.pinDB7.Read() != rpio.High { - //d.logger.Printf("BUS:%d%d%d%d%d%d%d%d\n", d.pinDB0.Read(), d.pinDB1.Read(), d.pinDB2.Read(), d.pinDB3.Read(), d.pinDB4.Read(), d.pinDB5.Read(), d.pinDB6.Read(), d.pinDB7.Read()) - ok = true - break - } - } - if !ok { - return fmt.Errorf("busy timeout") - } - - // Strobe end - d.pinE.Low() - time.Sleep(time.Millisecond - dataStrobeTimeout - adressWriteTimeout) - // d.logger.Println("Ready") - return nil + return d.dev.WaitReady() } func (d *mt12864a) ReadStatus(l, r rpio.State) byte { - d.busInput() // Set bus to input - d.pinRW.High() // We read - d.pinA0.Low() // Status d.pinE1.Write(l) // Select cristals d.pinE2.Write(r) // Select cristals - time.Sleep(adressWriteTimeout) - // Strobe start - d.pinE.High() - time.Sleep(dataStrobeTimeout) - d.busInput() - - var b byte = 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) PrintPins() { - if !enablePrintPins { - return - } - 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() + return d.dev.ReadByte(1) } diff --git a/pkg/parallel8bit/parallel8bit.go b/pkg/parallel8bit/parallel8bit.go index 981d0c0..180b41c 100644 --- a/pkg/parallel8bit/parallel8bit.go +++ b/pkg/parallel8bit/parallel8bit.go @@ -16,6 +16,7 @@ const ( // Interface for MT displays (do not set cristals bits) type Device interface { + Reset() WriteByte(b byte, cd rpio.State) ReadByte(cd rpio.State) byte @@ -53,6 +54,15 @@ func New(logger *log.Logger, pins DevicePins) Device { } } +func (d *device) Reset() { + d.PinA0.Output() + d.PinRW.Output() + d.PinE.Output() + d.PinRES.Output() + d.busOutput() + d.PinE.Low() +} + func (d *device) WriteByte(b byte, cd rpio.State) { // d.logger.Println("Write byte", b, cd, l, r) d.busOutput()