Add: mt12232a lib

This commit is contained in:
Andrey Egorov 2024-09-02 13:39:06 +03:00
parent efb2447c84
commit c6af2620e0
3 changed files with 240 additions and 187 deletions

205
pkg/mt12232a/mt12232a.go Normal file
View File

@ -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)
}

View File

@ -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)
}

View File

@ -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()