Jaecko
30.08.2008, 21:29
Moin.
Bin gerade dabei, einige Routinen in Eigenarbeit für ein LCD (128x64, Klassiker von Pollin mit KS0108-kompatiblem Controller) zu erstellen.
Es gibt zwar schon ein paar fertige Routinen, nur möcht ich das ganze selbst von Grund auf erstellen, um genau zu wissen, was ich da eigentlich mach.
Im Anhang ist der bisherige Stand.
Das Testprogramm in der main.c soll vom Prinzip her das gleiche machen, wie die Funktion TG12864B_Fill(), nur dass eben jedes Pixel gezielt angesprochen werden kann.
Problem ist nun hier, dass die Fläche nach dem Test nicht durchgehend weiss ist, sondern am linken Rand jedes "Treibers" dieses Muster hier aufweist:
http://cihome.kilu.de/_forendaten/lcd01.jpg
Wobei dieses "Muster" erst während des Aufbaus entsteht; d.h. die erste Zeile wird durchgehend gesetzt. Sobald die 2. Zeile beginnt, wird das erste Pixel wieder gelöscht. Beginnt die 3. Zeile, rutscht das gelöschte Pixel aus der ersten Zeile eins weiter ... usw, bis am Ende eben dieses Muster entsteht.
Der Fehler müsste entweder irgendwo in ~_SetPixel() oder ~_Goto() sein. Nur seh ich ihn nicht. Evtl jemand von euch?
Hier die Codes:
main.c
int main (void)
{
ui8_t x=0;
ui8_t y=0;
TG12864B_Init();
for (y = 0; y < 64 ; y++)
for (x = 0; x < 128 ; x++)
{
{
TG12864B_SetPixel(x,y,1);
// _delay_ms(100);
}
}
while(1)
{
}
return(0);
}
tg12864b.c
#include "tg12864b.h"
stc_DisplayPosition DPos;
volatile ui8_t readdata = 0;
static inline void _delay4Cycles(ui16_t __count)
{
if (__count == 0)
{
__asm__ __volatile__("rjmp 1f\n 1:");
}
else
{
__asm__ __volatile__ (
"1: sbiw %0,1" "\n\t"
"brne 1b"
: "=w" (__count)
: "0" (__count)
);
}
}
#define delay(us) _delay4Cycles(((F_CPU / 4000)*us)/1000)
void TG12864B_Init(void)
{
// Prepare Timer 0, PWM Channel B
//TCCR0A = (1 << WGM00) | (1 << COM0B1);
//TCCR0B = (1 << CS00) | (1 << CS01);
//OCR0B = 0;
// Set Ports & Pins as Output
TG12864B_DATA_PORT = 0x00;
TG12864B_DATA_DDR = 0xFF;
// TG12864B_LIGHT_DDR |= (1 << TG12864B_LIGHT_PIN);
TG12864B_EN_PORT &=~ (1 << TG12864B_EN_PIN);
TG12864B_EN_DDR |= (1 << TG12864B_EN_PIN);
TG12864B_RW_PORT &=~ (1 << TG12864B_RW_PIN);
TG12864B_RW_DDR |= (1 << TG12864B_RW_PIN);
TG12864B_DI_PORT &=~ (1 << TG12864B_DI_PIN);
TG12864B_DI_DDR |= (1 << TG12864B_DI_PIN);
TG12864B_CS1_PORT &=~ (1 << TG12864B_CS1_PIN);
TG12864B_CS1_DDR |= (1 << TG12864B_CS1_PIN);
TG12864B_CS2_PORT &=~ (1 << TG12864B_CS2_PIN);
TG12864B_CS2_DDR |= (1 << TG12864B_CS2_PIN);
TG12864B_RST_PORT &=~ (1 << TG12864B_RST_PIN);
TG12864B_RST_DDR |= (1 << TG12864B_RST_PIN);
_delay_ms(10);
TG12864B_RST_PORT |= (1 << TG12864B_RST_PIN);
_delay_ms(10);
// Send commands for init
DPos.x = 0;
DPos.y = 0;
DPos.page = 0;
DPos.addr = 0;
DPos.driver = 0;
DPos.rel_y = 0;
TG12864B_SendCmd(TG12864B_ON, 1); // Power on both drivers
TG12864B_SendCmd(TG12864B_ON, 2); // Power on both drivers
TG12864B_SendCmd(TG12864B_DISP_START, 1); // Display start line = 0
TG12864B_SendCmd(TG12864B_DISP_START, 2); // Display start line = 0
TG12864B_Fill(0x00);
}
void TG12864B_SendCmd(ui8_t cmd, ui8_t driver)
{
switch(driver)
{
case 1:
TG12864B_CS2_PORT &=~ (1 << TG12864B_CS2_PIN); // Driver 2 Off
TG12864B_CS1_PORT |= (1 << TG12864B_CS1_PIN); // Driver 1 On
break;
case 2:
TG12864B_CS2_PORT |= (1 << TG12864B_CS2_PIN); // Driver 2 On
TG12864B_CS1_PORT &=~ (1 << TG12864B_CS1_PIN); // Driver 1 Off
break;
case 3:
TG12864B_CS1_PORT |= (1 << TG12864B_CS1_PIN); // Driver 1 On
TG12864B_CS2_PORT |= (1 << TG12864B_CS2_PIN); // Driver 2 On
break;
default:
TG12864B_CS1_PORT &=~ (1 << TG12864B_CS1_PIN); // Driver 1 Off
TG12864B_CS2_PORT &=~ (1 << TG12864B_CS2_PIN); // Driver 2 Off
break;
}
TG12864B_DI_PORT &=~ (1 << TG12864B_DI_PIN); // D/I = 0 = Instruction
TG12864B_RW_PORT &=~ (1 << TG12864B_RW_PIN); // R/W = 0 = Write
TG12864B_DATA_DDR = 0xFF; // Port = Output
TG12864B_DATA_PORT = cmd; // Set data
TG12864B_EN_Pulse(); // Enable Clock
TG12864B_DATA_PORT = 0x00; // Reset data port
}
void TG12864B_EN_Pulse(void)
{
TG12864B_EN_PORT |= (1 << TG12864B_EN_PIN);
delay(4);
TG12864B_EN_PORT &=~ (1 << TG12864B_EN_PIN);
delay(4);
}
void TG12864B_Fill(ui8_t pattern)
{
ui8_t add;
ui8_t page;
for (page = 0; page < 8 ; page++)
{
for (add = 0 ; add < 64 ; add++)
{
TG12864B_SendCmd(TG12864B_SET_ADD | add, 3);
TG12864B_SendCmd(TG12864B_SET_PAGE | page, 3);
TG12864B_SendDataRaw(pattern,3);
}
}
}
void TG12864B_SendDataRaw(ui8_t data, ui8_t driver)
{
switch(driver)
{
case 1:
TG12864B_CS2_PORT &=~ (1 << TG12864B_CS2_PIN); // Driver 2 Off
TG12864B_CS1_PORT |= (1 << TG12864B_CS1_PIN); // Driver 1 On
break;
case 2:
TG12864B_CS2_PORT |= (1 << TG12864B_CS2_PIN); // Driver 2 On
TG12864B_CS1_PORT &=~ (1 << TG12864B_CS1_PIN); // Driver 1 Off
break;
case 3:
TG12864B_CS1_PORT |= (1 << TG12864B_CS1_PIN); // Driver 1 On
TG12864B_CS2_PORT |= (1 << TG12864B_CS2_PIN); // Driver 2 On
break;
default:
TG12864B_CS1_PORT &=~ (1 << TG12864B_CS1_PIN); // Driver 1 Off
TG12864B_CS2_PORT &=~ (1 << TG12864B_CS2_PIN); // Driver 2 Off
break;
}
TG12864B_DI_PORT |= (1 << TG12864B_DI_PIN); // D/I = 1 = Data
TG12864B_RW_PORT &=~ (1 << TG12864B_RW_PIN); // R/W = 0 = Write
TG12864B_DATA_DDR = 0xFF; // Port = Output
TG12864B_DATA_PORT = data; // Set data
TG12864B_EN_Pulse(); // Enable Clock
TG12864B_DATA_PORT = 0x00; // Reset data port
}
void TG12864B_Goto(ui8_t x, ui8_t y)
{
DPos.x = x;
DPos.y = y;
// Check: coordinates are valid
if (x > 127) { x = 127; }
if (y > 63) { y = 63; }
// Calculate Coordinates:
// Get driver nr. & relative x coordinate (= address)
if ( x >= 128)
{
return;
}
if ( x < 64 )
{
DPos.driver = 1;
DPos.addr = x;
}
if (( x >= 64 ) && ( x < 128 ))
{
DPos.driver = 2;
DPos.addr = x - 64;
}
// Get Page:
/*
if (y < 8) {DPos.page = 0;}
if ((y >= 8) && (y < 16)) {DPos.page = 1;}
if ((y >= 16) && (y < 24)) {DPos.page = 2;}
if ((y >= 24) && (y < 32)) {DPos.page = 3;}
if ((y >= 32) && (y < 40)) {DPos.page = 4;}
if ((y >= 40) && (y < 48)) {DPos.page = 5;}
if ((y >= 48) && (y < 56)) {DPos.page = 6;}
if ((y >= 56) && (y < 64)) {DPos.page = 7;}
*/
DPos.page = floor(y / 8);
DPos.rel_y = (y-DPos.page*8);
//DPos.rel_y = y & 8;
}
ui8_t TG12864B_ReadData(void)
{
ui8_t data;
TG12864B_DATA_PORT = 0x00; // Data = 0
TG12864B_DATA_DDR = 0x00; // Data = Input
if (DPos.driver == 1)
{
TG12864B_CS2_PORT &=~ (1 << TG12864B_CS2_PIN); // Driver 2 Off
TG12864B_CS1_PORT |= (1 << TG12864B_CS1_PIN); // Driver 1 On
}
if (DPos.driver == 2)
{
TG12864B_CS1_PORT &=~ (1 << TG12864B_CS1_PIN); // Driver 1 Off
TG12864B_CS2_PORT |= (1 << TG12864B_CS2_PIN); // Driver 2 On
}
TG12864B_DI_PORT |= (1 << TG12864B_DI_PIN); // D/I = 1 = Data
TG12864B_RW_PORT |= (1 << TG12864B_RW_PIN); // R/W = 1 = Read
TG12864B_EN_PORT |= (1 << TG12864B_EN_PIN);
delay(10);
data = TG12864B_DATA_INPUT;
delay(10);
TG12864B_EN_PORT &=~ (1 << TG12864B_EN_PIN);
delay(10);
TG12864B_DATA_DDR = 0xFF; // Data = Output
return (data);
}
void TG12864B_SetPixel(ui8_t x, ui8_t y, ui8_t value)
{
TG12864B_Goto(x, y);
TG12864B_SendCmd(TG12864B_SET_ADD | DPos.addr, DPos.driver);
TG12864B_SendCmd(TG12864B_SET_PAGE | DPos.page, DPos.driver);
readdata = TG12864B_ReadData();
if (value == 0)
{
readdata &=~ (1 << DPos.rel_y);
}
else
{
readdata |= (1 << DPos.rel_y);
}
TG12864B_SendCmd(TG12864B_SET_ADD | DPos.addr, DPos.driver);
TG12864B_SendCmd(TG12864B_SET_PAGE | DPos.page, DPos.driver);
TG12864B_SendDataRaw(readdata, DPos.driver) ;
}
tg12864b.h
#ifndef _TG12864B_H_
#define _TG12864B_H_
#include <math.h>
#include <avr/io.h>
#include <util/delay.h>
#include "glob_defs.h"
#include "glob_type.h"
#define TG12864B_DATA_PORT PORTA
#define TG12864B_DATA_DDR DDRA
#define TG12864B_DATA_INPUT PINA
#define TG12864B_EN_PORT PORTD
#define TG12864B_EN_DDR DDRD
#define TG12864B_EN_PIN 4
#define TG12864B_RW_PORT PORTD
#define TG12864B_RW_DDR DDRD
#define TG12864B_RW_PIN 5
#define TG12864B_DI_PORT PORTD
#define TG12864B_DI_DDR DDRD
#define TG12864B_DI_PIN 6
#define TG12864B_CS1_PORT PORTB
#define TG12864B_CS1_DDR DDRB
#define TG12864B_CS1_PIN 2
#define TG12864B_CS2_PORT PORTB
#define TG12864B_CS2_DDR DDRB
#define TG12864B_CS2_PIN 3
#define TG12864B_RST_PORT PORTD
#define TG12864B_RST_DDR DDRD
#define TG12864B_RST_PIN 3
// Commands
#define TG12864B_ON 0x3F
#define TG12864B_OFF 0x3E
#define TG12864B_SET_ADD 0x40
#define TG12864B_SET_PAGE 0xB8
#define TG12864B_DISP_START 0xC0
#define INCREMENT_X 0
#define NO_INCREMENT_X 1
void TG12864B_Init(void);
void TG12864B_SendCmd(ui8_t cmd, ui8_t driver);
void TG12864B_SendDataRaw(ui8_t data, ui8_t driver);
void TG12864B_EN_Pulse(void);
void TG12864B_Fill(ui8_t pattern);
void TG12864B_Goto(ui8_t x, ui8_t y);
ui8_t TG12864B_ReadData(void);
void TG12864B_SetPixel(ui8_t x, ui8_t y, ui8_t value);
typedef struct {
ui8_t x;
ui8_t y;
ui8_t driver;
ui8_t addr;
ui8_t page;
ui8_t rel_y;
} stc_DisplayPosition;
#endif
mfG
Bin gerade dabei, einige Routinen in Eigenarbeit für ein LCD (128x64, Klassiker von Pollin mit KS0108-kompatiblem Controller) zu erstellen.
Es gibt zwar schon ein paar fertige Routinen, nur möcht ich das ganze selbst von Grund auf erstellen, um genau zu wissen, was ich da eigentlich mach.
Im Anhang ist der bisherige Stand.
Das Testprogramm in der main.c soll vom Prinzip her das gleiche machen, wie die Funktion TG12864B_Fill(), nur dass eben jedes Pixel gezielt angesprochen werden kann.
Problem ist nun hier, dass die Fläche nach dem Test nicht durchgehend weiss ist, sondern am linken Rand jedes "Treibers" dieses Muster hier aufweist:
http://cihome.kilu.de/_forendaten/lcd01.jpg
Wobei dieses "Muster" erst während des Aufbaus entsteht; d.h. die erste Zeile wird durchgehend gesetzt. Sobald die 2. Zeile beginnt, wird das erste Pixel wieder gelöscht. Beginnt die 3. Zeile, rutscht das gelöschte Pixel aus der ersten Zeile eins weiter ... usw, bis am Ende eben dieses Muster entsteht.
Der Fehler müsste entweder irgendwo in ~_SetPixel() oder ~_Goto() sein. Nur seh ich ihn nicht. Evtl jemand von euch?
Hier die Codes:
main.c
int main (void)
{
ui8_t x=0;
ui8_t y=0;
TG12864B_Init();
for (y = 0; y < 64 ; y++)
for (x = 0; x < 128 ; x++)
{
{
TG12864B_SetPixel(x,y,1);
// _delay_ms(100);
}
}
while(1)
{
}
return(0);
}
tg12864b.c
#include "tg12864b.h"
stc_DisplayPosition DPos;
volatile ui8_t readdata = 0;
static inline void _delay4Cycles(ui16_t __count)
{
if (__count == 0)
{
__asm__ __volatile__("rjmp 1f\n 1:");
}
else
{
__asm__ __volatile__ (
"1: sbiw %0,1" "\n\t"
"brne 1b"
: "=w" (__count)
: "0" (__count)
);
}
}
#define delay(us) _delay4Cycles(((F_CPU / 4000)*us)/1000)
void TG12864B_Init(void)
{
// Prepare Timer 0, PWM Channel B
//TCCR0A = (1 << WGM00) | (1 << COM0B1);
//TCCR0B = (1 << CS00) | (1 << CS01);
//OCR0B = 0;
// Set Ports & Pins as Output
TG12864B_DATA_PORT = 0x00;
TG12864B_DATA_DDR = 0xFF;
// TG12864B_LIGHT_DDR |= (1 << TG12864B_LIGHT_PIN);
TG12864B_EN_PORT &=~ (1 << TG12864B_EN_PIN);
TG12864B_EN_DDR |= (1 << TG12864B_EN_PIN);
TG12864B_RW_PORT &=~ (1 << TG12864B_RW_PIN);
TG12864B_RW_DDR |= (1 << TG12864B_RW_PIN);
TG12864B_DI_PORT &=~ (1 << TG12864B_DI_PIN);
TG12864B_DI_DDR |= (1 << TG12864B_DI_PIN);
TG12864B_CS1_PORT &=~ (1 << TG12864B_CS1_PIN);
TG12864B_CS1_DDR |= (1 << TG12864B_CS1_PIN);
TG12864B_CS2_PORT &=~ (1 << TG12864B_CS2_PIN);
TG12864B_CS2_DDR |= (1 << TG12864B_CS2_PIN);
TG12864B_RST_PORT &=~ (1 << TG12864B_RST_PIN);
TG12864B_RST_DDR |= (1 << TG12864B_RST_PIN);
_delay_ms(10);
TG12864B_RST_PORT |= (1 << TG12864B_RST_PIN);
_delay_ms(10);
// Send commands for init
DPos.x = 0;
DPos.y = 0;
DPos.page = 0;
DPos.addr = 0;
DPos.driver = 0;
DPos.rel_y = 0;
TG12864B_SendCmd(TG12864B_ON, 1); // Power on both drivers
TG12864B_SendCmd(TG12864B_ON, 2); // Power on both drivers
TG12864B_SendCmd(TG12864B_DISP_START, 1); // Display start line = 0
TG12864B_SendCmd(TG12864B_DISP_START, 2); // Display start line = 0
TG12864B_Fill(0x00);
}
void TG12864B_SendCmd(ui8_t cmd, ui8_t driver)
{
switch(driver)
{
case 1:
TG12864B_CS2_PORT &=~ (1 << TG12864B_CS2_PIN); // Driver 2 Off
TG12864B_CS1_PORT |= (1 << TG12864B_CS1_PIN); // Driver 1 On
break;
case 2:
TG12864B_CS2_PORT |= (1 << TG12864B_CS2_PIN); // Driver 2 On
TG12864B_CS1_PORT &=~ (1 << TG12864B_CS1_PIN); // Driver 1 Off
break;
case 3:
TG12864B_CS1_PORT |= (1 << TG12864B_CS1_PIN); // Driver 1 On
TG12864B_CS2_PORT |= (1 << TG12864B_CS2_PIN); // Driver 2 On
break;
default:
TG12864B_CS1_PORT &=~ (1 << TG12864B_CS1_PIN); // Driver 1 Off
TG12864B_CS2_PORT &=~ (1 << TG12864B_CS2_PIN); // Driver 2 Off
break;
}
TG12864B_DI_PORT &=~ (1 << TG12864B_DI_PIN); // D/I = 0 = Instruction
TG12864B_RW_PORT &=~ (1 << TG12864B_RW_PIN); // R/W = 0 = Write
TG12864B_DATA_DDR = 0xFF; // Port = Output
TG12864B_DATA_PORT = cmd; // Set data
TG12864B_EN_Pulse(); // Enable Clock
TG12864B_DATA_PORT = 0x00; // Reset data port
}
void TG12864B_EN_Pulse(void)
{
TG12864B_EN_PORT |= (1 << TG12864B_EN_PIN);
delay(4);
TG12864B_EN_PORT &=~ (1 << TG12864B_EN_PIN);
delay(4);
}
void TG12864B_Fill(ui8_t pattern)
{
ui8_t add;
ui8_t page;
for (page = 0; page < 8 ; page++)
{
for (add = 0 ; add < 64 ; add++)
{
TG12864B_SendCmd(TG12864B_SET_ADD | add, 3);
TG12864B_SendCmd(TG12864B_SET_PAGE | page, 3);
TG12864B_SendDataRaw(pattern,3);
}
}
}
void TG12864B_SendDataRaw(ui8_t data, ui8_t driver)
{
switch(driver)
{
case 1:
TG12864B_CS2_PORT &=~ (1 << TG12864B_CS2_PIN); // Driver 2 Off
TG12864B_CS1_PORT |= (1 << TG12864B_CS1_PIN); // Driver 1 On
break;
case 2:
TG12864B_CS2_PORT |= (1 << TG12864B_CS2_PIN); // Driver 2 On
TG12864B_CS1_PORT &=~ (1 << TG12864B_CS1_PIN); // Driver 1 Off
break;
case 3:
TG12864B_CS1_PORT |= (1 << TG12864B_CS1_PIN); // Driver 1 On
TG12864B_CS2_PORT |= (1 << TG12864B_CS2_PIN); // Driver 2 On
break;
default:
TG12864B_CS1_PORT &=~ (1 << TG12864B_CS1_PIN); // Driver 1 Off
TG12864B_CS2_PORT &=~ (1 << TG12864B_CS2_PIN); // Driver 2 Off
break;
}
TG12864B_DI_PORT |= (1 << TG12864B_DI_PIN); // D/I = 1 = Data
TG12864B_RW_PORT &=~ (1 << TG12864B_RW_PIN); // R/W = 0 = Write
TG12864B_DATA_DDR = 0xFF; // Port = Output
TG12864B_DATA_PORT = data; // Set data
TG12864B_EN_Pulse(); // Enable Clock
TG12864B_DATA_PORT = 0x00; // Reset data port
}
void TG12864B_Goto(ui8_t x, ui8_t y)
{
DPos.x = x;
DPos.y = y;
// Check: coordinates are valid
if (x > 127) { x = 127; }
if (y > 63) { y = 63; }
// Calculate Coordinates:
// Get driver nr. & relative x coordinate (= address)
if ( x >= 128)
{
return;
}
if ( x < 64 )
{
DPos.driver = 1;
DPos.addr = x;
}
if (( x >= 64 ) && ( x < 128 ))
{
DPos.driver = 2;
DPos.addr = x - 64;
}
// Get Page:
/*
if (y < 8) {DPos.page = 0;}
if ((y >= 8) && (y < 16)) {DPos.page = 1;}
if ((y >= 16) && (y < 24)) {DPos.page = 2;}
if ((y >= 24) && (y < 32)) {DPos.page = 3;}
if ((y >= 32) && (y < 40)) {DPos.page = 4;}
if ((y >= 40) && (y < 48)) {DPos.page = 5;}
if ((y >= 48) && (y < 56)) {DPos.page = 6;}
if ((y >= 56) && (y < 64)) {DPos.page = 7;}
*/
DPos.page = floor(y / 8);
DPos.rel_y = (y-DPos.page*8);
//DPos.rel_y = y & 8;
}
ui8_t TG12864B_ReadData(void)
{
ui8_t data;
TG12864B_DATA_PORT = 0x00; // Data = 0
TG12864B_DATA_DDR = 0x00; // Data = Input
if (DPos.driver == 1)
{
TG12864B_CS2_PORT &=~ (1 << TG12864B_CS2_PIN); // Driver 2 Off
TG12864B_CS1_PORT |= (1 << TG12864B_CS1_PIN); // Driver 1 On
}
if (DPos.driver == 2)
{
TG12864B_CS1_PORT &=~ (1 << TG12864B_CS1_PIN); // Driver 1 Off
TG12864B_CS2_PORT |= (1 << TG12864B_CS2_PIN); // Driver 2 On
}
TG12864B_DI_PORT |= (1 << TG12864B_DI_PIN); // D/I = 1 = Data
TG12864B_RW_PORT |= (1 << TG12864B_RW_PIN); // R/W = 1 = Read
TG12864B_EN_PORT |= (1 << TG12864B_EN_PIN);
delay(10);
data = TG12864B_DATA_INPUT;
delay(10);
TG12864B_EN_PORT &=~ (1 << TG12864B_EN_PIN);
delay(10);
TG12864B_DATA_DDR = 0xFF; // Data = Output
return (data);
}
void TG12864B_SetPixel(ui8_t x, ui8_t y, ui8_t value)
{
TG12864B_Goto(x, y);
TG12864B_SendCmd(TG12864B_SET_ADD | DPos.addr, DPos.driver);
TG12864B_SendCmd(TG12864B_SET_PAGE | DPos.page, DPos.driver);
readdata = TG12864B_ReadData();
if (value == 0)
{
readdata &=~ (1 << DPos.rel_y);
}
else
{
readdata |= (1 << DPos.rel_y);
}
TG12864B_SendCmd(TG12864B_SET_ADD | DPos.addr, DPos.driver);
TG12864B_SendCmd(TG12864B_SET_PAGE | DPos.page, DPos.driver);
TG12864B_SendDataRaw(readdata, DPos.driver) ;
}
tg12864b.h
#ifndef _TG12864B_H_
#define _TG12864B_H_
#include <math.h>
#include <avr/io.h>
#include <util/delay.h>
#include "glob_defs.h"
#include "glob_type.h"
#define TG12864B_DATA_PORT PORTA
#define TG12864B_DATA_DDR DDRA
#define TG12864B_DATA_INPUT PINA
#define TG12864B_EN_PORT PORTD
#define TG12864B_EN_DDR DDRD
#define TG12864B_EN_PIN 4
#define TG12864B_RW_PORT PORTD
#define TG12864B_RW_DDR DDRD
#define TG12864B_RW_PIN 5
#define TG12864B_DI_PORT PORTD
#define TG12864B_DI_DDR DDRD
#define TG12864B_DI_PIN 6
#define TG12864B_CS1_PORT PORTB
#define TG12864B_CS1_DDR DDRB
#define TG12864B_CS1_PIN 2
#define TG12864B_CS2_PORT PORTB
#define TG12864B_CS2_DDR DDRB
#define TG12864B_CS2_PIN 3
#define TG12864B_RST_PORT PORTD
#define TG12864B_RST_DDR DDRD
#define TG12864B_RST_PIN 3
// Commands
#define TG12864B_ON 0x3F
#define TG12864B_OFF 0x3E
#define TG12864B_SET_ADD 0x40
#define TG12864B_SET_PAGE 0xB8
#define TG12864B_DISP_START 0xC0
#define INCREMENT_X 0
#define NO_INCREMENT_X 1
void TG12864B_Init(void);
void TG12864B_SendCmd(ui8_t cmd, ui8_t driver);
void TG12864B_SendDataRaw(ui8_t data, ui8_t driver);
void TG12864B_EN_Pulse(void);
void TG12864B_Fill(ui8_t pattern);
void TG12864B_Goto(ui8_t x, ui8_t y);
ui8_t TG12864B_ReadData(void);
void TG12864B_SetPixel(ui8_t x, ui8_t y, ui8_t value);
typedef struct {
ui8_t x;
ui8_t y;
ui8_t driver;
ui8_t addr;
ui8_t page;
ui8_t rel_y;
} stc_DisplayPosition;
#endif
mfG