CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

2X16 LCD Sniffer

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Sam_40



Joined: 07 Jan 2015
Posts: 131

View user's profile Send private message

2X16 LCD Sniffer
PostPosted: Thu May 07, 2026 4:52 pm     Reply with quote

Hello,
I am working on a project involving an older industrial control board that uses a standard 2x16 character LCD based on the HD44780 controller.
The issue I am facing is that the LCD is located in an inconvenient position, so I am considering removing it and instead capturing the LCD data signals and transmitting them to a remote display about 20 feet away.
The LCD interface has the typical 16-pin configuration (GND, VDD, VEE, RS, RW, E, and D0–D7, plus backlight pins A and K). All data lines D0–D7 are currently connected between the controller board and the LCD.
I have tried probing the signals with an oscilloscope, mainly focusing on RS, E, and the data lines, but it is difficult to clearly determine whether the system is operating in 4-bit or 8-bit mode. I do see valid square pulses on RS and E, but the data lines are not easy to interpret due to timing and overlap.
I also noticed if the LCD is plugged in after the system is already powered on, it displays solid blocks on the first line and nothing on the second line. However, if the system is reset with the LCD already connected, it works correctly. This makes me believe the initialization sequence is only executed at startup.

My main questions are:
What is the best practical method to reliably capture HD44780 LCD data in this type of system using PIC microcontroller?
Is there a recommended way to determine whether the interface is running in 4-bit or 8-bit mode without a logic analyzer?
For a 20-foot distance, would you recommend directly extending the LCD signals, or is it better to decode and retransmit the data using a microcontroller? I tried to use a shielded cables but will not work past 3 feet. I also prefer to get it on a PC monitor.
My goal is to reliably replicate the LCD output at a remote location without affecting the original system’s operation.

Thank you for your time and any guidance you can provide.
newguy



Joined: 24 Jun 2004
Posts: 1937

View user's profile Send private message

PostPosted: Fri May 08, 2026 3:32 pm     Reply with quote

Have a look in the code library for PCM programmer's flex LCD driver. Understand that and you'll understand everything to do with your current predicament. Probe & examine the 8 data lines, RW and E lines. Nothing else has to do with the data/driver itself.

For your remote display issue, it all starts with decoding the lines first and foremost and then tying everything back to display commands (i.e. erase screen, cursor position, etc.) and actual data to display. Again, using the driver as a starting point you'll be able to interpret the commands. Once you've worked out the interpretation, it's up to you to come up with your own bespoke comm link to relay what's happening on the main display so that it can be copied on the remote display. 20' is a good distance and I recommend you implement some form of differential signalling between main display and remote display unit. The remote will require a microcontroller and your main display will likewise require some custom PCBA with micro running some sort of 'sniff & transmit' code. I recommend differential signalling due to the noise immunity such a format affords.
temtronic



Joined: 01 Jul 2010
Posts: 9641
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Fri May 08, 2026 5:24 pm     Reply with quote

to add to Newguy's post......
Be sure to get the HD44780 data sheet ! You'll need it to decode how the LCD module is setup and the tricky part, to 'sync' the PIC with the LCD data.

for the hardware...
Be sure to use 'buffers' between the 'industrial control board' and your 'sniffer' PIC. That way you won't destroy anything.
Probably best to use 'serial' and RS-485 chips between your PICs. Easy to do and allows a PC running a terminal program to display and confirm 'data' is correct.
Ttelmah



Joined: 11 Mar 2010
Posts: 20086

View user's profile Send private message

PostPosted: Sat May 09, 2026 5:56 am     Reply with quote

I think you are missing what he wants to do!!... Very Happy
He wants to extend the data cables driving an existing Hitachi style
LCD controller 20'. He is talking about two possible routes:
1) transceivers to give the extended length.
or
2) 'sniff' the LCD transactions with a PIC, and then recreate these at
the other end. Obviously PCM Programmer's driver could help with
the 'recreation', but not with any of the other stuff.

Now the big question is how noisy the environment actually 'is'. TTL
signals can even ho this far in a low noise situation, but as distance goes
up you have increasing need for protection. It is 'borderline far'.

On sniffing with a scope, you should be able to turn off 'auto' on the scope
and sync to the 'E' signal, and then see what is going on. If all eight
data lines are connected, they are probably used.
Doing a PIC based sniffer would require using a fast chip, and handling
the sampling 'in line'. not using an interrupt, since the speed could easily
be faster than the PIC can easily sample. You need to work out if the
connection to the display is a simple 'output', or bidirectional. If the
latter, it makes all approaches much harder.
Find out how many lines are actually used, whether the data is bi-directional,
and the speed being used. We may then be able to suggest a way to go.
temtronic



