Compare commits

..

2 Commits

Author SHA1 Message Date
Andrey Egorov
c6af2620e0 Add: mt12232a lib 2024-09-02 13:39:06 +03:00
Andrey Egorov
efb2447c84 Add: separated Parallel 8 bit lib 2024-09-02 13:11:36 +03:00
4 changed files with 444 additions and 227 deletions

View File

@ -32,7 +32,9 @@ func newMt12864a(logger *log.Logger) (Display, error) {
}
// Temp debug draw
d.logger.Println("Draw...")
d.test()
d.logger.Println("Draw finished")
return &d, nil
}
@ -105,19 +107,30 @@ func (d *displayMt12864a) test() {
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xFF,
},
}
_ = Logo128
for p := byte(0); p < 8; p++ {
d.dev.WriteCodeL(p | 0xB8)
d.logger.Println("Write")
d.dev.WriteCodeL(0xB8)
d.dev.WriteCodeL(0x40)
for c := 0; c < 64; c++ {
d.dev.WriteDataL(Logo128[p][c])
}
d.dev.WriteCodeR(p | 0xB8)
d.dev.WriteCodeR(0x40)
for c := 64; c < 128; c++ {
d.dev.WriteDataR(Logo128[p][c])
}
}
d.dev.WriteDataL(47)
d.logger.Println("Read")
// d.dev.WriteCodeL(0xB8)
d.dev.WriteCodeL(0x40)
d.logger.Println(d.dev.ReadDataL())
d.logger.Println(d.dev.ReadDataL())
// for p := byte(0); p < 8; p++ {
// d.dev.WriteCodeL(p | 0xB8)
// d.dev.WriteCodeL(0x40)
// for c := 0; c < 64; c++ {
// d.dev.WriteDataL(Logo128[p][c])
// }
// d.dev.WriteCodeR(p | 0xB8)
// d.dev.WriteCodeR(0x40)
// for c := 64; c < 128; c++ {
// d.dev.WriteDataR(Logo128[p][c])
// }
// }
}
func (d *displayMt12864a) GetBounds() image.Rectangle {

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
}
@ -119,38 +100,35 @@ func (d *mt12864a) SetPixel(x, y byte, c bool) error {
}
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.logger.Println(d.ReadStatus(1, 0)) // Should be 0
d.logger.Println("Reset")
d.pinRES.Low()
time.Sleep(time.Microsecond)
d.logger.Println(d.ReadStatus(1, 0)) // Should be 48 (power off and reset)
d.pinRES.High()
time.Sleep(10 * time.Microsecond)
d.logger.Println(d.ReadStatus(1, 0)) // Should be 32 (power off)
d.PrintPins()
// Module is reset and should be turned off
if d.ReadStatus(1, 0) == 0 || d.ReadStatus(0, 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.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()
// Check that crystals are turned on
if (d.ReadStatus(1, 0) & (1 << 5)) != 0 {
return fmt.Errorf("Left cristal is still off")
}
if (d.ReadStatus(0, 1) & (1 << 5)) != 0 {
return fmt.Errorf("Right cristal is still off")
}
return nil
}
@ -188,7 +166,7 @@ func (d *mt12864a) ReadDataR() (byte, error) {
// Low level functions
func (d *mt12864a) writeByte(b byte, cd, l, r rpio.State) error {
d.logger.Println("Write byte", b, cd, l, r)
// 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")
@ -196,37 +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()
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)
d.dev.WriteByte(b, cd)
return nil
}
@ -237,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

@ -0,0 +1,170 @@
package parallel8bit
import (
"fmt"
"log"
"time"
"github.com/stianeikeland/go-rpio/v4"
)
const (
adressWriteTimeout = 140 * time.Nanosecond
dataStrobeTimeout = 250 * time.Nanosecond // (Data transfer)
maxWaitCycles = 100
)
// Interface for MT displays (do not set cristals bits)
type Device interface {
Reset()
WriteByte(b byte, cd rpio.State)
ReadByte(cd rpio.State) byte
WaitReady() error
}
type DevicePins struct {
// 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 struct {
logger *log.Logger
DevicePins
}
func New(logger *log.Logger, pins DevicePins) Device {
return &device{
logger: logger,
DevicePins: pins,
}
}
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()
d.PinRW.Low() // We write
d.PinA0.Write(cd)
// 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 *device) ReadByte(cd rpio.State) byte {
// Setup
var b byte
d.busOutput()
d.PinRW.High() // We write
d.PinA0.Write(cd)
// 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 *device) WaitReady() error {
d.busInput() // Set bus to input
d.PinRW.High() // We read
d.PinA0.Low() // Status
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
}
// Set bus pins to output
func (d *device) 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 *device) 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()
}