This sketch demo uses the NHD-FT81x-Shield paired with the NHD-ST1-BT817 Controller board. Display SPI initialization is done through the BT817 EVE IC.
//---------------------------------------------------------
/*
(c)2025 Newhaven Display International, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
//---------------------------------------------------------
#include <SPI.h>
#include <GD2.h>
// Include new BT817 registers
#define REG_GPIOX 3154076UL
#define REG_GPIOX_DIR 3154072UL
// Resolution for the display
int _hsize = 376;
int _vsize = 960;
int _screen = 0;
// Initialize Embedded Video Controller
void init_376X960() {
GD.wr16(REG_PWM_DUTY, 128);
GD.wr16(REG_PWM_HZ, 5000);
GD.wr16(REG_GPIOX_DIR, 0x800F);
GD.wr16(REG_GPIOX, 0x8000);
delay(20);
GD.wr16(REG_GPIOX, 0x0000);
delay(20);
GD.wr16(REG_GPIOX, 0x8000 | 0b1111);
delay(2000); // NECESSARRY 2s DELAY BEFORE TFT INITIALIZATION
_lcd_init();
delay(100);
// Horizontal timing (pixels)
GD.wr16(REG_HSIZE, _hsize); // Active pixels
GD.wr16(REG_HCYCLE, 536); // HYSNC(10) + HBP(90) + HSIZE(376) + HFP(60)
GD.wr16(REG_HSYNC0, 0); // HSYNC start
GD.wr16(REG_HSYNC1, 10); // HSYNC end (width = 10)
GD.wr16(REG_HOFFSET, 100); // HSYNC(10) + HBP(90)
// Vertical timing (lines)
GD.wr16(REG_VSIZE,_vsize); // Active lines
GD.wr16(REG_VCYCLE, 1050); // VYSNC(10) + VBP(60) + VSIZE(960) + VFP(60)
GD.wr16(REG_VSYNC0, 0); // VSYNC start
GD.wr16(REG_VSYNC1, 10); // VSYNC end (width = 10)
GD.wr16(REG_VOFFSET, 40); // VSYNC(10) + VBP(60)
// Pixel clock and signal polarity
GD.wr16(REG_PCLK, 1);
GD.wr16(REG_SWIZZLE, 0);
GD.wr16(REG_PCLK_POL, 0);
GD.wr16(REG_CSPREAD, 0);
GD.wr16(REG_DITHER, 1);
GD.wr16(REG_ROTATE, 0);
GD.swap();
}
// Initialization Command through BT817 GPIO SPI
void _lcd_com(unsigned char c) {
GD.wr16(REG_GPIOX, 0x8000 | 0b0011);
for (int i = 0; i < 8; i++) {
if ((c & 0x80) == 0x80) {
GD.wr16(REG_GPIOX, 0x8000 | 0b0011);
GD.wr16(REG_GPIOX, 0x8000 | 0b0010);
GD.wr16(REG_GPIOX, 0x8000 | 0b0011);
} else {
GD.wr16(REG_GPIOX, 0x8000 | 0b0001);
GD.wr16(REG_GPIOX, 0x8000 | 0b0000);
GD.wr16(REG_GPIOX, 0x8000 | 0b0001);
}
c = (c << 1); // Shift byte
}
GD.wr16(REG_GPIOX, 0x8000 | 0b0100);
}
// Initialization Data through BT817 GPIO SPI
void _lcd_dat(unsigned char d) {
GD.wr16(REG_GPIOX, 0x8000 | 0b1011);
for (int i = 0; i < 8; i++) {
if ((d & 0x80) == 0x80) {
GD.wr16(REG_GPIOX, 0x8000 | 0b1011);
GD.wr16(REG_GPIOX, 0x8000 | 0b1010);
GD.wr16(REG_GPIOX, 0x8000 | 0b1011);
} else {
GD.wr16(REG_GPIOX, 0x8000 | 0b1001);
GD.wr16(REG_GPIOX, 0x8000 | 0b1000);
GD.wr16(REG_GPIOX, 0x8000 | 0b1001);
}
d = (d << 1); // Shift byte
}
GD.wr16(REG_GPIOX, 0x8000 | 0b0100);
}
// Initializate LCD TFT
void _lcd_init() {
_lcd_com(0xFF);
_lcd_dat(0x77);
_lcd_dat(0x01);
_lcd_dat(0x00);
_lcd_dat(0x00);
_lcd_dat(0x13);
_lcd_com(0xEF);
_lcd_dat(0x08);
_lcd_com(0xFF);
_lcd_dat(0x77);
_lcd_dat(0x01);
_lcd_dat(0x00);
_lcd_dat(0x00);
_lcd_dat(0x10);
_lcd_com(0xC0);
_lcd_dat(0x77);
_lcd_dat(0x00);
_lcd_com(0xC1);
_lcd_dat(0x0C);
_lcd_dat(0x0C);
_lcd_com(0xC2);
_lcd_dat(0x07);
_lcd_dat(0x02);
_lcd_com(0xCC);
_lcd_dat(0x10);
_lcd_com(0xB0);
_lcd_dat(0x00);
_lcd_dat(0x0C);
_lcd_dat(0x19);
_lcd_dat(0x0B);
_lcd_dat(0x0F);
_lcd_dat(0x06);
_lcd_dat(0x05);
_lcd_dat(0x08);
_lcd_dat(0x08);
_lcd_dat(0x1F);
_lcd_dat(0x04);
_lcd_dat(0x11);
_lcd_dat(0x0F);
_lcd_dat(0x26);
_lcd_dat(0x2F);
_lcd_dat(0x1D);
_lcd_com(0xB1);
_lcd_dat(0x00);
_lcd_dat(0x17);
_lcd_dat(0x19);
_lcd_dat(0x0F);
_lcd_dat(0x12);
_lcd_dat(0x05);
_lcd_dat(0x05);
_lcd_dat(0x08);
_lcd_dat(0x07);
_lcd_dat(0x1F);
_lcd_dat(0x03);
_lcd_dat(0x10);
_lcd_dat(0x10);
_lcd_dat(0x27);
_lcd_dat(0x2F);
_lcd_dat(0x1D);
_lcd_com(0xFF);
_lcd_dat(0x77);
_lcd_dat(0x01);
_lcd_dat(0x00);
_lcd_dat(0x00);
_lcd_dat(0x11);
_lcd_com(0xB0);
_lcd_dat(0x25);
_lcd_com(0xB1);
_lcd_dat(0x76);
_lcd_com(0xB2);
_lcd_dat(0x81);
_lcd_com(0xB3);
_lcd_dat(0x80);
_lcd_com(0xB5);
_lcd_dat(0x4E);
_lcd_com(0xB7);
_lcd_dat(0x85);
_lcd_com(0xB8);
_lcd_dat(0x20);
_lcd_com(0xC1);
_lcd_dat(0x78);
_lcd_com(0xC2);
_lcd_dat(0x78);
_lcd_com(0xD0);
_lcd_dat(0x88);
_lcd_com(0xE0);
_lcd_dat(0x00);
_lcd_dat(0x00);
_lcd_dat(0x02);
_lcd_dat(0x00);
_lcd_dat(0x00);
_lcd_dat(0x0C);
_lcd_com(0xE1);
_lcd_dat(0x02);
_lcd_dat(0x8C);
_lcd_dat(0x04);
_lcd_dat(0x8C);
_lcd_dat(0x01);
_lcd_dat(0x8C);
_lcd_dat(0x03);
_lcd_dat(0x8C);
_lcd_dat(0x00);
_lcd_dat(0x44);
_lcd_dat(0x44);
_lcd_com(0xE2);
_lcd_dat(0x03);
_lcd_dat(0x03);
_lcd_dat(0x03);
_lcd_dat(0x03);
_lcd_dat(0x00);
_lcd_dat(0x00);
_lcd_dat(0xD4);
_lcd_dat(0x00);
_lcd_dat(0x00);
_lcd_dat(0x00);
_lcd_dat(0xD4);
_lcd_dat(0x00);
_lcd_com(0xE3);
_lcd_dat(0x00);
_lcd_dat(0x00);
_lcd_dat(0x33);
_lcd_dat(0x33);
_lcd_com(0xE4);
_lcd_dat(0x44);
_lcd_dat(0x44);
_lcd_com(0xE5);
_lcd_dat(0x09);
_lcd_dat(0xD2);
_lcd_dat(0x35);
_lcd_dat(0x8C);
_lcd_dat(0x0B);
_lcd_dat(0xD4);
_lcd_dat(0x35);
_lcd_dat(0x8C);
_lcd_dat(0x05);
_lcd_dat(0xCE);
_lcd_dat(0x35);
_lcd_dat(0x8C);
_lcd_dat(0x07);
_lcd_dat(0xD0);
_lcd_dat(0x35);
_lcd_dat(0x8C);
_lcd_com(0xE6);
_lcd_dat(0x00);
_lcd_dat(0x00);
_lcd_dat(0x33);
_lcd_dat(0x33);
_lcd_com(0xE7);
_lcd_dat(0x44);
_lcd_dat(0x44);
_lcd_com(0xE8);
_lcd_dat(0x08);
_lcd_dat(0xD1);
_lcd_dat(0x35);
_lcd_dat(0x8C);
_lcd_dat(0x0A);
_lcd_dat(0xD3);
_lcd_dat(0x35);
_lcd_dat(0x8C);
_lcd_dat(0x04);
_lcd_dat(0xCD);
_lcd_dat(0x35);
_lcd_dat(0x8C);
_lcd_dat(0x06);
_lcd_dat(0xCF);
_lcd_dat(0x35);
_lcd_dat(0x8C);
_lcd_com(0xEB);
_lcd_dat(0x00);
_lcd_dat(0x01);
_lcd_dat(0xE4);
_lcd_dat(0xE4);
_lcd_dat(0x44);
_lcd_dat(0x00);
_lcd_com(0xED);
_lcd_dat(0x77);
_lcd_dat(0x66);
_lcd_dat(0x55);
_lcd_dat(0x44);
_lcd_dat(0xCA);
_lcd_dat(0xF1);
_lcd_dat(0x03);
_lcd_dat(0xBF);
_lcd_dat(0xFB);
_lcd_dat(0x30);
_lcd_dat(0x1F);
_lcd_dat(0xAC);
_lcd_dat(0x44);
_lcd_dat(0x55);
_lcd_dat(0x66);
_lcd_dat(0x77);
_lcd_com(0xEF);
_lcd_dat(0x10);
_lcd_dat(0x0D);
_lcd_dat(0x04);
_lcd_dat(0x08);
_lcd_dat(0x3F);
_lcd_dat(0x1F);
_lcd_com(0xFF);
_lcd_dat(0x77);
_lcd_dat(0x01);
_lcd_dat(0x00);
_lcd_dat(0x00);
_lcd_dat(0x13);
_lcd_com(0xE8);
_lcd_dat(0x00);
_lcd_dat(0x0E);
_lcd_com(0x11);
delay(120);
_lcd_com(0xE8);
_lcd_dat(0x00);
_lcd_dat(0x0C);
delay(20);
_lcd_com(0xE8);
_lcd_dat(0x00);
_lcd_dat(0x00);
_lcd_com(0xFF);
_lcd_dat(0x77);
_lcd_dat(0x01);
_lcd_dat(0x00);
_lcd_dat(0x00);
_lcd_dat(0x00);
_lcd_com(0x29);
_lcd_com(0x35);
_lcd_dat(0x00); //TE ON
_lcd_com(0x36);
_lcd_dat(0x00); //FW:00 BW:10
_lcd_com(0x3A);
_lcd_dat(0x70);
}
void setup() {
GD.begin(0, 10, 5);
delay(100);
init_376X960();
GD.ClearColorRGB(0x808080);
GD.cmd_sketch(0, 0, 480, 480, 0, L8); // start sketching
GD.cmd_memset(0, 0, 480UL * 480UL); // clear the bitmap
GD.Clear();
GD.ColorRGB(255, 255, 255);
GD.PointSize(16 * 230);
GD.Begin(POINTS);
GD.Vertex2ii(240, 240);
GD.BitmapLayout(L8, 480, 480);
GD.BitmapSize(NEAREST, BORDER, BORDER, 480, 480);
GD.ColorRGB(255, 0, 0);
GD.Begin(BITMAPS);
GD.Vertex2ii(0, 0);
GD.finish();
GD.swap();
}
void loop() {
}