Joined: 01 Jul 2010
Posts: 9641
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Sun May 10, 2026 5:05 pm     Reply with quote

hmm, thinking on this again..
..it's only 20'.

74LS244 buffer should do the trick as an 'extender'. It's a fast device with good current capability.

Might be a 'one chip' solution ??
Sam_40



Joined: 07 Jan 2015
Posts: 131

View user's profile Send private message

PostPosted: Sun May 10, 2026 7:34 pm     Reply with quote

Thank you for the reply.
I’m familiar with the PCM programmer's flex LCD driver and the 8-bit mode, as I’ve used both in the past. However, I’m not sure how they relate to my current project. The target board is running in 8-bit mode with all data pins connected. I also confirmed the 8 bit mode myself. The LCD datasheet indicates it uses the ST7066 processor, which I understand is compatible with the HD44780. I tried using a buffer, but even with an LCD at the other end, it failed because I couldn't change the direction of the busy flag, and the parallel data cable length is limited. My current plan is to use a PIC18F4685 to emulate the LCD, then send the captured data via a MAX232 to a PC terminal. Is this doable? If so, what would be the best approach?
Thanks in advance!
Ttelmah



Joined: 11 Mar 2010
Posts: 20086

View user's profile Send private message

PostPosted: Mon May 11, 2026 1:11 am     Reply with quote

Exactly.
I realised this was not really applicable for that you wanted.
The big question/problem, is whether the controller uses the R/W connection?.
If it doesn't, then as Jay says, I think the easiest way, would just be
to add a data buffer chip, and send the signals directly. I'd probably
suggest adding some trapping/suppression at the far end.
If however the unit does use the R/W connection, the problem appears
of the buffering having to be bi-directional, and the signalling will get a
lot more complex. In this case, trying to 'snoop' the LCD might be worth
trying. For this you would actually have to program the PIC to be a direct
emulation of the Hitachi controller. It'd need to support 4bit mode and 8 bit
mode (remember the controller wakes in 4 bit mode, and is then turned
up to 8 bit mode as part of the initialisation), and basically grab the
commands and data, then forward these to a second unit at the display.
This link will be relatively complex (since the data rate will need to be
quite high), so probably worth using something like RS485 at a high rate.
At this 'slave' you could then use PCM Programmer's code to actually
drive the display here.
So you need to find out is the R/W connection is used, and answer about
the noise.


Last edited by Ttelmah on Mon May 11, 2026 6:50 am; edited 1 time in total
Sam_40



Joined: 07 Jan 2015
Posts: 131

View user's profile Send private message

PostPosted: Mon May 11, 2026 4:30 am     Reply with quote

Yes, The RW pin is used and I saw it toggling. what should be the sequence of operation in your opinion? I read both datasheets and I saw everything start at the rising edge of E, but i also noticed in the ST7066 that the data is valid from the rising edge of E to the second rising?
Ttelmah



Joined: 11 Mar 2010
Posts: 20086

View user's profile Send private message

PostPosted: Mon May 11, 2026 7:40 am     Reply with quote

The sniffer approach is going to be fairly complex. You'd need to have the
PIC give a software emulation of the display controller. Have E connect to the
interrupt input, but don't use an interrupt handler. Instead poll the
interrupt flag bit and as soon as it sets read the data. A lot will depend on
just how fast the data transfers are actually done. Ideally you would really
need to get access to a logic analyser, and see if the R/W is only used to
read from the controller, or is used to read from the display RAM. If the
latter, then I'd suggest you actually run a copy of the RAM in the PIC's
memory and return the data from this, rather than across the serial bus.
The timing of the latter might well make it too slow. You'd then have
a routine to send the display changes to the slave PIC. and have it send
these to the physical display. Some things can be ignored. for instance the
controller will send after boot the commands to switch the display to
the correct settings to handle the display, and switch the interface to
8bit. These can all be ignored, and you just handle these in the slave.
Sam_40



Joined: 07 Jan 2015
Posts: 131

View user's profile Send private message

PostPosted: Sat Jun 06, 2026 9:14 pm     Reply with quote

Hello, I have been working on this for a while now with no luck. As soon as I connect the PIC to the target board, the PIC freezes. Would you please look through my code and see if you see the issue? Thank you!
Code:

