sharp LM085YB01T01 kijelző vezérlése.

Hogyha sikeresen O/PLED illetve hagyományos alfanumerikus - esetleg tán grafikus kijelzővel gyűlik meg a baja valakinek:)
Bearnie74
DrótVégénSzéndarab
Hozzászólások: 34
Csatlakozott: 2016. november 25. péntek, 7:10

sharp LM085YB01T01 kijelző vezérlése.

HozzászólásSzerző: Bearnie74 » 2016. december 4. vasárnap, 15:37

Sziasztok!

Már itt ott kérdeztem, de most jutottam olyan adatok birtokába, hogy össze kellene szedni a tudásunkat hozzá, hátha érdemleges eszköz lesz belőle.

A problémám:

A fenti cimben megnevezett kijelző vezérlése hogyan oldhtó meg arduinoval, akár plusz elektronikával is.

Amit konkrétan tudok már róla egy dataset. Ami képként van elmente, és ide szertném beszúrni.
Screenshot_2016-12-04-15-30-02.png


Ezek alapján mit hogyan kell kötni programozni?
Nincs meg a kellő jogosultságod a hozzászóláshoz csatolt állományok megtekintéséhez.
A microkontroler sok mindenre alkalmas. a Pc bármire amire meg tudod tanítani.

Avatar
winnerbt
Chipfüstölő
Hozzászólások: 862
Csatlakozott: 2007. március 25. vasárnap, 6:00
Tartózkodási hely: Kecskemét

Re: sharp LM085YB01T01 kijelző vezérlése.

HozzászólásSzerző: winnerbt » 2016. december 4. vasárnap, 16:24

Nézd meg a SED1330/35 és T6963 LCD vezérlők pdf-jét. Az IC-nek lesznek ilyen lábai, oda kell kötni (tehát normális, 4-bites üzemmódban működik).
Lehet, hogy más vezérlőt kell majd választanod, amelyik tudja (főleg a vízszintes) megfelelő felbontást. Igazából, így belegondolva, amelyik uC (ARM) tudja a 4-bites SPI-t kezelni mondjuk DMA-val, azzal elég könnyen megoldható lenne programból is. AVR-el ne reménykedj, nincs rá ideje (vagy csak erre).
SED esetében ha már látsz futkosó vonalakat (bekapcsoláskor auto-refress módba áll), akkor már csak a kb 1000 oldalas doksit kell átbányászni a megfelelő beállításokhoz.

Bearnie74
DrótVégénSzéndarab
Hozzászólások: 34
Csatlakozott: 2016. november 25. péntek, 7:10

Re: sharp LM085YB01T01 kijelző vezérlése.

HozzászólásSzerző: Bearnie74 » 2016. december 4. vasárnap, 17:54

Nem hangzik valami bizalomgerjesztően elsőre. De hosszas munkával ezek szerint lehet még belőle display.

A tapi padját az életre tudtam kelteni, vagyis odáig eljutottam vele, hogy az uno kiirja a port monitorra az érintési poziciót.

