Hello everyone,
“I’m upgrading my display screen to a CFAF320240F-035T TFT and switching from SPI to an 8-bit parallel interface. I’m having trouble getting it to work, so far the screen only shows solid white. I’ve been testing with simple sketches, and while the screen sometimes pulses slightly between shades of white, it never changes colors the way the sketch is programmed to. Does any have any tips or ideas why this isn't working? Here is a photo of how the screen is plugged into the carrier board and my pin layout into the Teensy 4.1. I have attached the code as well. Thanks for any help!
Here is the test sketch aswell
//==============================================================================
//
// Fixed version for Teensy 4.1 with 8-bit 8080 parallel mode
// CRYSTALFONTZ CFAF320240F-035T 320x240 COLOR 3.5" TFT
//
//==============================================================================
// Pin definitions for 8080 parallel interface
#define LCD_D0 14
#define LCD_D1 15
#define LCD_D2 16
#define LCD_D3 17
#define LCD_D4 18
#define LCD_D5 19
#define LCD_D6 20
#define LCD_D7 21
#define LCD_WR 22 // Write strobe (active low)
#define LCD_RD 23 // Read strobe (active low) - keep high
#define LCD_RS 2 // RS/DC (Data/Command)
#define LCD_CS 3 // Chip select (active low)
#define LCD_RESET 4 // Reset (active low)
#define LCD_BL 5 // Backlight
// Touch screen pins
#define TS_XL A0
#define TS_XR A1
#define TS_YD A2
#define TS_YU A3
//==============================================================================
// Function to write 8-bit data to parallel bus
void writeData8(uint8_t data)
{
digitalWriteFast(LCD_D0, (data & 0x01) ? HIGH : LOW);
digitalWriteFast(LCD_D1, (data & 0x02) ? HIGH : LOW);
digitalWriteFast(LCD_D2, (data & 0x04) ? HIGH : LOW);
digitalWriteFast(LCD_D3, (data & 0x08) ? HIGH : LOW);
digitalWriteFast(LCD_D4, (data & 0x10) ? HIGH : LOW);
digitalWriteFast(LCD_D5, (data & 0x20) ? HIGH : LOW);
digitalWriteFast(LCD_D6, (data & 0x40) ? HIGH : LOW);
digitalWriteFast(LCD_D7, (data & 0x80) ? HIGH : LOW);
}
//==============================================================================
void LCD_sendCommand(uint8_t command)
{
digitalWriteFast(LCD_RS, LOW); // Command mode
digitalWriteFast(LCD_CS, LOW); // Select LCD
writeData8(command);
digitalWriteFast(LCD_WR, LOW); // Write strobe
__asm__ __volatile__ ("nop\n\t nop\n\t nop\n\t nop\n\t"); // ~80ns delay at 600MHz
digitalWriteFast(LCD_WR, HIGH);
digitalWriteFast(LCD_CS, HIGH); // Deselect LCD
}
//==============================================================================
void LCD_sendData8(uint8_t data)
{
digitalWriteFast(LCD_RS, HIGH); // Data mode
digitalWriteFast(LCD_CS, LOW); // Select LCD
writeData8(data);
digitalWriteFast(LCD_WR, LOW); // Write strobe
__asm__ __volatile__ ("nop\n\t nop\n\t nop\n\t nop\n\t"); // ~80ns delay
digitalWriteFast(LCD_WR, HIGH);
digitalWriteFast(LCD_CS, HIGH); // Deselect LCD
}
//==============================================================================
void LCD_sendData16(uint16_t data)
{
// Send as two 8-bit writes (MSB first)
LCD_sendData8(data >> 8);
LCD_sendData8(data & 0xFF);
}
//==============================================================================
void Initialize_LCD(void)
{
Serial.println("Starting LCD initialization...");
// Reset sequence
digitalWriteFast(LCD_RESET, LOW);
delay(10);
digitalWriteFast(LCD_RESET, HIGH);
delay(120);
Serial.println("Sending initialization commands...");
// Entry Mode - very important for 8080 mode
LCD_sendCommand(0x0011);
LCD_sendData16(0x6870); // Set for 8080 interface mode
delay(10);
LCD_sendCommand(0x0028); // VCOM OTP
LCD_sendData16(0x0006);
LCD_sendCommand(0x0000); // start Oscillator
LCD_sendData16(0x0001);
LCD_sendCommand(0x0010); // Sleep mode
LCD_sendData16(0x0000);
LCD_sendCommand(0x0001); // Driver Output Control
LCD_sendData16(0x72EF); // Mirror RL
LCD_sendCommand(0x0002); // LCD Driving Waveform Control
LCD_sendData16(0x0600);
LCD_sendCommand(0x0003); // Power Control 1
LCD_sendData16(0x6A38);
LCD_sendCommand(0X000F); // Gate Scan Position
LCD_sendData16(0x0000);
LCD_sendCommand(0X000B); // Frame Cycle Control
LCD_sendData16(0x5308);
LCD_sendCommand(0x000C); // Power Control 2
LCD_sendData16(0x0003);
LCD_sendCommand(0x000D); // Power Control 3
LCD_sendData16(0x000A);
LCD_sendCommand(0x000E); // Power Control 4
LCD_sendData16(0x2E00);
LCD_sendCommand(0x001E); // Power Control 5
LCD_sendData16(0x00B7);
LCD_sendCommand(0x0025); // Frame Frequency Control
LCD_sendData16(0x8000);
LCD_sendCommand(0x0026); // Analog setting
LCD_sendData16(0x3800);
LCD_sendCommand(0x0027); // Critical setting
LCD_sendData16(0x0078);
// Gamma Control
LCD_sendCommand(0x0030); LCD_sendData16(0x0000);
LCD_sendCommand(0x0031); LCD_sendData16(0x0104);
LCD_sendCommand(0x0032); LCD_sendData16(0x0100);
LCD_sendCommand(0x0033); LCD_sendData16(0x0305);
LCD_sendCommand(0x0034); LCD_sendData16(0x0505);
LCD_sendCommand(0x0035); LCD_sendData16(0x0305);
LCD_sendCommand(0x0036); LCD_sendData16(0x0707);
LCD_sendCommand(0x0037); LCD_sendData16(0x0300);
LCD_sendCommand(0x003A); LCD_sendData16(0x1200);
LCD_sendCommand(0x003B); LCD_sendData16(0x0800);
// Wake up and display on
LCD_sendCommand(0x0007); // Display Control
LCD_sendData16(0x0033);
LCD_sendCommand(0x0044); // Vertical RAM address position
LCD_sendData16(0xEF00);
LCD_sendCommand(0x0045); // Horizontal RAM address position
LCD_sendData16(0x0000);
LCD_sendCommand(0x0046); // Horizontal RAM address position
LCD_sendData16(0x013F);
LCD_sendCommand(0x004E); // RAM address set X
LCD_sendData16(0x0000);
LCD_sendCommand(0x004F); // RAM address set Y
LCD_sendData16(0x0000);
LCD_sendCommand(0x0012); // Sleep mode control
LCD_sendData16(0x0D99);
delay(50);
LCD_sendCommand(0x0022); // RAM data write/read
// Exit sleep and turn on display
LCD_sendCommand(0x0010); // Sleep mode
LCD_sendData16(0x0000); // Sleep OUT
delay(200);
LCD_sendCommand(0x0007); // Display Control
LCD_sendData16(0x0033); // Display ON
Serial.println("LCD initialization complete");
}
//==============================================================================
void setWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1)
{
LCD_sendCommand(0x0044); // Vertical RAM address position
LCD_sendData16((y1 << 8) | y0);
LCD_sendCommand(0x0045); // Horizontal RAM address position
LCD_sendData16(x0);
LCD_sendCommand(0x0046); // Horizontal RAM address position
LCD_sendData16(x1);
LCD_sendCommand(0x004E); // RAM address set X
LCD_sendData16(x0);
LCD_sendCommand(0x004F); // RAM address set Y
LCD_sendData16(y0);
LCD_sendCommand(0x0022); // RAM data write/read
}
//==============================================================================
void fillScreen(uint16_t color)
{
Serial.print("Filling screen with color: 0x");
Serial.println(color, HEX);
setWindow(0, 0, 319, 239);
digitalWriteFast(LCD_RS, HIGH); // Data mode
digitalWriteFast(LCD_CS, LOW); // Select LCD and keep selected
for (uint32_t i = 0; i < 76800UL; i++) // 320*240 = 76800
{
// Send MSB
writeData8(color >> 8);
digitalWriteFast(LCD_WR, LOW);
__asm__ __volatile__ ("nop\n\t nop\n\t");
digitalWriteFast(LCD_WR, HIGH);
// Send LSB
writeData8(color & 0xFF);
digitalWriteFast(LCD_WR, LOW);
__asm__ __volatile__ ("nop\n\t nop\n\t");
digitalWriteFast(LCD_WR, HIGH);
}
digitalWriteFast(LCD_CS, HIGH); // Deselect LCD
Serial.println("Screen fill complete");
}
//==============================================================================
void drawPixel(uint16_t x, uint16_t y, uint16_t color)
{
setWindow(x, y, x, y);
LCD_sendData16(color);
}
//==============================================================================
void testBasicDrawing()
{
Serial.println("Testing basic drawing...");
// Fill screen with different colors to test
fillScreen(0x0000); // Black
delay(1000);
fillScreen(0xF800); // Red
delay(1000);
fillScreen(0x07E0); // Green
delay(1000);
fillScreen(0x001F); // Blue
delay(1000);
fillScreen(0xFFFF); // White
delay(1000);
// Draw some pixels
fillScreen(0x0000); // Black background
for(int i = 0; i < 100; i++)
{
drawPixel(i, i, 0xFFFF); // White diagonal line
}
Serial.println("Basic drawing test complete");
}
//==============================================================================
void setup()
{
Serial.begin(115200);
delay(1000);
Serial.println("CFAF320240F-035T Teensy 4.1 8080 Mode Test");
// Set up control pins
pinMode(LCD_RS, OUTPUT);
pinMode(LCD_CS, OUTPUT);
pinMode(LCD_WR, OUTPUT);
pinMode(LCD_RD, OUTPUT);
pinMode(LCD_RESET, OUTPUT);
pinMode(LCD_BL, OUTPUT);
// Set up data bus pins as outputs
pinMode(LCD_D0, OUTPUT);
pinMode(LCD_D1, OUTPUT);
pinMode(LCD_D2, OUTPUT);
pinMode(LCD_D3, OUTPUT);
pinMode(LCD_D4, OUTPUT);
pinMode(LCD_D5, OUTPUT);
pinMode(LCD_D6, OUTPUT);
pinMode(LCD_D7, OUTPUT);
// Initialize control signals
digitalWriteFast(LCD_CS, HIGH); // Deselect LCD
digitalWriteFast(LCD_WR, HIGH); // Write strobe idle high
digitalWriteFast(LCD_RD, HIGH); // Read strobe idle high
digitalWriteFast(LCD_RS, LOW); // Start in command mode
digitalWriteFast(LCD_RESET, HIGH); // Reset inactive
digitalWriteFast(LCD_BL, HIGH); // Turn on backlight
delay(100);
Serial.println("Pins configured, starting LCD initialization...");
// Initialize the LCD
Initialize_LCD();
Serial.println("Running basic drawing test...");
testBasicDrawing();
}
//==============================================================================
void loop()
{
// Simple color cycling test
static uint8_t colorTest = 0;
switch(colorTest)
{
case 0: fillScreen(0xF800); break; // Red
case 1: fillScreen(0x07E0); break; // Green
case 2: fillScreen(0x001F); break; // Blue
case 3: fillScreen(0xFFE0); break; // Yellow
case 4: fillScreen(0xF81F); break; // Magenta
case 5: fillScreen(0x07FF); break; // Cyan
case 6: fillScreen(0xFFFF); break; // White
case 7: fillScreen(0x0000); break; // Black
}
colorTest = (colorTest + 1) % 8;
delay(2000);
}
“I’m upgrading my display screen to a CFAF320240F-035T TFT and switching from SPI to an 8-bit parallel interface. I’m having trouble getting it to work, so far the screen only shows solid white. I’ve been testing with simple sketches, and while the screen sometimes pulses slightly between shades of white, it never changes colors the way the sketch is programmed to. Does any have any tips or ideas why this isn't working? Here is a photo of how the screen is plugged into the carrier board and my pin layout into the Teensy 4.1. I have attached the code as well. Thanks for any help!
| TFT | Teensy 4.1 pin | Notes |
| D0..D7 | 14,15,16,17,18,19,20,21 | 8-bit data bus (LSB→MSB) |
| WR (Write) | 22 | Active-low write strobe |
| RD (Read) | 23 | Usually kept high if you don’t read; still connect for compatibility |
| RS/DC | 2 | Data/Command (aka RS) |
| CS | 3 | TFT chip select |
| RESET | 4 | TFT reset |
| BL (Backlight) | 5 (PWM optional) | Drive via N-MOSFET if high current; or direct if module has onboard driver |
//==============================================================================
//
// Fixed version for Teensy 4.1 with 8-bit 8080 parallel mode
// CRYSTALFONTZ CFAF320240F-035T 320x240 COLOR 3.5" TFT
//
//==============================================================================
// Pin definitions for 8080 parallel interface
#define LCD_D0 14
#define LCD_D1 15
#define LCD_D2 16
#define LCD_D3 17
#define LCD_D4 18
#define LCD_D5 19
#define LCD_D6 20
#define LCD_D7 21
#define LCD_WR 22 // Write strobe (active low)
#define LCD_RD 23 // Read strobe (active low) - keep high
#define LCD_RS 2 // RS/DC (Data/Command)
#define LCD_CS 3 // Chip select (active low)
#define LCD_RESET 4 // Reset (active low)
#define LCD_BL 5 // Backlight
// Touch screen pins
#define TS_XL A0
#define TS_XR A1
#define TS_YD A2
#define TS_YU A3
//==============================================================================
// Function to write 8-bit data to parallel bus
void writeData8(uint8_t data)
{
digitalWriteFast(LCD_D0, (data & 0x01) ? HIGH : LOW);
digitalWriteFast(LCD_D1, (data & 0x02) ? HIGH : LOW);
digitalWriteFast(LCD_D2, (data & 0x04) ? HIGH : LOW);
digitalWriteFast(LCD_D3, (data & 0x08) ? HIGH : LOW);
digitalWriteFast(LCD_D4, (data & 0x10) ? HIGH : LOW);
digitalWriteFast(LCD_D5, (data & 0x20) ? HIGH : LOW);
digitalWriteFast(LCD_D6, (data & 0x40) ? HIGH : LOW);
digitalWriteFast(LCD_D7, (data & 0x80) ? HIGH : LOW);
}
//==============================================================================
void LCD_sendCommand(uint8_t command)
{
digitalWriteFast(LCD_RS, LOW); // Command mode
digitalWriteFast(LCD_CS, LOW); // Select LCD
writeData8(command);
digitalWriteFast(LCD_WR, LOW); // Write strobe
__asm__ __volatile__ ("nop\n\t nop\n\t nop\n\t nop\n\t"); // ~80ns delay at 600MHz
digitalWriteFast(LCD_WR, HIGH);
digitalWriteFast(LCD_CS, HIGH); // Deselect LCD
}
//==============================================================================
void LCD_sendData8(uint8_t data)
{
digitalWriteFast(LCD_RS, HIGH); // Data mode
digitalWriteFast(LCD_CS, LOW); // Select LCD
writeData8(data);
digitalWriteFast(LCD_WR, LOW); // Write strobe
__asm__ __volatile__ ("nop\n\t nop\n\t nop\n\t nop\n\t"); // ~80ns delay
digitalWriteFast(LCD_WR, HIGH);
digitalWriteFast(LCD_CS, HIGH); // Deselect LCD
}
//==============================================================================
void LCD_sendData16(uint16_t data)
{
// Send as two 8-bit writes (MSB first)
LCD_sendData8(data >> 8);
LCD_sendData8(data & 0xFF);
}
//==============================================================================
void Initialize_LCD(void)
{
Serial.println("Starting LCD initialization...");
// Reset sequence
digitalWriteFast(LCD_RESET, LOW);
delay(10);
digitalWriteFast(LCD_RESET, HIGH);
delay(120);
Serial.println("Sending initialization commands...");
// Entry Mode - very important for 8080 mode
LCD_sendCommand(0x0011);
LCD_sendData16(0x6870); // Set for 8080 interface mode
delay(10);
LCD_sendCommand(0x0028); // VCOM OTP
LCD_sendData16(0x0006);
LCD_sendCommand(0x0000); // start Oscillator
LCD_sendData16(0x0001);
LCD_sendCommand(0x0010); // Sleep mode
LCD_sendData16(0x0000);
LCD_sendCommand(0x0001); // Driver Output Control
LCD_sendData16(0x72EF); // Mirror RL
LCD_sendCommand(0x0002); // LCD Driving Waveform Control
LCD_sendData16(0x0600);
LCD_sendCommand(0x0003); // Power Control 1
LCD_sendData16(0x6A38);
LCD_sendCommand(0X000F); // Gate Scan Position
LCD_sendData16(0x0000);
LCD_sendCommand(0X000B); // Frame Cycle Control
LCD_sendData16(0x5308);
LCD_sendCommand(0x000C); // Power Control 2
LCD_sendData16(0x0003);
LCD_sendCommand(0x000D); // Power Control 3
LCD_sendData16(0x000A);
LCD_sendCommand(0x000E); // Power Control 4
LCD_sendData16(0x2E00);
LCD_sendCommand(0x001E); // Power Control 5
LCD_sendData16(0x00B7);
LCD_sendCommand(0x0025); // Frame Frequency Control
LCD_sendData16(0x8000);
LCD_sendCommand(0x0026); // Analog setting
LCD_sendData16(0x3800);
LCD_sendCommand(0x0027); // Critical setting
LCD_sendData16(0x0078);
// Gamma Control
LCD_sendCommand(0x0030); LCD_sendData16(0x0000);
LCD_sendCommand(0x0031); LCD_sendData16(0x0104);
LCD_sendCommand(0x0032); LCD_sendData16(0x0100);
LCD_sendCommand(0x0033); LCD_sendData16(0x0305);
LCD_sendCommand(0x0034); LCD_sendData16(0x0505);
LCD_sendCommand(0x0035); LCD_sendData16(0x0305);
LCD_sendCommand(0x0036); LCD_sendData16(0x0707);
LCD_sendCommand(0x0037); LCD_sendData16(0x0300);
LCD_sendCommand(0x003A); LCD_sendData16(0x1200);
LCD_sendCommand(0x003B); LCD_sendData16(0x0800);
// Wake up and display on
LCD_sendCommand(0x0007); // Display Control
LCD_sendData16(0x0033);
LCD_sendCommand(0x0044); // Vertical RAM address position
LCD_sendData16(0xEF00);
LCD_sendCommand(0x0045); // Horizontal RAM address position
LCD_sendData16(0x0000);
LCD_sendCommand(0x0046); // Horizontal RAM address position
LCD_sendData16(0x013F);
LCD_sendCommand(0x004E); // RAM address set X
LCD_sendData16(0x0000);
LCD_sendCommand(0x004F); // RAM address set Y
LCD_sendData16(0x0000);
LCD_sendCommand(0x0012); // Sleep mode control
LCD_sendData16(0x0D99);
delay(50);
LCD_sendCommand(0x0022); // RAM data write/read
// Exit sleep and turn on display
LCD_sendCommand(0x0010); // Sleep mode
LCD_sendData16(0x0000); // Sleep OUT
delay(200);
LCD_sendCommand(0x0007); // Display Control
LCD_sendData16(0x0033); // Display ON
Serial.println("LCD initialization complete");
}
//==============================================================================
void setWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1)
{
LCD_sendCommand(0x0044); // Vertical RAM address position
LCD_sendData16((y1 << 8) | y0);
LCD_sendCommand(0x0045); // Horizontal RAM address position
LCD_sendData16(x0);
LCD_sendCommand(0x0046); // Horizontal RAM address position
LCD_sendData16(x1);
LCD_sendCommand(0x004E); // RAM address set X
LCD_sendData16(x0);
LCD_sendCommand(0x004F); // RAM address set Y
LCD_sendData16(y0);
LCD_sendCommand(0x0022); // RAM data write/read
}
//==============================================================================
void fillScreen(uint16_t color)
{
Serial.print("Filling screen with color: 0x");
Serial.println(color, HEX);
setWindow(0, 0, 319, 239);
digitalWriteFast(LCD_RS, HIGH); // Data mode
digitalWriteFast(LCD_CS, LOW); // Select LCD and keep selected
for (uint32_t i = 0; i < 76800UL; i++) // 320*240 = 76800
{
// Send MSB
writeData8(color >> 8);
digitalWriteFast(LCD_WR, LOW);
__asm__ __volatile__ ("nop\n\t nop\n\t");
digitalWriteFast(LCD_WR, HIGH);
// Send LSB
writeData8(color & 0xFF);
digitalWriteFast(LCD_WR, LOW);
__asm__ __volatile__ ("nop\n\t nop\n\t");
digitalWriteFast(LCD_WR, HIGH);
}
digitalWriteFast(LCD_CS, HIGH); // Deselect LCD
Serial.println("Screen fill complete");
}
//==============================================================================
void drawPixel(uint16_t x, uint16_t y, uint16_t color)
{
setWindow(x, y, x, y);
LCD_sendData16(color);
}
//==============================================================================
void testBasicDrawing()
{
Serial.println("Testing basic drawing...");
// Fill screen with different colors to test
fillScreen(0x0000); // Black
delay(1000);
fillScreen(0xF800); // Red
delay(1000);
fillScreen(0x07E0); // Green
delay(1000);
fillScreen(0x001F); // Blue
delay(1000);
fillScreen(0xFFFF); // White
delay(1000);
// Draw some pixels
fillScreen(0x0000); // Black background
for(int i = 0; i < 100; i++)
{
drawPixel(i, i, 0xFFFF); // White diagonal line
}
Serial.println("Basic drawing test complete");
}
//==============================================================================
void setup()
{
Serial.begin(115200);
delay(1000);
Serial.println("CFAF320240F-035T Teensy 4.1 8080 Mode Test");
// Set up control pins
pinMode(LCD_RS, OUTPUT);
pinMode(LCD_CS, OUTPUT);
pinMode(LCD_WR, OUTPUT);
pinMode(LCD_RD, OUTPUT);
pinMode(LCD_RESET, OUTPUT);
pinMode(LCD_BL, OUTPUT);
// Set up data bus pins as outputs
pinMode(LCD_D0, OUTPUT);
pinMode(LCD_D1, OUTPUT);
pinMode(LCD_D2, OUTPUT);
pinMode(LCD_D3, OUTPUT);
pinMode(LCD_D4, OUTPUT);
pinMode(LCD_D5, OUTPUT);
pinMode(LCD_D6, OUTPUT);
pinMode(LCD_D7, OUTPUT);
// Initialize control signals
digitalWriteFast(LCD_CS, HIGH); // Deselect LCD
digitalWriteFast(LCD_WR, HIGH); // Write strobe idle high
digitalWriteFast(LCD_RD, HIGH); // Read strobe idle high
digitalWriteFast(LCD_RS, LOW); // Start in command mode
digitalWriteFast(LCD_RESET, HIGH); // Reset inactive
digitalWriteFast(LCD_BL, HIGH); // Turn on backlight
delay(100);
Serial.println("Pins configured, starting LCD initialization...");
// Initialize the LCD
Initialize_LCD();
Serial.println("Running basic drawing test...");
testBasicDrawing();
}
//==============================================================================
void loop()
{
// Simple color cycling test
static uint8_t colorTest = 0;
switch(colorTest)
{
case 0: fillScreen(0xF800); break; // Red
case 1: fillScreen(0x07E0); break; // Green
case 2: fillScreen(0x001F); break; // Blue
case 3: fillScreen(0xFFE0); break; // Yellow
case 4: fillScreen(0xF81F); break; // Magenta
case 5: fillScreen(0x07FF); break; // Cyan
case 6: fillScreen(0xFFFF); break; // White
case 7: fillScreen(0x0000); break; // Black
}
colorTest = (colorTest + 1) % 8;
delay(2000);
}