// =============================================================================
// PIC18F4685 HD44780 LCD EMULATOR
// =============================================================================
// This code makes the PIC18F4685 behave exactly like an HD44780 compatible
// LCD module. The target board connects directly to the PIC and thinks it is
// talking to a real LCD. The PIC captures all display data and sends it to
// an external device via UART for display.
//
// HARDWARE REQUIREMENTS:
// - PIC18F4685 powered at 3.3V to match the target board.
// - 10k resistor from MCLR (pin 1) to VDD (3.3V)
// - 100nF decoupling capacitor between VDD (pin 11) and GND (pin 12)
// - 100nF decoupling capacitor between VDD (pin 32) and GND (pin 31)
//
// TARGET BOARD TO PIC18F4685 CONNECTIONS:
// ----------------------------------------
// Target RS  (Register Select) --> PIC RB0 (pin 33)
// Target RW  (Read/Write)      --> PIC RB1 (pin 34)
// Target E   (Enable)          --> PIC RB2 (pin 35)
// Target D0  (Data bit 0)      --> PIC RD0 (pin 19)
// Target D1  (Data bit 1)      --> PIC RD1 (pin 20)
// Target D2  (Data bit 2)      --> PIC RD2 (pin 21)
// Target D3  (Data bit 3)      --> PIC RD3 (pin 22)
// Target D4  (Data bit 4)      --> PIC RD4 (pin 27)
// Target D5  (Data bit 5)      --> PIC RD5 (pin 28)
// Target D6  (Data bit 6)      --> PIC RD6 (pin 29)
// Target D7  (Data bit 7)      --> PIC RD7 (pin 30)  ** BIDIRECTIONAL **
// Target GND                   --> PIC GND (pin 12) and GND (pin 31)
//
//
// UART OUTPUT (sends LCD content to external device):
// ---------------------------------------------------
// PIC RC6 (pin 25) --> UART TX --> External device RX
// PIC RC7 (pin 26) --> UART RX --> External device TX
// Baud rate: 9600, 8N1
// Protocol: sends "LCD:row1data|row2data\r\n" when display changes
//
// D7 BIDIRECTIONAL OPERATION:
// ---------------------------
// During WRITE cycles: RD7 is INPUT  - reads data from target
// During READ  cycles: RD7 is OUTPUT - drives LOW to signal "not busy"
// The HD44780 busy flag is on D7. When target reads with RW=HIGH,
// it expects D7=LOW meaning "LCD is ready". We always respond LOW.
// =============================================================================

#include <18F4685.h>

// -- Oscillator and watchdog configuration -----------------------------------
#fuses INTRC_IO          // Using internal oscillator
#fuses NOWDT       // Watchdog timer disabled
#fuses NOLVP       // Low voltage programming disabled
#fuses NOPROTECT   // Code protection disabled
#fuses PUT         // Power up timer enabled - ensures clean startup

// -- Clock and UART setup ----------------------------------------------------
#use delay(clock=8000000)    // 8MHz  internal oscillator

// UART on RC6(TX) and RC7(RX) - connects to external display device
// stream=UART allows fprintf(UART,...) syntax throughout code
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, stream=UART, ERRORS)

// ============================================================================
// PIN DEFINITIONS
// ============================================================================

// LCD control signals from target board - all inputs
#define PIN_RS    PIN_B0   // Register Select: HIGH=data, LOW=command
#define PIN_RW    PIN_B1   // Read/Write:      HIGH=read, LOW=write
#define PIN_E     PIN_B2   // Enable:          data latched on falling edge

// D7 is on PORTD bit 7 - needs direction control for busy flag
// During reads we drive it LOW, during writes we read it as input
// All other PORTD pins (D0-D6) are always inputs

// Heartbeat LED - shows PIC is running
// Connect LED + 330 ohm resistor from this pin to GND
#define LED_HB    PIN_A0

// ============================================================================
// HD44780 EMULATION STATE VARIABLES
// ============================================================================

// Bus mode - set by Function Set command from target
#define MODE_8BIT 0    // All 8 data pins used, one E pulse per byte
#define MODE_4BIT 1    // Only D4-D7 used, two E pulses per byte

int8  busMode     = MODE_8BIT;  // Default 8-bit, updated by Function Set cmd
int1  gotUpperNib = 0;          // 4-bit mode: have we received upper nibble?
int8  upperNibble = 0;          // 4-bit mode: stored upper nibble value
int8  upperRS     = 0;          // 4-bit mode: RS value of upper nibble