Mostmár csak a nyomkodni való képet kellene alá varázsolnom. :-(
A microkontroler sok mindenre alkalmas. a Pc bármire amire meg tudod tanítani.

Avatar
winnerbt
Chipfüstölő
Hozzászólások: 862
Csatlakozott: 2007. március 25. vasárnap, 6:00
Tartózkodási hely: Kecskemét

Re: sharp LM085YB01T01 kijelző vezérlése.

HozzászólásSzerző: winnerbt » 2016. december 4. vasárnap, 18:08

Nem olyan vészes, logikus a felépítése a vezérlőknek, a T6963 egyszerűbb, a SED kicsit macerásabb, mert tud layer-eket kezelni meg grafikus/karakteres dolgokat egyszerre. Viszont be kellene szerezned egy IC-s kispanelt (valaki gyártott SED1335-os kispaneleket, de nem találom) vagy törött kijelzőt, arról beköthető. Magában csak igen rövid ideig kapcsold be (és tapizd meg a csatlékokat, akkor beszalad valami adat), mert beég (-het), szóval pár másodperc. A vezérlőkhöz mindenképp kell külső SRAM (videoram), kivéve pl. SED13700. HE forumon valaki PICcel hajtott 512x64-es, ilyen buta kijelzőt, szerintem segít Neked. A touch-pad szerintem hétköznapi, azzal nem lesz gondod.

Bearnie74
DrótVégénSzéndarab
Hozzászólások: 34
Csatlakozott: 2016. november 25. péntek, 7:10

Re: sharp LM085YB01T01 kijelző vezérlése.

HozzászólásSzerző: Bearnie74 » 2016. december 5. hétfő, 6:11

Mitől éghet be a kijelző?

Ez egy fénymáxolóban volt. Ott elég sokat ment bekapcsolt állapotban uhyanazzal a képpel. De béégve nincs.

Vagy ezeknél mit jelent a beégés?
A microkontroler sok mindenre alkalmas. a Pc bármire amire meg tudod tanítani.

Avatar
Robert
Elektronbűvölő
Hozzászólások: 9737
Csatlakozott: 2005. december 9. péntek, 7:00
Tartózkodási hely: Budapest
Kapcsolat:

Re: sharp LM085YB01T01 kijelző vezérlése.

HozzászólásSzerző: Robert » 2016. december 5. hétfő, 6:29

Az LCD maga (azaz a folyadékkristály). Ezt nem 50-50% jellel hajtva a folyadékkristály bomlani kezd.
http://www.tavir.hu - a gazda :)

Avatar
winnerbt
Chipfüstölő
Hozzászólások: 862
Csatlakozott: 2007. március 25. vasárnap, 6:00
Tartózkodási hely: Kecskemét

Re: sharp LM085YB01T01 kijelző vezérlése.

HozzászólásSzerző: winnerbt » 2016. december 5. hétfő, 7:54

Keress rá a SED1180 pdf-re, kb 10 oldalon van egy általános kijelző felépítéséről rajz. Tehát van X meg Y meghajtó (blokkok), ezek végül is hosszú shiftregiszterek, ezek vezérlése megtalálható a leírásban. A rajzon van egy soktagú feszültségosztó, ennek feszültségeit kapcsolgatja a FRAME-jellel szinkronban magára a folyadékkristályra, tehát AC meghajtást igényel. A vezérlők ezért állnak be egy auto-refress módba mindenféle inicializálás nélkül, így egy aránylag lassú pásztázást lehet látni a kijelzőn, hogy ezek az AC görbék létrejöjjenek, ne károsodjon a DC-től az anyag. Szenvedések közben kb 10 másodperces DC (tehát egy csík beszalad és ott áll) kb 6 órán keresztül látszott még, szerencsére lassan helyrerázódik (ha szerencsénk van, ha nincs, akkor örökre ott marad). Alap dolog az LCD-nél, hogy a kristály meghajtása DC összetevőt nem tartalmazhat. (ami végül is téged nem annyira érdekel, mert a vezérlő majd megoldja, ha egyszer beindul) Sokaknak sikerült túlhajtott AVR-el meghajtani ilyen kijelzőket, keress rá "Driving controller-less graphical LCD" -re.

Bearnie74
DrótVégénSzéndarab
Hozzászólások: 34
Csatlakozott: 2016. november 25. péntek, 7:10

Re: sharp LM085YB01T01 kijelző vezérlése.

HozzászólásSzerző: Bearnie74 » 2016. december 5. hétfő, 10:19

Gondolkodtam rajta, hogy magából a fénymásolóból kivarázsolom a meghajtását is.

Elképzelésem szerint, magát a gombok képeit alap és benyomott állapot is egy memóriában tárolhatja. Meg gondolom azon a meghajtó ic is rajta kell legyen.

De mikor kibontottam magát az elektronikát, hát van rajta ki meg bemenő kanóc rendesen. Meg pár ic is. Igy szerintem nehézkes lesz kiszűrni melyik lehet a vezérlő ic je.

Itt a kép róla: vagyis csak lett volna, mert igy túl nagy. Majd otthon gépről felteszem, mert ott le tudom venni a méretét.
A microkontroler sok mindenre alkalmas. a Pc bármire amire meg tudod tanítani.

Bearnie74
DrótVégénSzéndarab
Hozzászólások: 34
Csatlakozott: 2016. november 25. péntek, 7:10

Re: sharp LM085YB01T01 kijelző vezérlése.

HozzászólásSzerző: Bearnie74 » 2016. december 11. vasárnap, 13:32

Itt vannak a képek a vezérlőjéről.

Maga az lcd még nincs feltölthető formában.
Nincs meg a kellő jogosultságod a hozzászóláshoz csatolt állományok megtekintéséhez.
A microkontroler sok mindenre alkalmas. a Pc bármire amire meg tudod tanítani.

Bearnie74
DrótVégénSzéndarab
Hozzászólások: 34
Csatlakozott: 2016. november 25. péntek, 7:10

Re: sharp LM085YB01T01 kijelző vezérlése.

HozzászólásSzerző: Bearnie74 » 2016. december 11. vasárnap, 13:35

Maga a vezárlő panel egyszer 24v ot meg 5 v ot kap a fénymásolótol egy szalagkábelen, amin még jön rá pár érzékelő jele, de az most nálunk nem számit.

Tapija lejön külön. Próbáltam életre kelteni, de még az se nagyon sikerűlt. A 4 vezetéket valószinű rosszul kötöm be. Vagy passz.
A microkontroler sok mindenre alkalmas. a Pc bármire amire meg tudod tanítani.

Avatar
kapu48
Elektronbűvölő
Hozzászólások: 3210
Csatlakozott: 2008. augusztus 29. péntek, 6:00
Tartózkodási hely: Újkígyós

Re: sharp LM085YB01T01 kijelző vezérlése.

HozzászólásSzerző: kapu48 » 2016. december 11. vasárnap, 14:58

A vezérlő megtartása jó ötletnek tűnik.

Olyan képek kellenének, amin látunk is valamit, ez nagyon csillog!
Nem olvasható, a középen lévő nagyobb IC típus száma?
Ha ahhoz találsz adatlapot? Még boldogulhatsz vele.

Egy ehhez hasonló házilagos megépítésén ne is álmodozzál!

vargham
Tranzisztorgyógyász
Hozzászólások: 150
Csatlakozott: 2014. január 8. szerda, 8:32
Kapcsolat:

Re: sharp LM085YB01T01 kijelző vezérlése.

HozzászólásSzerző: vargham » 2016. december 11. vasárnap, 19:02

NYÁK-ot úgy érdemes fotózni, hogy kikapcsolod a vakut, és leteszel mellé egy zseblámpát, ami oldalról világítja meg (súrlófény). Ha megtalálod a jó irányt, akkor az IC típusjelzése szinte kiugrik a képből.

Bearnie74
DrótVégénSzéndarab
Hozzászólások: 34
Csatlakozott: 2016. november 25. péntek, 7:10

Re: sharp LM085YB01T01 kijelző vezérlése.

HozzászólásSzerző: Bearnie74 » 2016. december 29. csütörtök, 13:28

Nos van már újabb fejlemény a sharp kijelzővel kapcsolatban.

Találtam egy oldalt, ahol a következők voltak leírva. Sajnos csak lengyelűl. (http://www.elektroda.pl/rtvforum/topic2686696.html)

Kód: Egész kijelölése

Atmega1284p podłaczenie do LCD:
PB0..PB3: Data bits 0..3
PD2: YSCL
PD3: M (AC)
PD4: LCD Enable
PD5: HSYNC
PD6: VSYNC
PD7: DOTCLOCK
PC1: ECL

PINOUTY:
1 – DSP_OFF10 – VDD5
2 – VSYNC11 – VDD4
3 – HSYNC12 – VDD3
4 – SFIC_K13 – VDD2
5 – +5VS14 – VDD1
6 – GND15 – VDD0
7 – N.C16 – VEE
8 – VDD717 – VLCD
9 – VDD618 – N.C



Meg 3 program kód is van, melyet próbálok az időhiányos szabadidőmben megfejteni.

1.:

// 640 x 1 x 200
// 4-bit parallel data interface.

#include <avr/io.h>
#include <stdlib.h>
#include <string.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <util/delay.h>

#include "./config.h"
#include "./clkisr.h"
#include "./util.h"

#define NIBBLEALIGN(px) if (1) {px = (px + 3) & 0xfffc;}   //align on next 4 bit boundary

// Clock Image Data
#include "./SharpClock.inc"

extern prog_uint8_t Font8x8[][8];
// SplashScreen 320 x 240
extern prog_uint8_t SplashScreen[];
//
#define max(a,b) ((a > b) ? a : b)
#define min(a,b) ((a < b) ? a : b)
//
#define COLORON      0b00000001
#define COLOROFF   0b00000000
//
// a cluster is the lowest common denominator of
// pixels and memory units (bytes/nibbles)
//
#if BITSPERPIXEL == 1
#define nClustersPerLine (nHorPixels / DATABITS)
#elif BITSPERPIXEL == 3
#define nClustersPerLine (nHorPixels / 8)
#endif

#define nLinesPerBar 20
#define CLOCKOFFSET 20         // such that the 200 x 200 Clock and the 80 x 60 picture are centered in the right side window

uint8 FrameBuffer[PHYS_LINES*BYTES_PER_LINE];
uint8 pwrup_state;
uint8 RefreshLine;
uint8 PDATA;
uint8 BDATA;
uint8 Vx, Vy, Vb;         //nibble address, row address, byte address
uint  Vpix;               //pixel address
uint8 ParseState, PrevParseCommand;
uint8 GlobalFault;
uint8 CommandTimeout;
uint  NoActivityTimeout;
uint8 SecsCountdown;
volatile uint8 SecsToAdd;
uint8 TimeSecs, TimeMins, TimeHrs;
uint8 fShowClock, fStartClock, fAutoClock;
uint  XStart, XEnd, XSize;         //current window limits
uint8 YStart, YEnd, YSize;
uint MaxPictureBytes;
// for Line Command
uint8 SavedArgs[9];
uint8 SavedIdx;
unsigned int BMByteCount;
#if EXTDEBUG
uint8 *pSTData;
unsigned long InCnt;
#endif

void LCDDemo(uint8 val);
void Serial_In (uint8 data);
void DrawTable(prog_uint8_t *Table, uint8 erase);

extern void InitMem(void);
#if DEBUG
uint8 ReadNibble(uint8 x, uint8 y)   __attribute__ ((noinline));
void WriteNibble(uint8 val, uint8 x, uint8 y)   __attribute__ ((noinline));
#else
uint8 ReadNibble(uint8 x, uint8 y);
void WriteNibble(uint8 val, uint8 x, uint8 y);
#endif
void SetPixel(uint8 color, uint x, uint8 y);
void PutChar(uint8 ch);

#if DEBUG
void MemoryScanNonZero(uint8 y);
#endif

void Parse(uint8 inByte);

void __attribute__ ((naked, section (".init1")))   // called before .do_copy_data_start
SetMem_init (void)
{
   InitMem();
}

// __heap_start is defined in the linker script
extern uint8_t __heap_start;

#if DEBUG
//       Check for 0xcc (in DEBUG mode) as set by SetMem();
uint16_t
GetMemUnused (void)
{
   uint16_t unused = 0;
   
    // Get end of static allocated RAM space (.data, .bss, .noinit, ...)
   uint8_t *p = &__heap_start;
   
   do
   {
        // Value written in InitMem() still intact?
      if (*p++ != 0xcc)
         break;
         
      unused++;
   } while (p <= (uint8_t *) RAMEND);

   return unused;
}
#endif

void foo(void)
{
   do {
      asm volatile (
         "nop   \n\t"
      );
   } while (1);
}
//
// Enable debug led
//
void InitDebug(void)
{
#if USE_LED
   LED_OFF;
   sbi(LED_DDR,LED_BIT);         //output
#endif
   LED2_OFF;
   sbi(LED2_DDR,LED2_BIT);         //output
}

const char DiagStr0[] PROGMEM = "DebugL0 ";
const char DiagStr1[] PROGMEM = "\n\rDebugL1: 0x";
const char DiagStr2[] PROGMEM = "DebugL2\n\r";
const char DiagStr3[] PROGMEM = "DebugL3\n\r";
const char DiagStr4[] PROGMEM = "DebugL4\n\r";
const char DiagStr5[] PROGMEM = "DebugL5\n\r";

void DebugL0(uint8 err)  __attribute__ ((noinline));
void DebugL0(uint8 err)
{
   UARTPrintfProgStr_I((prog_char*)DiagStr0);
   Printfuint8(err);
   PrintfEndOfLine();
   FlashLed(5, 1);
}

void DebugL1(void)
{
   UARTPrintfProgStr_I((prog_char*)DiagStr1);
#if 0
   // Move this to ClkIsr.c
   uint8 *ptr;
   Printfu16((int)TailPtr);
   UARTSendByte(' ', FALSE);
   FlashLed(10, 1);
   //
   // now print last 32 bytes from input queue
   //
   for (int i = 32; i >= 1; --i) {
      ptr = (uint8 *)(TailPtr - i);
      if (ptr < &RxBuffer[0]) ptr += RXSIZE;
      Printfuint8(*ptr);
      UARTSendByte(' ', FALSE);
   }
#endif
   PrintfEndOfLine();
}

void DebugL2(void)
{
   UARTPrintfProgStr_I((prog_char*)DiagStr2);
   FlashLed(10, 2);
}

void DebugL3(void)
{
   UARTPrintfProgStr_I((prog_char*)DiagStr3);
   FlashLed(10, 3);
}

void DebugL4(void)
{
   UARTPrintfProgStr_I((prog_char*)DiagStr4);
   FlashLed(10, 4);
}

void DebugL5(void)
{
   UARTPrintfProgStr_I((prog_char*)DiagStr5);
   FlashLed(10, 5);
}
//
// TC0 is used to do the LCD Screen Refresh
//
// Initialize TC0
// Set prescaler to clkio/64. At 20 Mhz, this is 3.2 uSec
// Using a Timer0CountUp value of 52 yields an match every 166.4 uSec.
// resulting in a refresh rate of 60 (60 x 100 = 6,000 Hz -> 166.66 uSec)
// 60Hz refresh rate shows no visible flicker, a little flicker on video.
//
// Processing time per line: 89 uSec (1/3/2011),
// meaning the LCD refresh load is 53%. At this load, the AVR has no
// trouble processing a 115,200 bps serial stream (plus there is flow control)
//
// The refresh rate can be reduced to 50 Hz and there still is no visible flicker.
//
#if F_CPU==20000000UL
#define Timer0CountUp 52      //62 for 50 Hz.
#else
error: F_CPU undefined
#endif

void InitTC0(void)
{
   TCCR0A = _BV(WGM01);         // run timer in CTC mode
   TCCR0B = (0<<CS02)|_BV(CS01)|_BV(CS00);
   OCR0A = Timer0CountUp;
}

void EnableTC0(void)
{
   TIFR0 = _BV(OCF0A);            //clear pending match
   TIMSK0 = _BV(OCIE0A);         //Enable TC0.match
}

//
// Timer1 is setup in util.c but calls the application
// specific function "AppTimer1Stuff"
//
void AppTimer1Stuff(void)
{
   if (--SecsCountdown == 0) {
      SecsCountdown = 10;
      ++SecsToAdd;
   }
   if (CommandTimeout != 0) {
      if (--CommandTimeout == 0) {
         // Command Time out. Reset State Machine
         ParseState = STANDBY;
      }
   }
   if (NoActivityTimeout != 0) {
      if (--NoActivityTimeout == 0) {
         // No Activity Timeout. Start Clock
         // Ought to save current image, then clrscreen first
         fStartClock = TRUE;
         fAutoClock = TRUE;
      }
   }
}

void InitDebug(void);

void InitCtrl(void)
{
//
// I/O PORTS INITIALIZATION
//
    SRAMDATA_DDR = SRAMDATA_MASK;   //data port defaults to output


   cbi(LCD_YSCL, YSCL_BIT);      //active High
   cbi(LCD_ENABLE, ENABLE_BIT);   //disable LCD
   cbi(LCD_HSYNC, HSYNC_BIT);      //active High
   cbi(LCD_VSYNC, VSYNC_BIT);      //active High
   cbi(DOTCLK, DOTCLK_BIT);      //active on falling edge
   cbi(LCD_ECL, ECL_BIT);         //active High

   sbi(YSCL_DDR, YSCL_BIT);
   sbi(LCDM_DDR, M_BIT);
   sbi(ENABLE_DDR, ENABLE_BIT);
   sbi(HSYNC_DDR, HSYNC_BIT);
   sbi(VSYNC_DDR, VSYNC_BIT);
   sbi(DOTCLK_DDR, DOTCLK_BIT);
   sbi(ECL_DDR, ECL_BIT);

#if DEBUG
   cbi(MCU_TEST, MCU_TEST_BIT);
   sbi(MCU_TEST_DDR, MCU_TEST_BIT);
#endif
//
// Disable unused parts of the AVR to reduce power consumption
//
// unused TWI, ADC, TIM2, SPI
//
// Reserve TIM1 for inByte timeout
//
   PRR0 = _BV(PRTWI) | _BV(PRADC) | _BV(PRTIM2) | _BV(PRSPI);

   InitTC0();               //LCD refresh timer
   InitTC1();               //Timeout/Led
   InitDebug();
//
// VARIABLES INITIALIZATION
//
   XStart = 0;
   XEnd = nHorPixels - 1;
   XSize = XEnd - XStart + 1;
   YStart = 0;
   YEnd = nLines - 1;
   YSize = YEnd - YStart + 1;
   MaxPictureBytes  = (YSize * (XSize / 8));

   RefreshLine = 0;         //LCD Line being displayed
   pwrup_state = 0;
   ParseState = 0;            //GrState = STANDBY
   PrevParseCommand = 0;         //nothing
   PDATA = COLORON;
   BDATA = COLOROFF;
   Vpix = Vx = Vy = 0;
   GlobalFault = 0;
   SecsCountdown = 10;
   SecsToAdd = 0;
   CommandTimeout = 0;
   NoActivityTimeout = NOACTIVITY;
#if EXTDEBUG
   pSTData = FrameBuffer;
   InCnt = 0;
#endif
}
//
// WriteNibble:   write a nibble to SRam.
//
// IN:   r24:nibble   r22 x-address   r20 y-address
//
void WriteNibble(uint8 nibble, uint8 x, uint8 y)
{
   uint8 b, *p;
   uint x0 = x;
   ASSERT(x < LOG_NIBBLES_PER_LINE);
   if (x >= LOG_NIBBLES_PER_LINE) {
      x = LOG_NIBBLES_PER_LINE - 1;
   }
   ASSERT(y < LOG_MAX_LINES);
   if (y >= LOG_MAX_LINES) {
      y = LOG_MAX_LINES - 1;
   }
   if (y >= PHYS_LINES) {
      y -= PHYS_LINES;
      x0 += LOG_NIBBLES_PER_LINE;
   }
   p = &FrameBuffer[(y * BYTES_PER_LINE) + (x0 >> 1)];
   b = *p;
   if (x & 1) {
      b = (nibble & 0x0f) | (b & 0xf0);
   } else {
      b = (nibble << 4) | (b & 0x0f);
   }
   *p = b;
}

//
// WriteByte:   write a byte to SRam.
//
// IN:   r24:byte   r22 x-address (in bytes)   r20 y-address
//
void WriteByte(uint8 b, uint8 x, uint8 y)
{
   ASSERT(x < LOG_NIBBLES_PER_LINE / 2);
   if (x >= (LOG_NIBBLES_PER_LINE /2)) {
      x = (LOG_NIBBLES_PER_LINE / 2) - 1;
   }
   ASSERT(y < LOG_MAX_LINES);
   if (y >= LOG_MAX_LINES) {
      y = LOG_MAX_LINES - 1;
   }
   if (y >= PHYS_LINES) {
      y -= PHYS_LINES;
      x += (LOG_NIBBLES_PER_LINE / 2);
   }
   FrameBuffer[(y * BYTES_PER_LINE) + x] = b;
}

uint8 ReadNibble(uint8 x, uint8 y)
{
   uint8 b;
   uint x0 = x;
   ASSERT(x < LOG_NIBBLES_PER_LINE);
   if (x >= LOG_NIBBLES_PER_LINE) {
      x = LOG_NIBBLES_PER_LINE - 1;
   }
   ASSERT(y < LOG_MAX_LINES);
   if (y >= LOG_MAX_LINES) {
      y = LOG_MAX_LINES - 1;
   }
   if (y >= PHYS_LINES) {
      y -= PHYS_LINES;
      x0 += LOG_NIBBLES_PER_LINE;
   }
   b = FrameBuffer[(y * BYTES_PER_LINE) + (x0 >> 1)];
   if (x & 1) {
      return (b & 0x0f);
   } else {
      return (b >> 4);
   }
}
//
// Write a character at the current pixel location.
// May not wrap Vpix and Vy properly.
// SED
//
void PutChar(uint8 ch)
{
   uint8   i,FontLine,px;
   prog_uint8_t *pCode;
   NIBBLEALIGN(Vpix);
   if ((Vpix + 8) > nHorPixels) {         // char won't fit on current line
      Vpix = 0;
      Vy += 8;                     // Line overflow check next
   }
   if ((Vy + 8) > nLines) {            // char won't fit on screen
      Vy = 0;
   }
   if (((uint8)Vpix & 0x07) != 0) {      // not byte aligned
      px = (Vpix >> 2);               // Convert to nibble
      //
      // write One Line at a time
      for (i = 0; i < 8; i++) {
         pCode = &(Font8x8[ch][i]);
         FontLine = __LPM(pCode);
         WriteNibble(FontLine >> 4, px, Vy+i);
         WriteNibble(FontLine & 0x0f, px+1, Vy+i);
      }
   } else {                        // Vpix is byte aligned
      px = (Vpix >> 3);               // Convert to byte
      //
      // write One Line at a time
      for (i = 0; i < 8; i++) {
         pCode = &(Font8x8[ch][i]);
         FontLine = __LPM(pCode);
         WriteByte(FontLine, px, Vy+i);
      }
   }
   Vpix += 8;
}

byte MaskTbl[4] PROGMEM = {
   8, 4, 2, 1
};

//
// Set Pixel at location x, y to color
// TODO use 4 byte table to compute bitmask
//
void SetPixel(uint8 color, uint x, uint8 y)
{
   uint8 v, offset, bitmask, px;
   x = min(x, nHorPixels - 1);
   y = min(y, nLines - 1);
   px = (x >> 2);            //enclosing nibble
   v = ReadNibble(px, y);
   offset = x & 0x03;
   bitmask = __LPM(&MaskTbl[offset]);
   v &= ~bitmask;      //clear pixel
   if (color) {
      v |= bitmask;
   }
   WriteNibble(v, px, y);
}
//
// Bresenham line drawing
//
void DrawLine(uint x0, uint y0, uint x1, uint y1)
{
   uint steep, tmp;
   u32 x, y;
   s16 ystep;
   int deltax, deltay, error;

#if DEBUG
   if ((x0 >= nHorPixels) || (x1 >= nHorPixels) || (y0 >= nLines) || (y1 >= nLines)) return;
#endif

   steep = (abs(y1 - y0) > abs (x1 - x0));
   if (steep) {
      tmp = x0; x0 = y0; y0 = tmp;      //  swap(x0, y0)
      tmp = x1; x1 = y1; y1 = tmp;        //  swap(x1, y1)
   }
    if (x0 > x1) {
      tmp = x0; x0 = x1; x1 = tmp;      // swap(x0, x1)
      tmp = y0; y0 = y1; y1 = tmp;      // swap(y0, y1)
   }
   deltax = x1 - x0;
   deltay = abs(y1 - y0);
   error = 0;
   y = y0;
   if (y0 < y1) ystep = 1;
   else ystep = -1;
   for (x = x0; x <= x1; x++) {
      if (steep) SetPixel(PDATA, y, x);
      else SetPixel(PDATA, x, y);
      error += deltay;
      if ((error * 2) >= deltax) {
         y += ystep;
         error -= deltax;
      }
   }
}

//
// Bresenham circle drawing
//
void DrawCircle(unsigned int cx, unsigned int cy ,unsigned int radius)
{
   int x, y, xchange, ychange, radiusError;
   x = radius;
   y = 0;
   xchange = 1 - 2 * radius;
   ychange = 1;
   radiusError = 0;
   while(x >= y) {
     SetPixel(PDATA, cx+x, cy+y );
     SetPixel(PDATA, cx-x, cy+y );
     SetPixel(PDATA, cx-x, cy-y );
     SetPixel(PDATA, cx+x, cy-y );
     SetPixel(PDATA, cx+y, cy+x );
     SetPixel(PDATA, cx-y, cy+x );
     SetPixel(PDATA, cx-y, cy-x );
     SetPixel(PDATA, cx+y, cy-x );
     y++;
     radiusError += ychange;
     ychange += 2;
     if ( 2*radiusError + xchange > 0 ) {
       x--;
      radiusError += xchange;
      xchange += 2;
      }
   }
}

void DrawTable(prog_uint8_t *Table, uint8 erase)
{
   prog_uint8_t *pCode = Table;
   uint8 x0,y0,x1,y1;
   uint8 SavedColor = PDATA;

   if (erase) {
      PDATA = BDATA;
   }

   do {
      while ((x0 = __LPM(pCode)) == 0) {      //skip leading 0 bytes
         ++pCode;
      }
      ++pCode;
      ASSERT (x0 != 0);
      y0 = min(lastLine, __LPM(pCode));
      y0 = lastLine-y0;                  //invert Y
      ++pCode;
      do {
         x1 = __LPM(pCode);
         ++pCode;
         if (0 == x1) break;            //move to next coordinate pair
         if (0xff == x1) {            //end of coordinate pairs
            if (erase) {
               BDATA = PDATA;
               PDATA = SavedColor;
            }
            return;
         }
         y1 = min(lastLine, __LPM(pCode));
         y1 = lastLine-y1;                  //invert Y
         ++pCode;
         DrawLine(x0 + CLOCKOFFSET, y0, x1 + CLOCKOFFSET, y1);
         x0 = x1;
         y0 = y1;
      } while (1);
   } while (1);

   if (erase) {
      BDATA = PDATA;
      PDATA = SavedColor;
   }
}

void DrawSecsHand(uint8 sec, uint8 erase)
{
   if (sec >= 60)
      return;

   DrawTable(&SecPtrData[sec * 5], erase);
}

void DrawMinsHand(uint8 min, uint8 erase)
{
   if (min >= 60)
      return;

   DrawTable(&MinPtrData[min * 9], erase);
}

void DrawHrsHand(uint8 hr, uint8 erase)
{
   if (hr >= 12)
      return;

   DrawTable(&HrPtrData[hr * 45], erase);
}

void UpdateTime(void)
{
   while (SecsToAdd > 0) {
      --SecsToAdd;
      if (fShowClock) {
         DrawSecsHand(TimeSecs, TRUE);         //erase current seconds hand
      }
      ++TimeSecs;
      if (TimeSecs >= 60) {
         if (fShowClock) {
            DrawMinsHand(TimeMins, TRUE);      //erase current minutes hand
         }
         TimeSecs = 0;
         ++TimeMins;
         if (TimeMins >= 60) {
            if (fShowClock) {
               DrawHrsHand(TimeHrs, TRUE);      //erase current hours hand
            }
            TimeMins = 0;
            ++TimeHrs;
            if (TimeHrs >= 12) {
               TimeHrs = 0;
            }
         }
      }
      if (fShowClock) {
         DrawTable(DialDigits12, FALSE);
         DrawSecsHand(TimeSecs, FALSE);
         DrawMinsHand(TimeMins, FALSE);
         DrawHrsHand(TimeHrs, FALSE);
      }
   }
}

void StartClock(void)
{
   fStartClock = FALSE;
   fShowClock = TRUE;
   DrawTable(DialData, FALSE);
   DrawTable(DialDigits12, FALSE);
   DrawSecsHand(TimeSecs, FALSE);
   DrawMinsHand(TimeMins, FALSE);
   DrawHrsHand(TimeHrs, FALSE);
}

void StopClock(void)
{
   DrawTable(DialData, TRUE);
   DrawTable(DialDigits12, TRUE);
   DrawSecsHand(TimeSecs, TRUE);
   DrawMinsHand(TimeMins, TRUE);
   DrawHrsHand(TimeHrs, TRUE);
   fShowClock = FALSE;
   fAutoClock = FALSE;
}

uint8 PrepareNibble(uint8 color)
{
#if DEBUG
   color &= 0x01;
#endif
   return (color) ? 0b00001111 : 0;
}
//
// set screen area to color. Set BDATA, Vx, Vy, Vpix
//
void SetScreenX(uint8 color, uint x0, uint8 y0, uint x1, uint8 y1)
{
   uint8 nibble, x, y;
//
// convert pixel address X0 to nibble boundary
// align starting pixel to next nibble boundary
// align ending pixel to previous nibble boundary
//
   NIBBLEALIGN(x0);
   x1 = (x1 + 0) & 0xfffc;

   nibble = PrepareNibble(color);
   for (y = y0; y <= y1; ++y) {      // Top to Bottom
      for (x = (x0 >> 2) ; x <= (x1 >> 2); ++x) {
         WriteNibble(nibble, x, y);
      }
   }
   BDATA = color;                  //set color as background color
   Vy = y0;
   Vx = (x0 >> 2);
   Vpix = (Vx << 2);
}

//
// set screen to color. Set BDATA, Vx, Vy, Vpix
//
// Optimization: could to a memset on the FrameBuffer!
//
void SetScreen(uint8 color)
{
   uint8 v, x, y;
#if DEBUG
   color &= 0x01;
#endif
   v = (color) ? 0b11111111 : 0;
   for (y = 0; y < nLines; ++y) {      // Top to Bottom
      for (x = 0 ; x < (LOG_NIBBLES_PER_LINE / 2); ++x) {
         WriteByte(v, x, y);
      }
   }
   BDATA = color;                  //set color as background color
   Vy = Vx = Vpix = 0;
}

#if DEBUG
//
// Draw a line using argument color. Starting at current Vy
// Use WriteNibble()
//
void HorizontalLine(uint8 color)
{
   uint8 x, nibble;
   nibble = PrepareNibble(color);
   for (x = 0; x < nColumnsPerLine; ++x) {
      WriteNibble(nibble, x, Vy);
   }
}

//
// Draw a line using argument color. Starting at current Vy.
// Use SetPixel
//
void HorizontalPixelLine(uint8 color)
{
   PDATA = color;
   uint px;
   for (px = 0; px < (nHorPixels/16); ++px) {
      SetPixel(color, px, Vy);
   }
}
#endif

//
// Draw a bar using argument color. Starting at current Vy
//
void HorizontalBar(uint8 color)
{
   uint8 i, x, nibble;
   i = nLinesPerBar;         //number of lines
   nibble = PrepareNibble(color);
   do {
      for (x = 0; x < nColumnsPerLine; ++x) {
         WriteNibble(nibble, x, Vy);
      }
      ++Vy;
   } while (--i);
   Vx = 0;
}
//   
// horizontal test bars.
//
void HorizontalTest(void)
{
   uint8 i;
   Vy = 0;
   for (i = 0; i < (nLines/(2 * nLinesPerBar)); ++i) {      //as many as will fit
      HorizontalBar(COLORON);
      HorizontalBar(COLOROFF);
   }
#if DEBUG
   if (Vy != nLines) {
      DebugL0(LCDERROR0);
   }
#endif
   Vx = Vy = 0;
}
//
//  compare data with PDATA
//
void VerifyNibble(uint8 data)
{
   // bit 0: D0 .. bit 3: D0
   if ((data & 0x01) != PDATA) DebugL0(LCDERROR0);
   data >>= 1;
   if ((data & 0x01) != PDATA) DebugL0(LCDERROR0);
   data >>= 1;
   if ((data & 0x01) != PDATA) DebugL0(LCDERROR0);
   data >>= 1;
   if ((data & 0x01) != PDATA) DebugL0(LCDERROR0);
}

void VerifyHorizontalLine(void)
{
   uint8 nibble, i = nClustersPerLine;
   Vx = 0;
   do {
      nibble = ReadNibble(Vx, Vy);
      ++Vx;
      VerifyNibble(nibble);      //compare with PDATA
   } while (--i);
}
//
// argument: expected color
//
void VerifyHorizontalBar(uint8 color)
{
   uint8 i = nLinesPerBar;
   PDATA = color;         //save
   do {
      VerifyHorizontalLine();
      ++Vy;
   } while (--i);
}

void VerifyHorizontalTest()
{
   Vy = 0;
   for (uint8 i = 0; i < (nLines/(2 * nLinesPerBar)); ++i) {      //as many as will fit
      VerifyHorizontalBar(COLORON);
      VerifyHorizontalBar(COLOROFF);
   }
   Vx = Vy = 0;            //reset
   Vpix = 0;
}
//
// VerticalTest: draw vertical bars
//
void VerticalTest()
{
   uint8 color, i, nibble, x, y;
   for (y = 0; y < nLines; ++y) {
      x = 0;
      color = COLOROFF;      //color
      for (i = 0; i < (nColumnsPerLine >> 1); ++i) {
         if (++color > COLORON) {   //next color
            color = COLOROFF;
         }
         nibble = PrepareNibble(color);   //set from PDATA
         WriteNibble(nibble, x, y);
         WriteNibble(nibble, x+1, y);
         x += 2;
      }
   }
   Vx = Vy = 0;            //reset
   Vpix = 0;
}

//
// HorVertTest: draw clusters
//
void HorVertTest()
{
   uint8 i, j, color0, color, nibble, x, y;
   color0 = COLOROFF;            //start color
   for (y = 0; y < nLines;) {
      if (++color0 > COLORON) {   //next color
         color0 = COLOROFF;
      }
      color = color0;
      for (j = 0; j < 8; ++j) {      //nr of lines per block
         x = 0;
         for (i = 0; i < (nColumnsPerLine >> 1); ++i) {
            nibble = PrepareNibble(color);   //set  from PDATA
            WriteNibble(nibble, x, y);
            WriteNibble(nibble, x+1, y);
            x += 2;
            if (++color > COLORON) {   //next color
               color = COLOROFF;
            }
         }
         ++y;
      }
   }
   Vx = Vy = 0;         //reset
   Vpix = 0;
}
//
// Draw horizontal bars slowly.
//
void SlowHorizontalBars(void)
{
   uint8 i;
   Vy = 0;
   for (i = 0; i < (nLines/(2 * nLinesPerBar)); ++i) {      //as many as will fit
      HorizontalBar(COLORON);
      HorizontalBar(COLOROFF);
      delayOneSecond();
   }
   Vx = 0;
   Vy = 0;
}
//
// Select a demo. All delays done by sender
//
void LCDDemo(uint8 val)
{
   if (val == 1) {
      HorizontalTest();
      VerifyHorizontalTest();
   } else if (val == 2) {
      VerticalTest();
   } else if (val == 3) {
      HorVertTest();
   } else if (val == 4) {
      SlowHorizontalBars();      //takes a while
   }
}

void Parse(uint8 inByte)
{
   uint8 v;
   //
   // Setting CommandTimeout to 50 gives us 5 second
   // before the ParseState is set to STANDBY
   // Timeout will never occur while inside Parse() - that's the intent
   //
   CommandTimeout = 50;
   if (ParseState == STANDBY) {
      //
      //Decode inByte
      //
        if ((inByte & SINGLEBYTEMASK) != SINGLEBYTECMD) {
         //
         //MultiByteCommand
         //
         PrevParseCommand = inByte;
         ParseState = inByte & MULTIBYTEMASK;
      }
      else {
         //
         // SingleByteCommand
         //
         if (LCD_DUMMY == inByte) {
         } else if (CLEAR_SCR == inByte) {
            SetScreen(COLOROFF);      // sets BDATA
            PDATA = COLORON;
         } else if (CLOCK_ON == inByte) {
            StartClock();
         } else if (CLOCK_OFF == inByte) {
            StopClock();
         }
         //
         // done with unparameterized single byte commands.
         // Must be <PSET>, <X++>, <Y++>, <X-->, <Y-->, <X++,PSET>, <Y++,PSET>, <X--,PSET> or, <Y--,PSET>
         // Also UNSET (Clr pixel)
         else if ((inByte & PSETINCDECMASK) == PSETINCDECCMD) {   //Increment, Decrement, PSET
            if ((inByte & PSETPIXMASK) == PSETPIXMASK) {      // unused
            } else if (inByte & PSETPIXON) {
               SetPixel(PDATA, Vpix, Vy);         // Set Pixel
            } else if (inByte & PSETPIXOFF) {
               SetPixel(BDATA, Vpix, Vy);         //Clear Pixel
            }
            //
            // Now check for X/Y increment or decrement
            //
            v = (inByte & PSETXYMASK);            //X, Y or nothing
            if (v == PSETXYMASK) {               //unused
            } else if (v == PSETX) {
               if (inByte & PSETDEC) {            //Decrement
                  if (--Vpix == 0xffff) Vpix = lastHorPixel;
               } else {                     //Increment
                  if (++Vpix == nHorPixels) Vpix = 0;
               }
            } else if (v == PSETY) {
               if (inByte & PSETDEC) {            //Decrement
                  if (--Vy == 0xff) Vy = lastLine;
               } else {                     //Increment
                  if (++Vy == nLines) Vy = 0;
               }
            } else {                        //No X or Y action.
            }
         } //PSETINCDECCMD
         else { // UNKNOWN or UNIMPLEMENTED
         //ignore since it's single byte
         }
      } // SingleByteCommand
   } //ParseState == STANDBY
#if EXTDEBUG
   else if (ParseState == SERIALTEST) {
        if ((PrevParseCommand & MULTIBYTEMASK) == SERIALTEST) {
         //First time through.
         SavedIdx = 0;
         PrevParseCommand &= ~MULTIBYTEMASK;
      }
      // 1 byte argument: #of test bytes
      SavedArgs[SavedIdx++] = inByte;
      if (SavedIdx >= 1) {
         ParseState = SERIALTEST_DATA;
         PrevParseCommand = SERIALTEST;
      }
   }
   else if (ParseState == SERIALTEST_DATA) {
      if (PrevParseCommand != SERIALTEST) {
         // inconsistency
            DebugL1();
      }
      *pSTData++ = inByte;      //store test bytes
      if (pSTData >= &FrameBuffer[PHYS_LINES*BYTES_PER_LINE]) {
         pSTData = FrameBuffer;
      }
      if (--SavedArgs[0] == 0) {
         ParseState = STANDBY;
      }
   }
#endif
   else if (ParseState == PICTURE) {
      //
      // TODO. sb pixel argument for x. If x0 or x1 not aligned
      // on nibble boundary, discard the data.
      // first 4 byte arguments (x0, y0, x1, y1. Nibble addresses
      // then data: (((x1 - x0 + 1) * (y1 - y0 + 1)) / 2) bytes
        if ((PrevParseCommand & MULTIBYTEMASK) == PICTURE) {
         //First time through.
         SavedIdx = 0;
         PrevParseCommand &= ~MULTIBYTEMASK;
      }
      // 4 bytes argument: X0,Y0,X1,Y1 (nibble addresses)
      SavedArgs[SavedIdx++] = inByte;
      if (SavedIdx >= 4) {   // collected all args
         BMByteCount = ((SavedArgs[2] - SavedArgs[0] + 1) * (SavedArgs[3] - SavedArgs[1] + 1) / 2);
         if (BMByteCount > MaxPictureBytes) {
            // TODO. Compute excess and ignore those bytes
            DebugL1();
         }
         // TODO: expect Pixel Argument? Cluster Argument. Use X window limits
         if (SavedArgs[0] >= nClustersPerLine) SavedArgs[0] = 0;      //TODO
         Vx = SavedArgs[0];
//         if (SavedArgs[1] < YStart) SavedArgs[1] = YStart;
         if (SavedArgs[3] > YEnd) SavedArgs[3] = YEnd;
         Vy = SavedArgs[3];
         ParseState = PICTURE_DATA;
#if DEBUG
         PrevParseCommand = PICTURE;
#endif
      }
   }   // PICTURE
   else if (ParseState == PICTURE_DATA) {
      ASSERT(PrevParseCommand == PICTURE);
      // 2 nibbles packed per byte, packed Upper nibble, then Lower nibble
      // works as long as "x1 - x0 + 1" is even
      // Data come in bottom of area lines first
      if (((uint8)Vx & 0x01) != 0) {      // not byte aligned
         WriteNibble((inByte >> 4), Vx, Vy);
         WriteNibble((inByte & 0x0f), Vx+1, Vy);
      } else {
         WriteByte(inByte, Vx >> 1, Vy);
      }
      Vx += 2;
      if ((Vx - 1) == SavedArgs[2]) {
         Vx = SavedArgs[0];
         Vpix = (Vx << 2);
         if (--Vy == SavedArgs[1] - 1) {
            Vy = SavedArgs[1];
         }
      }
      if (--BMByteCount == 0) {
         ParseState = STANDBY;
      }

   } //PICTURE_DATA
   else if ((ParseState & MULTIBYTEMASK) == COLOR) {
      PDATA = (PrevParseCommand & 0x07);
      BDATA = PDATA ? 0 : 1;
      // ignore current byte in inByte
      ParseState = STANDBY;
   }
   else if (ParseState == SET) {
        if ((PrevParseCommand & MULTIBYTEMASK) == SET) {
         //First time through.
         SavedIdx = 0;
         PrevParseCommand &= ~MULTIBYTEMASK;
      }
      // 2 bytes argument: X or Y
      SavedArgs[SavedIdx++] = inByte;
      if (SavedIdx >= 2) {   // collected all args
         if (PrevParseCommand & SETX) Vpix = SavedArgs[0] | (SavedArgs[1] << 8);
         else Vy = (uint8)(SavedArgs[0] | (SavedArgs[1] << 8));
         if (PrevParseCommand & SETPIXON) {
            SetPixel(PDATA, Vpix, Vy);
         } else if (PrevParseCommand & SETPIXOFF) {
            SetPixel(BDATA, Vpix, Vy);
         }
         ParseState = STANDBY;
      }
   }
   else if (ParseState == PRINT_STRING) {
      //
      // Print String State. Check if NULL
      //
      if (inByte != 0) {
         PutChar(inByte);
      }
      else {
         ParseState = STANDBY;   // End of String
      }
   }
   else if (ParseState == PUT_CHAR) {
      PutChar(inByte);
      ParseState = STANDBY;
   }
   else if (ParseState == DRAW_LINE) {
        if ((PrevParseCommand & MULTIBYTEMASK) == DRAW_LINE) {
         //First time through.
         SavedIdx = 0;
         PrevParseCommand &= ~MULTIBYTEMASK;
      }
      // 8 bytes argument: X0,Y0,X1,Y1
      // X0, X1, Y0 and Y1 are 2 bytes each (low, high)
      SavedArgs[SavedIdx++] = inByte;
      if (SavedIdx >= 8) {   // collected all args
         DrawLine(SavedArgs[0] | (SavedArgs[1] << 8),
                SavedArgs[2] | (SavedArgs[3] << 8),
                SavedArgs[4] | (SavedArgs[5] << 8),
                SavedArgs[6] | (SavedArgs[7] << 8));
         //
         // Set current coordinate to last pixel drawn
         //
         Vpix = SavedArgs[4] | (SavedArgs[5] << 8);
         Vy = SavedArgs[6] | (SavedArgs[7] << 8);
         ParseState = STANDBY;
      }
   }
   else if (ParseState == DRAW_CIRCLE) {
        if ((PrevParseCommand & MULTIBYTEMASK) == DRAW_CIRCLE) {
         //First time through.
         SavedIdx = 0;
         PrevParseCommand &= ~MULTIBYTEMASK;
      }
      // 6 bytes argument: X,Y,Radius
      // X, Y and Radius are 2 bytes each (low, high)
      SavedArgs[SavedIdx++] = inByte;
      if (SavedIdx >= 6) {   // collected all args
         DrawCircle(SavedArgs[0] | (SavedArgs[1] << 8),
                  SavedArgs[2] | (SavedArgs[3] << 8),
                  SavedArgs[4] | (SavedArgs[5] << 8));
         //
         // Set current coordinate to center of circle
         //
         Vpix = SavedArgs[0] | (SavedArgs[1] << 8);
         Vy = SavedArgs[2] | (SavedArgs[3] << 8);
         ParseState = STANDBY;
      }
   }
   else if (ParseState == SET_SCREEN) {
        if ((PrevParseCommand & MULTIBYTEMASK) == SET_SCREEN) {
         //First time through.
         SavedIdx = 0;
         PrevParseCommand &= ~MULTIBYTEMASK;
      }
      // 9 bytes argument: color, X0,Y0,X1,Y1
      // color is 1 byte. X0, X1, Y0 and Y1 are 2 bytes each (low, high)
      SavedArgs[SavedIdx++] = inByte;
      if (SavedIdx >= 9) {   // collected all args
         SetScreenX(   SavedArgs[0],
                  SavedArgs[1] | (SavedArgs[2] << 8),            //x0
                  (uint8)(SavedArgs[3] | (SavedArgs[4] << 8)),   //y0
                  SavedArgs[5] | (SavedArgs[6] << 8),            //x1
                  (uint8)(SavedArgs[7] | (SavedArgs[8] << 8)));   //y1
         ParseState = STANDBY;
      }
   }
   else if (ParseState == LCDDEMO) {
      LCDDemo(inByte);      //select Demo
      ParseState = STANDBY;
   }
   else {
      DebugL1();
      ParseState = STANDBY;
   }
#if 0&DEBUG
   if (STANDBY == ParseState) {
      UARTSendByte('.', FALSE);
   }
#endif
}

const char StartStr1[] PROGMEM = "\r\nEpson P3000 LCD Controller V1.2\r\n";
//
// TODO: replace columnOffset with SetWindow()
void SetSplashScreen(uint8 columnOffset)
{
//
// should compress image before enabling this feature
//
// Bitmap is for QVGA (320 x 240) screen.
// Skip first and last 20 lines (6400 pixels, 800 bytes)
//
   prog_uint8_t *pCode = SplashScreen;
   uint8 x, v;
   int y;         //needed for for loop
   pCode += 800;
   for (y = YEnd; y >= YStart; --y) {
      //OK to use WriteByte since horizontal offset X is always even.
      for (x = 0; x < (nColumnsPerLine / 2); x += 2) {
            v = __LPM(pCode++);
            WriteByte(v, (x / 2) + (columnOffset / 2), y);
      }
   }
   fStartClock = TRUE;   //TEST TODO
}

void Preset(void)
{
   Serial_In(CLEAR_SCR);      //clear Screen
   Serial_In(PRINT_STRING);   //String
     Serial_In('R');
   Serial_In('e');
   Serial_In('a');
   Serial_In('d');
   Serial_In('y');
   Serial_In(0);
}

int main(void)
{
   unsigned long i = 0;
   uint8 inByte;
   MCUSR = 0;
   GPIOR0 = 0;
   InitCtrl();
   if (0 == UARTInit(BAUD_115200)) {
      FlashLed(10, 100);
   }

   fShowClock = FALSE;
   fStartClock = FALSE;
   fAutoClock = FALSE;
   TimeSecs = 0;
   TimeMins = 0;
   TimeHrs = 1;
   SetScreen(COLOROFF);      // sets BDATA
   PDATA = COLORON;
#if SPLASHSCREEN
   SetSplashScreen(0);
   SetSplashScreen(80);
#else
   Preset();      // text to lines 0..7 through SerialIn()
#endif
//
//   Enable Timer0 & Timer1 in Interrupt Mask
//
   EnableTC0();
   EnableTC1();
   sei();                     //start interrupts -> screen refresh, serial in
   BlinkFast();
   UARTPrintfProgStr((prog_char*)StartStr1);

#if 0
   SetScreen(COLOROFF);      // sets BDATA
   PDATA = COLORON;
   DrawTable(DialData, FALSE);
   DrawTable(DialDigits12, FALSE);
   DrawSecsHand(TimeMins, FALSE);
   DrawMinsHand(TimeSecs, FALSE);
   DrawHrsHand(TimeHrs, FALSE);
#endif

   do {
      //
      // process queued graphic commands from SerialIn
      //
      while (UARTRXAvailable()) {
         inByte = UARTReceiveByte();
         if (fAutoClock) {
            StopClock();
         }
         Parse(inByte);
         NoActivityTimeout = NOACTIVITY;      // 1 minute
      }

      if (GlobalFault) {
         DebugL0(GlobalFault);
      }
      //
      // Signal when buffer is empty.
      if (++i == 0x4ffff) {
         FlashLed(1, 5);
         i = 0;
         ASSERT(GetMemUnused() > 25);
      }

      if (fStartClock &!fShowClock) {
         SetScreen(COLOROFF);      // sets BDATA
         PDATA = COLORON;
         SetSplashScreen(80);
         StartClock();
      }
      fStartClock = FALSE;

      if (SecsToAdd > 0) {
         UpdateTime();
      }
   } while (TRUE);
}


2.:



byte DialData[] PROGMEM = {
                0x64,0xc7,0x64,0xbe,0x00,0x6e,0xc7,0x6d,0xc2,0x00,0x78,0xc5,0x77,0xc0,0x00,0x82,0xc3,0x81,0xbe,0x00,
                0x8c,0xbf,0x8a,0xba,0x00,0x95,0xba,0x92,0xb4,0x00,0x9e,0xb5,0x9b,0xb1,0x00,0xa6,0xae,0xa2,0xaa,0x00,
                0xad,0xa7,0xa9,0xa3,0x00,0xb4,0x9f,0xb0,0x9c,0x00,0xb9,0x96,0xb3,0x92,0x00,0xbe,0x8d,0xb9,0x8b,0x00,
                0xc2,0x83,0xbd,0x82,0x00,0xc4,0x79,0xbf,0x78,0x00,0xc6,0x6f,0xc1,0x6e,0x00,0xc6,0x64,0xbd,0x64,0x00,
                0xc6,0x5a,0xc1,0x5b,0x00,0xc4,0x50,0xbf,0x51,0x00,0xc2,0x46,0xbd,0x47,0x00,0xbe,0x3c,0xb9,0x3e,0x00,
                0xb9,0x33,0xb3,0x36,0x00,0xb4,0x2a,0xb0,0x2d,0x00,0xad,0x22,0xa9,0x26,0x00,0xa6,0x1b,0xa2,0x1f,0x00,
                0x9e,0x14,0x9b,0x18,0x00,0x95,0x0f,0x92,0x15,0x00,0x8c,0x0a,0x8a,0x0f,0x00,0x82,0x06,0x81,0x0b,0x00,
                0x78,0x04,0x77,0x09,0x00,0x6e,0x02,0x6d,0x07,0x00,0x63,0x02,0x63,0x0b,0x00,0x59,0x02,0x5a,0x07,0x00,
                0x4f,0x04,0x50,0x09,0x00,0x45,0x06,0x46,0x0b,0x00,0x3b,0x0a,0x3d,0x0f,0x00,0x32,0x0f,0x36,0x15,0x00,
                0x29,0x14,0x2c,0x18,0x00,0x21,0x1b,0x25,0x1f,0x00,0x1a,0x22,0x1e,0x26,0x00,0x13,0x2a,0x17,0x2d,0x00,
                0x0e,0x33,0x14,0x37,0x00,0x09,0x3c,0x0e,0x3e,0x00,0x05,0x46,0x0a,0x47,0x00,0x03,0x50,0x08,0x51,0x00,
                0x01,0x5a,0x06,0x5b,0x00,0x01,0x65,0x0a,0x65,0x00,0x01,0x6f,0x06,0x6e,0x00,0x03,0x79,0x08,0x78,0x00,
                0x05,0x83,0x0a,0x82,0x00,0x09,0x8d,0x0e,0x8b,0x00,0x0e,0x96,0x14,0x92,0x00,0x13,0x9f,0x17,0x9c,0x00,
                0x1a,0xa7,0x1e,0xa3,0x00,0x21,0xae,0x25,0xaa,0x00,0x29,0xb5,0x2c,0xb1,0x00,0x32,0xba,0x35,0xb4,0x00,
                0x3b,0xbf,0x3d,0xba,0x00,0x45,0xc3,0x46,0xbe,0x00,0x4f,0xc5,0x50,0xc0,0x00,0x59,0xc7,0x5a,0xc2,0xff
};


byte DialDigits12[] PROGMEM = {
                0x5c,0xb9,0x5d,0xba,0x60,0xbc,0x60,0xab,0x00,0x64,0xb8,0x64,0xb9,0x65,0xba,0x66,0xbb,0x67,0xbc,0x6b,0xbc,0x6c,0xbb,0x6d,0xba,0x6e,0xb9,0x6e,0xb7,0x6d,0xb5,0x6b,0xb3,0x63,0xab,0x6f,0xab,0x00,
                0x88,0xae,0x89,0xaf,0x8c,0xb1,0x8c,0xa0,0x00,0x00,
                0xa5,0x95,0xa5,0x96,0xa6,0x97,0xa7,0x98,0xa8,0x99,0xac,0x99,0xad,0x98,0xae,0x97,0xaf,0x96,0xaf,0x94,0xae,0x92,0xac,0x90,0xa4,0x88,0xb0,0x88,0x00,0x00,
                0xb1,0x6e,0xba,0x6e,0xb5,0x67,0xb7,0x67,0xb9,0x67,0xba,0x66,0xbb,0x63,0xbb,0x62,0xba,0x5f,0xb8,0x5d,0xb6,0x5d,0xb3,0x5d,0xb1,0x5d,0xb0,0x5e,0xaf,0x60,0x00,0xac,0x46,0xa4,0x3a,0xb1,0x3a,0x00,0xac,0x46,0xac,0x35,0x00,0x00,
                0x90,0x28,0x88,0x28,0x87,0x21,0x88,0x21,0x8a,0x22,0x8d,0x22,0x8f,0x21,0x91,0x20,0x92,0x1d,0x92,0x1c,0x91,0x19,0x8f,0x17,0x8d,0x17,0x8a,0x17,0x88,0x17,0x87,0x18,0x86,0x1a,0x00,0x00,
                0x68,0x1d,0x67,0x1e,0x65,0x1f,0x63,0x1f,0x60,0x1e,0x5f,0x1c,0x5e,0x18,0x5e,0x13,0x5f,0x10,0x60,0x0e,0x63,0x0e,0x64,0x0e,0x66,0x0e,0x68,0x10,0x69,0x13,0x69,0x13,0x68,0x16,0x66,0x18,0x64,0x18,0x63,0x18,0x60,0x18,0x5f,0x16,0x5e,0x13,0x00,0x42,0x28,0x39,0x17,0x00,0x36,0x28,0x42,0x28,0x00,0x00,
                0x1b,0x46,0x19,0x45,0x18,0x44,0x18,0x42,0x19,0x40,0x1a,0x3f,0x1e,0x3f,0x20,0x3e,0x22,0x3c,0x23,0x3a,0x23,0x38,0x22,0x36,0x21,0x35,0x1f,0x35,0x1b,0x35,0x19,0x35,0x18,0x36,0x17,0x38,0x17,0x3a,0x18,0x3c,0x1a,0x3e,0x1c,0x3f,0x1f,0x3f,0x21,0x40,0x22,0x42,0x22,0x44,0x21,0x45,0x1f,0x46,0x1b,0x46,0x00,0x00,
                0x18,0x69,0x17,0x67,0x15,0x65,0x13,0x64,0x12,0x64,0x10,0x65,0x0e,0x67,0x0d,0x69,0x0d,0x6a,0x0e,0x6d,0x10,0x6e,0x12,0x6f,0x13,0x6f,0x15,0x6e,0x17,0x6d,0x18,0x69,0x18,0x65,0x17,0x61,0x15,0x5e,0x13,0x5e,0x11,0x5e,0x0f,0x5e,0x0e,0x60,0x00,0x00,
                0x19,0x96,0x1a,0x97,0x1d,0x99,0x1d,0x88,0x00,0x00,
                0x25,0x99,0x23,0x98,0x21,0x96,0x20,0x92,0x20,0x8f,0x21,0x8b,0x23,0x88,0x25,0x88,0x27,0x88,0x29,0x88,0x2b,0x8b,0x2c,0x8f,0x2c,0x92,0x2b,0x96,0x29,0x98,0x27,0x99,0x25,0x99,0x00,0x00,
                0x34,0xae,0x35,0xaf,0x38,0xb1,0x38,0xa0,0x00,0x00,
                0x3e,0xae,0x3f,0xaf,0x42,0xb1,0x42,0xa0,0xff,0x00
};

byte SecPtrData[] PROGMEM = {
                0x64,0xbe,0x64,0x64,0xff,0x6d,0xbe,0x64,0x64,0xff,0x76,0xbd,0x64,0x64,0xff,0x7f,0xba,0x64,0x64,0xff,
                0x88,0xb7,0x64,0x64,0xff,0x91,0xb2,0x64,0x64,0xff,0x98,0xad,0x64,0x64,0xff,0xa0,0xa7,0x64,0x64,0xff,
                0xa6,0xa1,0x64,0x64,0xff,0xac,0x99,0x64,0x64,0xff,0xb1,0x91,0x64,0x64,0xff,0xb6,0x89,0x64,0x64,0xff,
                0xb9,0x80,0x64,0x64,0xff,0xbc,0x77,0x64,0x64,0xff,0xbd,0x6e,0x64,0x64,0xff,0xbd,0x64,0x64,0x64,0xff,
                0xbd,0x5b,0x64,0x64,0xff,0xbc,0x52,0x64,0x64,0xff,0xb9,0x49,0x64,0x64,0xff,0xb6,0x40,0x64,0x64,0xff,
                0xb1,0x37,0x64,0x64,0xff,0xac,0x30,0x64,0x64,0xff,0xa6,0x28,0x64,0x64,0xff,0xa0,0x22,0x64,0x64,0xff,
                0x98,0x1c,0x64,0x64,0xff,0x91,0x17,0x64,0x64,0xff,0x88,0x12,0x64,0x64,0xff,0x7f,0x0f,0x64,0x64,0xff,
                0x76,0x0c,0x64,0x64,0xff,0x6d,0x0b,0x64,0x64,0xff,0x64,0x0b,0x64,0x64,0xff,0x5a,0x0b,0x64,0x64,0xff,
                0x51,0x0c,0x64,0x64,0xff,0x48,0x0f,0x64,0x64,0xff,0x3f,0x12,0x64,0x64,0xff,0x37,0x17,0x64,0x64,0xff,
                0x2f,0x1c,0x64,0x64,0xff,0x27,0x22,0x64,0x64,0xff,0x21,0x28,0x64,0x64,0xff,0x1b,0x30,0x64,0x64,0xff,
                0x16,0x38,0x64,0x64,0xff,0x11,0x40,0x64,0x64,0xff,0x0e,0x49,0x64,0x64,0xff,0x0b,0x52,0x64,0x64,0xff,
                0x0a,0x5b,0x64,0x64,0xff,0x0a,0x64,0x64,0x64,0xff,0x0a,0x6e,0x64,0x64,0xff,0x0b,0x77,0x64,0x64,0xff,
                0x0e,0x80,0x64,0x64,0xff,0x11,0x89,0x64,0x64,0xff,0x16,0x91,0x64,0x64,0xff,0x1b,0x99,0x64,0x64,0xff,
                0x21,0xa1,0x64,0x64,0xff,0x27,0xa7,0x64,0x64,0xff,0x2f,0xad,0x64,0x64,0xff,0x36,0xb2,0x64,0x64,0xff,
                0x3f,0xb7,0x64,0x64,0xff,0x48,0xba,0x64,0x64,0xff,0x51,0xbd,0x64,0x64,0xff,0x5a,0xbe,0x64,0x64,0xff

};
byte MinPtrData[] PROGMEM = {
                0x66,0x64,0x64,0xb4,0x62,0x64,0x66,0x64,0xff,0x65,0x64,0x6c,0xb4,0x62,0x65,0x65,0x64,0xff,
                0x65,0x64,0x74,0xb3,0x62,0x65,0x65,0x64,0xff,0x65,0x64,0x7c,0xb1,0x62,0x65,0x65,0x64,0xff,
                0x65,0x64,0x84,0xae,0x62,0x65,0x65,0x64,0xff,0x65,0x63,0x8c,0xaa,0x62,0x66,0x65,0x63,0xff,
                0x65,0x63,0x93,0xa5,0x62,0x66,0x65,0x63,0xff,0x65,0x63,0x99,0xa0,0x62,0x66,0x65,0x63,0xff,
                0x65,0x63,0x9f,0x9a,0x62,0x66,0x65,0x63,0xff,0x65,0x63,0xa4,0x94,0x62,0x66,0x65,0x63,0xff,
                0x64,0x63,0xa9,0x8c,0x63,0x66,0x64,0x63,0xff,0x64,0x63,0xad,0x85,0x63,0x66,0x64,0x63,0xff,
                0x64,0x63,0xb0,0x7d,0x63,0x66,0x64,0x63,0xff,0x64,0x63,0xb2,0x75,0x63,0x66,0x64,0x63,0xff,
                0x64,0x63,0xb3,0x6d,0x63,0x66,0x64,0x63,0xff,0x63,0x62,0xb3,0x64,0x64,0x66,0x63,0x62,0xff,
                0x63,0x63,0xb3,0x5c,0x64,0x66,0x63,0x63,0xff,0x63,0x63,0xb2,0x54,0x64,0x66,0x63,0x63,0xff,
                0x63,0x63,0xb0,0x4c,0x64,0x66,0x63,0x63,0xff,0x63,0x63,0xad,0x44,0x64,0x66,0x63,0x63,0xff,
                0x62,0x63,0xa9,0x3c,0x65,0x66,0x62,0x63,0xff,0x62,0x63,0xa4,0x35,0x65,0x66,0x62,0x63,0xff,
                0x62,0x63,0x9f,0x2f,0x65,0x66,0x62,0x63,0xff,0x62,0x63,0x99,0x29,0x65,0x66,0x62,0x63,0xff,
                0x62,0x63,0x93,0x24,0x65,0x66,0x62,0x63,0xff,0x62,0x63,0x8c,0x1f,0x65,0x66,0x62,0x63,0xff,
                0x62,0x64,0x84,0x1b,0x65,0x65,0x62,0x64,0xff,0x62,0x64,0x7c,0x18,0x65,0x65,0x62,0x64,0xff,
                0x62,0x64,0x74,0x16,0x65,0x65,0x62,0x64,0xff,0x62,0x64,0x6c,0x15,0x65,0x65,0x62,0x64,0xff,
                0x62,0x65,0x63,0x15,0x65,0x64,0x62,0x65,0xff,0x62,0x65,0x5b,0x15,0x65,0x64,0x62,0x65,0xff,
                0x62,0x65,0x53,0x16,0x65,0x64,0x62,0x65,0xff,0x62,0x65,0x4b,0x18,0x65,0x64,0x62,0x65,0xff,
                0x62,0x65,0x43,0x1b,0x65,0x64,0x62,0x65,0xff,0x62,0x65,0x3c,0x1f,0x65,0x64,0x62,0x65,0xff,
                0x62,0x66,0x34,0x24,0x65,0x63,0x62,0x66,0xff,0x62,0x66,0x2e,0x29,0x65,0x63,0x62,0x66,0xff,
                0x62,0x66,0x28,0x2f,0x65,0x63,0x62,0x66,0xff,0x62,0x66,0x23,0x35,0x65,0x63,0x62,0x66,0xff,
                0x63,0x66,0x1e,0x3d,0x64,0x63,0x63,0x66,0xff,0x63,0x66,0x1a,0x44,0x64,0x63,0x63,0x66,0xff,
                0x63,0x66,0x17,0x4c,0x64,0x63,0x63,0x66,0xff,0x63,0x66,0x15,0x54,0x64,0x63,0x63,0x66,0xff,
                0x63,0x66,0x14,0x5c,0x64,0x63,0x63,0x66,0xff,0x64,0x66,0x14,0x65,0x63,0x62,0x64,0x66,0xff,
                0x64,0x66,0x14,0x6d,0x63,0x63,0x64,0x66,0xff,0x64,0x66,0x15,0x75,0x63,0x63,0x64,0x66,0xff,
                0x64,0x66,0x17,0x7d,0x63,0x63,0x64,0x66,0xff,0x64,0x66,0x1a,0x85,0x63,0x63,0x64,0x66,0xff,
                0x64,0x66,0x1e,0x8c,0x63,0x63,0x64,0x66,0xff,0x65,0x66,0x23,0x94,0x62,0x63,0x65,0x66,0xff,
                0x65,0x66,0x28,0x9a,0x62,0x63,0x65,0x66,0xff,0x65,0x66,0x2e,0xa0,0x62,0x63,0x65,0x66,0xff,
                0x65,0x66,0x34,0xa5,0x62,0x63,0x65,0x66,0xff,0x65,0x66,0x3b,0xaa,0x62,0x63,0x65,0x66,0xff,
                0x65,0x65,0x43,0xae,0x62,0x64,0x65,0x65,0xff,0x65,0x65,0x4b,0xb1,0x62,0x64,0x65,0x65,0xff,
                0x65,0x65,0x53,0xb3,0x62,0x64,0x65,0x65,0xff,0x65,0x65,0x5b,0xb4,0x62,0x64,0x65,0x65,0xff

};
byte HrPtrData[] PROGMEM = {
                0x66,0x64,0x64,0x9b,0x62,0x64,0x66,0x64,0xff,0x65,0x64,0x69,0x9b,0x62,0x65,0x65,0x64,0xff,
                0x65,0x64,0x6f,0x9a,0x62,0x65,0x65,0x64,0xff,0x65,0x64,0x74,0x99,0x62,0x65,0x65,0x64,0xff,
                0x65,0x64,0x7a,0x97,0x62,0x65,0x65,0x64,0xff,0x65,0x63,0x7f,0x94,0x62,0x66,0x65,0x63,0xff,
                0x65,0x63,0x84,0x91,0x62,0x66,0x65,0x63,0xff,0x65,0x63,0x88,0x8d,0x62,0x66,0x65,0x63,0xff,
                0x65,0x63,0x8c,0x89,0x62,0x66,0x65,0x63,0xff,0x65,0x63,0x90,0x85,0x62,0x66,0x65,0x63,0xff,
                0x64,0x63,0x93,0x80,0x63,0x66,0x64,0x63,0xff,0x64,0x63,0x96,0x7b,0x63,0x66,0x64,0x63,0xff,
                0x64,0x63,0x98,0x75,0x63,0x66,0x64,0x63,0xff,0x64,0x63,0x99,0x70,0x63,0x66,0x64,0x63,0xff,
                0x64,0x63,0x9a,0x6a,0x63,0x66,0x64,0x63,0xff,0x63,0x62,0x9a,0x64,0x64,0x66,0x63,0x62,0xff,
                0x63,0x63,0x9a,0x5f,0x64,0x66,0x63,0x63,0xff,0x63,0x63,0x99,0x59,0x64,0x66,0x63,0x63,0xff,
                0x63,0x63,0x98,0x54,0x64,0x66,0x63,0x63,0xff,0x63,0x63,0x96,0x4e,0x64,0x66,0x63,0x63,0xff,
                0x62,0x63,0x93,0x49,0x65,0x66,0x62,0x63,0xff,0x62,0x63,0x90,0x44,0x65,0x66,0x62,0x63,0xff,
                0x62,0x63,0x8c,0x40,0x65,0x66,0x62,0x63,0xff,0x62,0x63,0x88,0x3c,0x65,0x66,0x62,0x63,0xff,
                0x62,0x63,0x84,0x38,0x65,0x66,0x62,0x63,0xff,0x62,0x63,0x7f,0x35,0x65,0x66,0x62,0x63,0xff,
                0x62,0x64,0x7a,0x32,0x65,0x65,0x62,0x64,0xff,0x62,0x64,0x74,0x30,0x65,0x65,0x62,0x64,0xff,
                0x62,0x64,0x6f,0x2f,0x65,0x65,0x62,0x64,0xff,0x62,0x64,0x69,0x2e,0x65,0x65,0x62,0x64,0xff,
                0x62,0x65,0x63,0x2e,0x65,0x64,0x62,0x65,0xff,0x62,0x65,0x5e,0x2e,0x65,0x64,0x62,0x65,0xff,
                0x62,0x65,0x58,0x2f,0x65,0x64,0x62,0x65,0xff,0x62,0x65,0x53,0x30,0x65,0x64,0x62,0x65,0xff,
                0x62,0x65,0x4d,0x32,0x65,0x64,0x62,0x65,0xff,0x62,0x65,0x48,0x35,0x65,0x64,0x62,0x65,0xff,
                0x62,0x66,0x43,0x38,0x65,0x63,0x62,0x66,0xff,0x62,0x66,0x3f,0x3c,0x65,0x63,0x62,0x66,0xff,
                0x62,0x66,0x3b,0x40,0x65,0x63,0x62,0x66,0xff,0x62,0x66,0x37,0x44,0x65,0x63,0x62,0x66,0xff,
                0x63,0x66,0x34,0x49,0x64,0x63,0x63,0x66,0xff,0x63,0x66,0x31,0x4e,0x64,0x63,0x63,0x66,0xff,
                0x63,0x66,0x2f,0x54,0x64,0x63,0x63,0x66,0xff,0x63,0x66,0x2e,0x59,0x64,0x63,0x63,0x66,0xff,
                0x63,0x66,0x2d,0x5f,0x64,0x63,0x63,0x66,0xff,0x64,0x66,0x2d,0x65,0x63,0x62,0x64,0x66,0xff,
                0x64,0x66,0x2d,0x6a,0x63,0x63,0x64,0x66,0xff,0x64,0x66,0x2e,0x70,0x63,0x63,0x64,0x66,0xff,
                0x64,0x66,0x2f,0x75,0x63,0x63,0x64,0x66,0xff,0x64,0x66,0x31,0x7b,0x63,0x63,0x64,0x66,0xff,
                0x64,0x66,0x34,0x80,0x63,0x63,0x64,0x66,0xff,0x65,0x66,0x37,0x85,0x62,0x63,0x65,0x66,0xff,
                0x65,0x66,0x3b,0x89,0x62,0x63,0x65,0x66,0xff,0x65,0x66,0x3f,0x8d,0x62,0x63,0x65,0x66,0xff,
                0x65,0x66,0x43,0x91,0x62,0x63,0x65,0x66,0xff,0x65,0x66,0x48,0x94,0x62,0x63,0x65,0x66,0xff,
                0x65,0x65,0x4d,0x97,0x62,0x64,0x65,0x65,0xff,0x65,0x65,0x53,0x99,0x62,0x64,0x65,0x65,0xff,
                0x65,0x65,0x58,0x9a,0x62,0x64,0x65,0x65,0xff,0x65,0x65,0x5e,0x9b,0x62,0x64,0x65,0x65,0xff

};


3.:


#include "./avr.inc"
#include <avr/io.h>
#include <avr/portpins.h>

#include "Configuracja.h" 

   .extern TextPage
   .extern Font8x8

//-- map the IO register back into the IO address space
#define PA_DDR      (_SFR_IO_ADDR(PORTA) - 1)
#define PB_DDR      (_SFR_IO_ADDR(PORTB) - 1)
#define PC_DDR      (_SFR_IO_ADDR(PORTC) - 1)
#define PD_DDR      (_SFR_IO_ADDR(PORTD) - 1)
#define PA_OUT      _SFR_IO_ADDR(PORTA)
#define PB_OUT      _SFR_IO_ADDR(PORTB)
#define PC_OUT      _SFR_IO_ADDR(PORTC)
#define PD_OUT      _SFR_IO_ADDR(PORTD)
#define PA_IN      (_SFR_IO_ADDR(PORTA) - 2)
#define PB_IN      (_SFR_IO_ADDR(PORTB) - 2)
#define PC_IN      (_SFR_IO_ADDR(PORTC) - 2)
#define PD_IN      (_SFR_IO_ADDR(PORTD) - 2)

//
// GENERAL DEFINITIONS
//
// Vx is a memory nibble address, not a pixel address
// Vy is line number (pixel and memory values are identical)
//
// PB0..PD3 connected to D0..D3 (nibble data)
//
#define   SRAMDATAI   PB_IN
#define   SRAMDATAO   PB_OUT
#define   SRAMDATA_DDR PB_DDR
//
// PD2 connected to YSCL
//
#define   LCD_YSCL   PD_OUT,YSCL_BIT
#define   YSCL_DDR   PD_DDR,YSCL_BIT
//
// PD3 connected to M (AC) Line
//
#define   M_DDR      PD_DDR,3
#define   LCD_MTOGGLE   PD_IN,M_BIT
//
// PD4 connected to LCD Enable
//
#define   LCD_ENABLE   PD_OUT,ENABLE_BIT
#define   ENABLE_DDR   PD_DDR,ENABLE_BIT
//
// PD5 connected to LCD HSYNC (LP)
//
#define   LCD_HSYNC   PD_OUT,HSYNC_BIT
#define   HSYNC_DDR   PD_DDR,HSYNC_BIT
//
// PD6 connected to LCD VSYNC (SF)
//
#define   LCD_VSYNC   PD_OUT,VSYNC_BIT
#define   VSYNC_DDR   PD_DDR,VSYNC_BIT
//
// PD7 connected to software DOTCLOCK (XSCL)
//
#define   DOTCLK      PD_OUT,DOTCLK_BIT
#define   DOTCLK_PORT   PD_OUT
#define   DOTCLK_DDR   PD_DDR,DOTCLK_BIT
//
// PC0 connected to MCU_TEST bit
//
#define MCU_TEST   PC_OUT,MCU_TEST_BIT
#define MCU_TEST_DDR   DDRC,MCU_TEST_BIT
//
// PC1 connected to LCD ECL
//
#define   LCD_ECL      PC_OUT,ECL_BIT
#define   ECLDDR      PC_DDR,ECL_BIT
//
// PA0 connected to LED
//
#define   LEDI      PA_IN,0
#define   LEDO      PA_OUT,0
#define   LED_DDR      PA_DDR,0
//
// PA1 connected to LED2
//
#define   LED2I      PA_IN,1
#define   LED2O      PA_OUT,1
#define   LED2_DDR   PA_DDR,1

#define COLORWHITE   0b00000001
#define COLORBLACK   0b00000000

#define BITSPERPIXEL   1
#define DATABITS      4

.section   .text

#define   PORTDCLKOFF      r21
#define   PORTDCLKON      r20

        .global TIMER0_COMPA_vect
//
// Assume non-data pins in PORTB are input
//
   .macro   UpdateColumns
   ld      r16,Z+
   swap   r16            ;ldata >> 4
   out      DOTCLK_PORT,PORTDCLKON         ; sbi   DOTCLK
   out      SRAMDATAO,r16
   out      DOTCLK_PORT,PORTDCLKOFF         ; cbi   DOTCLK
   swap   r16            ;ldata << 4
   out      DOTCLK_PORT,PORTDCLKON         ; sbi   DOTCLK
   out      SRAMDATAO,r16
   out      DOTCLK_PORT,PORTDCLKOFF         ; cbi   DOTCLK
   .endm
//

//
// Executed every 198.4 uSec (5,000 Hz).
//
// Refreshes one display line.
// 100 lines -> 50 Screen refreshes / second
//
TIMER0_COMPA_vect:
   push   r16
   in      r16, _SFR_IO_ADDR(SREG)
   push   r16
#if 0
Not needed when running in CTC mode
   clr      r16
   sts      TCNT0,r16
#endif
   push   ZL
   push   ZH
   push   r18
   push   r19
   push   PORTDCLKOFF
   push   PORTDCLKON
   push   r0
   push   r1
#if DEBUG
   sbi      MCU_TEST
#endif
//
// get the line we're refreshing. Compute data ptr.
// todo: times 160 => times 128 + times 32
//
   lds      r19,RefreshLine         // Y
   ldi      r16,160               //160 bytes per line
   mul      r19,r16
   movw   ZL,r0
   eor      r1,r1
   subi   ZL,lo8(-(FrameBuffer))
   sbci   ZH,hi8(-(FrameBuffer))
//
//   Allow interrupts again (process Serial In while doing refresh)
//
   sei
//
   ldi      r18,20                  //1180 count
#if 1
   tst      r19                     //RefreshLine
   brne   1f
   sbi      LCD_VSYNC               //start VSYNC
1:
#endif
//
// preload the clock toggle registers
//
   in      PORTDCLKOFF,DOTCLK_PORT
   mov      PORTDCLKON,PORTDCLKOFF
   sbr      PORTDCLKON,_BV(DOTCLK_BIT)   //DotClk On
SED1180Loop:
   UpdateColumns
   UpdateColumns
   UpdateColumns
   UpdateColumns
   UpdateColumns
   UpdateColumns
   UpdateColumns
   UpdateColumns
//
// Transfer the 1180 to the next 1180
//
   sbi   LCD_ECL
   cbi   LCD_ECL   
//
// Loop until all 20 1180s had their turn
//
   dec      r18
   breq   1f
   rjmp   SED1180Loop
1:
//
// Horizontal Sync.
//
   sbi      LCD_ECL            //needed!!
   sbi      LCD_YSCL
   sbi      LCD_HSYNC
   cbi      LCD_ECL            //PORTC!
#if 0
   tst      r19               //RefreshLine
   brne   1f
   sbi      LCD_VSYNC         //start VSYNC
1:
#endif
   cbi      LCD_YSCL         //exact sequence is essential
   cbi      LCD_HSYNC
   cbi      LCD_VSYNC         //stop VSYNC

//
// Update Line Address
//
   inc      r19
   cpi      r19,PHYS_LINES
;   brsh   DoLCD_LastLine
;   rjmp   RefreshExit         //done
   brlo   RefreshExit

DoLCD_LastLine:
//
//toggle AC line
//
   sbi      LCD_MTOGGLE
//
// start new frame
//
   clr      r19
//
// Enable display after 3 frames
//
   lds      r16,pwrup_state
   cpi      r16,3
   brsh   Turn_On_LCDX
   inc    r16
   sts      pwrup_state,r16
   rjmp   RefreshExit
Turn_On_LCDX:
   sbi      LCD_ENABLE
RefreshExit:
   sts      RefreshLine,r19
#if DEBUG
   cbi      MCU_TEST
#endif
   pop      r1
   pop      r0
   pop      PORTDCLKON
   pop      PORTDCLKOFF
   pop      r19
   pop      r18
   pop      ZH
   pop      ZL
Tdone:
   pop      r16
   out      _SFR_IO_ADDR(SREG),r16
   pop      r16
   reti

#undef   PORTDCLKOFF
#undef   PORTDCLKON

   .global   InitMem

#define   RAMSTART 0x0100

InitMem:
   push   r18
   push   r20
   push   r21
   push   ZL
   push   ZH
   in      r20,_SFR_IO_ADDR(SPL)               ;top
   in      r21,_SFR_IO_ADDR(SPH)
   
   ldi      r18,0xcc
;   ldiw   Z,RAMSTART         ;Preset RAM
   ldiw   Z,__heap_start
1:
   st      Z+,r18
   cp      ZL,r20
   cpc      ZH,r21
   brne   1b
   pop      ZH
   pop      ZL
   pop      r21
   pop      r20
   pop      r18
   ret



//## -------------------  FONTS & BITMAPS   
   .global   Font8x8
   .global   Font8x8End

#include ".\Font8x8.inc"

Font8x8End:
   .align

#if 0
   .global   DialData
   .global DialDigits
   .global SecPtrData
   .global MinPtrData
   .global HrPtrData

#include "./EpsonClk.inc"
#endif
   .align

#if SPLASHSCREEN
#include ".\RoseBM.inc"

   .global   SplashScreen
#endif

   .align


Igy esetleg lehet vele valamit kezdeni?

lcd sharp_1.jpg



Admin: a következő 4 oldalas kódbeszúrásért CODE gomb nélkül fenékbebillentés jár!
Nincs meg a kellő jogosultságod a hozzászóláshoz csatolt állományok megtekintéséhez.
A microkontroler sok mindenre alkalmas. a Pc bármire amire meg tudod tanítani.

Avatar
Robert
Elektronbűvölő
Hozzászólások: 9737
Csatlakozott: 2005. december 9. péntek, 7:00
Tartózkodási hely: Budapest
Kapcsolat:

Re: sharp LM085YB01T01 kijelző vezérlése.

HozzászólásSzerző: Robert » 2016. december 29. csütörtök, 13:39

Ha van üres 10....30 órád, nyugodtan.
- A kód ATMega1284re készült (Nem Arduino támogatott chip)
- C nyelven (Nem Arduino)

Amúgy a Nextion Touch kijelzője 800x480 (5") felbontás, touch támogatásal: ~60$ -> 18 eFt.
Ha a kijelződ tudna minimum ennyit, akkor a Nextion árat oszd le 30 órára: 600 Ft órabér. És van egy olyan kijelződ amibe minimum 100 órát még bele kellene tolnod és ha meghibásodik, nem pótolható.
Gazdaságilag NEM éri meg.
Én inkább tanulnék valami rentábilisabbat:) .
http://www.tavir.hu - a gazda :)

Bearnie74
DrótVégénSzéndarab
Hozzászólások: 34
Csatlakozott: 2016. november 25. péntek, 7:10

Re: sharp LM085YB01T01 kijelző vezérlése.

HozzászólásSzerző: Bearnie74 » 2016. december 29. csütörtök, 14:01

Ezt a kijelzőt 10.000 ért vesztegetik újonnan, és a céljaimnak tökéletesen megfelel, főleg hogy a hozzá való tapi sem több 1500 Ft nál.
A microkontroler sok mindenre alkalmas. a Pc bármire amire meg tudod tanítani.


Vissza: “LCD kezelése”

Ki van itt

Jelenlévő fórumozók: Google [Bot] valamint 3 vendég