package mt12864a import ( "fmt" "io" "log" "time" "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 pinE1 rpio.Pin pinE2 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(l, r rpio.State) byte io.Closer } func New(logger *log.Logger) (Device, error) { rpio.Open() 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 // 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(19), pinE2: rpio.Pin(26), pinRES: rpio.Pin(21), } d.AllOutput() return &d, nil } func (d *mt12864a) Close() error { return rpio.Close() } func (d *mt12864a) 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 *mt12864a) PowerOn() error { 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.logger.Println("All low ") d.PrintPins() d.logger.Println("Power on") d.pinE.Low() d.pinRES.Low() time.Sleep(time.Microsecond) d.pinRES.High() time.Sleep(10 * time.Microsecond) d.PrintPins() d.logger.Println("Top line to 0") d.WriteCodeL(0xC0) // Top line to 0 d.WriteCodeR(0xC0) // Top line to 0 d.PrintPins() d.logger.Println("Display on") d.WriteCodeL(0x3F) // Display on d.WriteCodeR(0x3F) // Display on d.PrintPins() return nil } // Write codes func (d *mt12864a) WriteCodeL(c byte) error { return d.writeByte(c, 0, 1, 0) } func (d *mt12864a) WriteCodeR(c byte) error { return d.writeByte(c, 0, 0, 1) } // Write data as byte func (d *mt12864a) WriteDataL(b byte) error { return d.writeByte(b, 1, 1, 0) } func (d *mt12864a) WriteDataR(b byte) error { return d.writeByte(b, 1, 0, 1) } // Read data func (d *mt12864a) ReadDataL() (byte, error) { return d.readByte(1, 1, 0) } func (d *mt12864a) ReadDataR() (byte, error) { return d.readByte(1, 0, 1) } // Low level functions func (d *mt12864a) writeByte(b byte, cd, l, r rpio.State) error { 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 fmt.Errorf("cannot write left and right at the same times") } 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() d.pinDB0.Low() d.pinDB1.Low() d.pinDB2.Low() d.pinDB3.Low() d.pinDB4.Low() d.pinDB5.Low() d.pinDB6.Low() d.pinDB7.Low() time.Sleep(time.Millisecond - dataStrobeTimeout - adressWriteTimeout) return nil } func (d *mt12864a) readByte(cd, l, r rpio.State) (byte, error) { if l == rpio.High && r == rpio.High { d.logger.Println("L and R are high!!!") return 0, fmt.Errorf("cannot ready left and right at the same time") } // 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 } // 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 } 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() }