// DDRAM - Display Data RAM, same as real HD44780
// Row 1 addresses: 0x00 to 0x27 (stored at DDRAM index 0   to 39)
// Row 2 addresses: 0x40 to 0x67 (stored at DDRAM index 64  to 103)
// Total: 104 bytes covers full HD44780 address space
int8  DDRAM[104];

// Address counter - tracks current read/write position
int8  addrCounter = 0x00;
int1  addrIsDDRAM = 1;     // 1=DDRAM addressing, 0=CGRAM addressing
int1  entryIncr   = 1;     // 1=increment after write, 0=decrement

// Flag to indicate display content has changed - triggers UART send
int1  lcdDirty = 0;

// ============================================================================
// HEARTBEAT VARIABLES
// ============================================================================
int16 hbCount = 0;    // Counter for heartbeat timing
int1  hbState = 0;    // Current LED state

// ============================================================================
// BUSY FLAG CONTROL
// Controls direction of RD7 (D7) pin
// ============================================================================

// Call this before responding to a busy flag read (RW=HIGH)
// Switches D7 to output and drives it LOW = "LCD not busy, ready"
void busy_flag_on(void) {
   // 0x7F = 0111 1111: RD7=output(0), RD0-RD6=input(1)
   set_tris_d(0x7F);
   output_low(PIN_D7);   // D7 LOW = busy flag clear = LCD ready
}

// Call this after busy flag read is complete
// Releases D7 back to input so target can drive it during writes
void busy_flag_off(void) {
   set_tris_d(0xFF);     // 0xFF = all PORTD pins are inputs
}

// ============================================================================
// SEND LCD CONTENT VIA UART
// Sends current display content to external device
// Format: "LCD:1234567890123456|1234567890123456\r\n"
//          LCD: = identifier
//          16 chars = row 1 content (DDRAM 0x00-0x0F)
//          |         = row separator
//          16 chars = row 2 content (DDRAM 0x40-0x4F)
//          \r\n      = line ending
// ============================================================================
void send_lcd(void) {
   int8 i;
   int8 c;

   // Send row 1 - DDRAM addresses 0x00 to 0x0F (index 0 to 15)
   fprintf(UART, "LCD:");
   for(i = 0; i < 16; i++) {
      c = DDRAM[i];
      // Only send printable ASCII characters, replace others with space
      fputc((c >= 32 && c < 127) ? c : ' ', UART);
   }

   // Row separator
   fputc('|', UART);

   // Send row 2 - DDRAM addresses 0x40 to 0x4F (index 64 to 79)
   for(i = 0; i < 16; i++) {
      c = DDRAM[64 + i];
      fputc((c >= 32 && c < 127) ? c : ' ', UART);
   }

   // Line ending
   fprintf(UART, "\r\n");
}

