package mt12864a import ( "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() 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(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() { // // } /* void Pset(byte x, byte y, bit c) {//Записать одну точку в индикатор (координата 0,0 в левом верхнем углу индикатора) byte c8;//Временное хранение считаного из индикатора байта byte m8;//Маска нужного бита в байте if ((x>127)||(y>63)) return;//Выход за пределы индикатора if (x<64) {//Выводить в левую половину индикатора WriteCodeL(0xB8|(y>>3));//Установить нужную страницу индикатора WriteCodeL(0x40|x);//Установить адрес нужного байта c8=ReadDataL();//Фиктивное чтение c8=ReadDataL();//Чтение нужного байта из индикатора m8=1<<(y&0x07);//Вычислить маску нужного бита в байте if (c==1) //Зажигать точку? c8|=m8//Установить нужный бит в байте else //Или гасить точку? c8&=~m8;//Сбросить нужный бит в байте WriteCodeL(0x40|x);//Снова установить адрес нужного байта WriteDataL(c8);//Записать изменённый байт обратно в индикатор } else {//Выводить в правую половину индикатора WriteCodeR(0xB8|(y>>3));//Установить нужную страницу индикатора WriteCodeR(0x40|(x-64));//Установить адрес нужного байта c8=ReadDataR();//Фиктивное чтение c8=ReadDataR();//Чтение нужного байта из индикатора m8=1<<(y&0x07);//Вычислить маску нужного бита в байте if (c==1) //Зажигать точку? c8|=m8//Установить нужный бит в байте else //Или гасить точку? c8&=~m8;//Сбросить нужный бит в байте WriteCodeR(0x40|(x-64));//Снова установить адрес нужного байта WriteDataR(c8);//Записать изменённый байт обратно в индикатор } } */ 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.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.waitReady(1, 0) d.waitReady(0, 1) d.WriteCodeR(0x3F) // Display on d.waitReady(1, 0) d.waitReady(0, 1) 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() 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) } 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() 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) } 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 { 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()) 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() { 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() }