// ============================================================================
// HD44780 COMMAND DECODER
// Processes all standard HD44780 commands
// Called when RS=LOW (command register selected)
// ============================================================================
void eval_command(int8 cmd) {
   int8 i;

   // -- Clear Display (0x01) ------------------------------------------------
   // Fills all DDRAM with spaces, resets address counter to 0x00
   // Execution time on real LCD: 1.52ms (we handle instantly)
   if(cmd == 0x01) {
      for(i = 0; i < 104; i++) DDRAM[i] = ' ';
      addrCounter = 0x00;
      addrIsDDRAM = 1;
      entryIncr   = 1;
      lcdDirty    = 1;
      return;
   }

   // -- Return Home (0x02 or 0x03) ------------------------------------------
   // Moves cursor to DDRAM address 0x00, display content unchanged
   if((cmd & 0xFE) == 0x02) {
      addrCounter = 0x00;
      addrIsDDRAM = 1;
      lcdDirty    = 1;
      return;
   }

   // -- Entry Mode Set (0x04 to 0x07) ---------------------------------------
   // Bit 1: I/D = 1 means increment address after each write
   //              0 means decrement address after each write
   // Bit 0: S  = display shift (we track but don't implement shifting)
   if((cmd & 0xFC) == 0x04) {
      entryIncr = (cmd & 0x02) ? 1 : 0;
      return;
   }

   // -- Display ON/OFF Control (0x08 to 0x0F) -------------------------------
   // Bit 2: D = display on/off
   // Bit 1: C = cursor on/off
   // Bit 0: B = cursor blink on/off
   // We just mark dirty so external device updates
   if((cmd & 0xF8) == 0x08) {
      lcdDirty = 1;
      return;
   }

   // -- Function Set (0x20 to 0x3F) -----------------------------------------
   // Bit 4: DL = 1 means 8-bit bus, 0 means 4-bit bus
   // Bit 3: N  = number of lines (1 or 2)
   // Bit 2: F  = font size (5x8 or 5x11)
   // This command determines how we read the data bus
   if((cmd & 0xE0) == 0x20) {
      if(cmd & 0x10) {
         // DL=1: 8-bit mode - one E pulse per complete byte
         busMode = MODE_8BIT;
      } else {
         // DL=0: 4-bit mode - two E pulses per byte (upper then lower nibble)
         busMode = MODE_4BIT;
      }
      gotUpperNib = 0;   // Reset nibble state on mode change
      return;
   }

   // -- Set CGRAM Address (0x40 to 0x7F) ------------------------------------
   // Switches address counter to CGRAM (custom character RAM)
   // Subsequent data writes go to CGRAM until DDRAM address is set
   if((cmd & 0xC0) == 0x40) {
      addrCounter = cmd & 0x3F;
      addrIsDDRAM = 0;
      return;
   }

   // -- Set DDRAM Address (0x80 and above) ----------------------------------
   // Moves cursor to specified DDRAM address
   // Row 1: addresses 0x00-0x27
   // Row 2: addresses 0x40-0x67
   if(cmd & 0x80) {
      addrCounter = cmd & 0x7F;   // Strip bit 7 to get address
      addrIsDDRAM = 1;
      return;
   }
}

// ============================================================================
// PROCESS ONE COMPLETE BYTE
// Called after a full byte has been received (both nibbles in 4-bit mode)
// rs=1 means data write to DDRAM/CGRAM
// rs=0 means command write to instruction register
// ============================================================================
void process_byte(int8 rs, int8 data) {
   if(rs == 1) {
      // -- Data write - store character in DDRAM ----------------------------
      if(addrIsDDRAM) {
         // Row 1: DDRAM 0x00-0x27 stored at array index 0-39
         if(addrCounter <= 0x27) {
            DDRAM[addrCounter] = data;
            lcdDirty = 1;
         }
         // Row 2: DDRAM 0x40-0x67 stored at array index 64-103
         else if(addrCounter >= 0x40 && addrCounter <= 0x67) {
            DDRAM[addrCounter] = data;
            lcdDirty = 1;
         }
         // Addresses outside valid range are ignored
      }
      // Advance address counter after each write
      if(entryIncr) addrCounter++;
      else          addrCounter--;

   } else {
      // -- Command write - decode and execute -------------------------------
      eval_command(data);
   }
}

// ============================================================================
// MAIN PROGRAM
// ============================================================================
void main(void) {
   int8  i;
   int8  rs;        // Register Select value read from target
   int8  rw;        // Read/Write value read from target
   int8  data;      // Data byte read from PORTD
   int8  nib;       // Nibble for 4-bit mode
   int32 timeout;   // Timeout counter for E wait loops

   // -- Initialize DDRAM with spaces ----------------------------------------
   for(i = 0; i < 104; i++) DDRAM[i] = ' ';

   // -- Configure PORTD as inputs (data bus) --------------------------------
   // All 8 data pins start as inputs
   // RD7 switches to output only during busy flag reads
   set_tris_d(0xFF);

   // -- Configure PORTB as inputs (control signals) -------------------------
   // RB0=RS, RB1=RW, RB2=E all driven by target board
   // External 10k pullups on RB0, RB1, RB2 required
   set_tris_b(0xFF);

   // -- Disable analog inputs -----------------------------------------------
   // PORTB and PORTA default to analog on PIC18F4685
   // Must disable analog to use as digital inputs
   setup_adc_ports(NO_ANALOGS);

   // -- Configure heartbeat LED on RA0 --------------------------------------
   output_low(LED_HB);
   set_tris_a(0x00);    // All PORTA as outputs

   // -- Stabilization delay -------------------------------------------------
   // Allow crystal oscillator and power supply to stabilize
   delay_ms(500);

   // -- Signal ready to external device via UART ----------------------------
   fprintf(UART, "READY\r\n");

   // =========================================================================
   // MAIN POLLING LOOP
   // Polls E pin continuously looking for falling edges from target board
   // =========================================================================
   while(1) {

      // -- Heartbeat LED ---------------------------------------------------
      // Toggles approximately every 0.5 seconds to show PIC is alive
      // If LED stops blinking, PIC is frozen in a wait loop
      hbCount++;
      if(hbCount > 20000) {
         hbCount = 0;
         hbState = !hbState;
         if(hbState) output_high(LED_HB);
         else        output_low(LED_HB);
      }

      // -- Check for E falling edge ----------------------------------------
      // Target drives E LOW to start a transaction
      if(!input(PIN_E)) {

         // Read control signals immediately while E is LOW
         // Data on PORTD is valid and stable while E is LOW
         rs = input(PIN_RS);   // 1=data register, 0=command register
         rw = input(PIN_RW);   // 1=read from LCD, 0=write to LCD

         if(rw == 1) {
            // ---------------------------------------------------------------
            // READ CYCLE - target is reading from LCD (busy flag check)
            // Target sets RW=HIGH, RS=LOW, then pulses E HIGH then LOW
            // We must drive D7 LOW during the entire E HIGH period
            // D7=LOW means "LCD not busy, ready for next command"
            // ---------------------------------------------------------------
            busy_flag_on();    // Drive D7 LOW immediately

            // Wait for E to go HIGH - target samples D7 while E is HIGH
            // No timeout here - we MUST hold D7 LOW until E goes HIGH
            // This is required by HD44780 protocol
            while(!input(PIN_E));

            // E went HIGH - target has sampled our D7=LOW response
            // Now wait for E to go LOW again (end of read cycle)
            while(input(PIN_E));

            busy_flag_off();   // Release D7 back to input

         } else {
            // ---------------------------------------------------------------
            // WRITE CYCLE - target is writing command or data to LCD
            // Target has placed data on D0-D7 and driven E LOW
            // We read PORTD in one instruction - all 8 bits simultaneously
            // This is the critical advantage of using PIC with PORTD
            // ---------------------------------------------------------------
            data = input_d();  // Read all 8 data pins in ONE instruction

            // Wait for E to go HIGH - data is valid while E is LOW
            // Use timeout to prevent freeze if target has wiring issue
            timeout = 0;
            while(!input(PIN_E)) {
               timeout++;
               if(timeout > 100000L) break; 
            }

            // Process the received byte
            if(busMode == MODE_8BIT) {
               // 8-bit mode: one E pulse = one complete byte
               process_byte(rs, data);

            } else {
               // 4-bit mode: two E pulses = one complete byte
               // First pulse carries upper nibble on D4-D7
               // Second pulse carries lower nibble on D4-D7
               nib = (data >> 4) & 0x0F;

               if(!gotUpperNib) {
                  // First nibble received - store and wait for second
                  upperNibble = nib;
                  upperRS     = rs;
                  gotUpperNib = 1;
               } else {
                  // Second nibble received - assemble and process full byte
                  data = (upperNibble << 4) | nib;
                  gotUpperNib = 0;
                  process_byte(upperRS, data);
               }
            }
         }

         // Wait for E to return HIGH before processing next transaction
         // Prevents detecting same pulse twice
         timeout = 0;
         while(!input(PIN_E)) {
            timeout++;
            if(timeout > 100000L) break;
         }

         // Brief settling time before next sample
         delay_us(5);
      }

      // -- Send LCD update via UART when content changes -------------------
      // Only sends when lcdDirty flag is set by process_byte or eval_command
      // Sending only on change keeps UART traffic minimal
      if(lcdDirty) {
         lcdDirty = 0;
         send_lcd();
      }
   }
}
Ttelmah



Joined: 11 Mar 2010
Posts: 20086

View user's profile Send private message

PostPosted: Sat Jun 06, 2026 10:58 pm     Reply with quote

Several things:

First you delay 500mSec at boot. The LCD must be ready in 90mSec
from POR. You may well be ready too late.
Then you have 8bit mode as the default. This is not true. All these LCD's
wake up in 4bit mode, and have to be switched to 8bit by their
initialisation code.
Then speed. The Hitachi format requires the E pulse to only be 1uSec
minimum. At 8MHz master clock, you are just not fast enough to handle
things if the main CPU is sending stuff at all quickly.
Then speed #2. You are sending a huge number of bytes for a single
arriving byte. You either need to increase the transmission speed a lot
or have a lot of transmit buffering. In fact this latter is required even
if the speed is raised.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group