Complete From-Scratch Guide (Tested & Working – Nov 2025)
Goal: Boot directly to fullscreen digital clock + date on 3.5″ LCD No desktop, no icons, no X, no splash, no cursor For fresh Raspberry Pi OS Lite install Total time: ~20 mins
1. HARDWARE REQUIRED
| Item | Notes |
|---|---|
| Raspberry Pi Zero 2 W | |
| 3.5″ SPI TFT LCD (480×320) | Generic ILI9486 + XPT2046 (Waveshare, Elecrow, etc.) |
| MicroSD card (8GB+) | |
| 5V/2A Micro-USB power | |
| Internet (WiFi) | For initial setup |
2. FLASH OS (ON YOUR PC)
- Download: Raspberry Pi OS Lite (64-bit)
- Use Raspberry Pi Imager → Choose OS → Select Raspberry Pi OS Lite (64-bit)
- Click gear icon →
- Hostname: clockpi
- Enable SSH
- Username: admin
- Password: raspberry
- WiFi: Enter your SSID/password
- Locale: Set your timezone
- Flash to SD card → Eject
3. BOOT & INITIAL SETUP (HEADLESS VIA SSH)
bash
ssh admin@clockpi.local
# Password: raspberry
bash
# Change password
passwd
# Update system
sudo apt update && sudo apt upgrade -y
sudo reboot
4. INSTALL 3.5″ LCD DRIVER (ILI9486)
bash
cd ~
sudo rm -rf LCD-show
git clone https://github.com/goodtft/LCD-show.git
cd LCD-show
chmod +x LCD35-show
sudo ./LCD35-show
Reboots automatically After reboot: You should see green console text on 3.5″ LCD
5. VERIFY FRAMEBUFFER
bash
ls -l /dev/fb*
Expected output:
text
crw-rw---- 1 root video 29, 0 ... /dev/fb0
crw-rw---- 1 root video 29, 1 ... /dev/fb1
/dev/fb1 = your 3.5″ LCD
6. GIVE USER ACCESS TO /dev/fb1
bash
sudo usermod -a -G video admin
# Permanent udev rule
sudo tee /etc/udev/rules.d/99-fb1.rules > /dev/null << 'EOF'
KERNEL=="fb1", GROUP="video", MODE="0660"
EOF
sudo udevadm control --reload-rules
sudo udevadm trigger
Log out & back in (or reboot later)
7. INSTALL MINIMAL DEPENDENCIES
bash
sudo apt install -y python3-pip
pip3 install --user pygame==2.6.1
8. CREATE FINAL clock.py (PURE FRAMEBUFFER)
bash
cat > ~/clock.py << 'EOF'
#!/usr/bin/env python3
import os
import pygame
import datetime
import struct
os.environ['SDL_VIDEODRIVER'] = 'dummy'
os.environ['PYGAME_HIDE_SUPPORT_PROMPT'] = '1'
pygame.init()
screen = pygame.Surface((480, 320))
font_time = pygame.font.SysFont('freesansbold', 100)
font_date = pygame.font.SysFont('freesansbold', 45)
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
fb = open('/dev/fb1', 'wb')
def rgb_to_rgb565(r, g, b):
return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3)
clock = pygame.time.Clock()
while True:
now = datetime.datetime.now()
time_str = now.strftime("%H:%M:%S")
date_str = now.strftime("%Y-%m-%d %A")
screen.fill(WHITE)
t = font_time.render(time_str, True, BLACK)
d = font_date.render(date_str, True, BLACK)
screen.blit(t, t.get_rect(center=(240, 140)))
screen.blit(d, d.get_rect(center=(240, 220)))
pixels = pygame.image.tostring(screen, 'RGB')
buffer = bytearray(480 * 320 * 2)
idx = 0
for i in range(0, len(pixels), 3):
r, g, b = pixels[i:i+3]
color = rgb_to_rgb565(r, g, b)
buffer[idx:idx+2] = struct.pack('<H', color)
idx += 2
fb.seek(0)
fb.write(buffer)
fb.flush()
clock.tick(1)
EOF
bash
chmod +x ~/clock.py
9. TEST CLOCK (MUST WORK)
bash
python3 ~/clock.py
Clock appears on 3.5″ screen Press Ctrl+C to exit
10. CREATE SYSTEMD SERVICE (AUTO-START)
bash
sudo tee /etc/systemd/system/clock.service > /dev/null << 'EOF'
[Unit]
Description=Digital Clock on 3.5" LCD
After=local-fs.target
[Service]
Type=simple
User=admin
Group=video
Environment=SDL_VIDEODRIVER=dummy
ExecStart=/usr/bin/python3 /home/admin/clock.py
Restart=always
RestartSec=2
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
EOF
bash
sudo systemctl daemon-reload
sudo systemctl enable --now clock.service
11. DISABLE SPLASH & BOOT TEXT
bash
sudo raspi-config
# → 1 System Options → S1 Splash Screen → No
# → Finish
Or manually:
bash
sudo sed -i 's/ quiet splash//g' /boot/cmdline.txt
echo "disable_splash=1" | sudo tee -a /boot/config.txt
12. FINAL REBOOT
bash
sudo reboot
FINAL RESULT
| Stage | Display |
|---|---|
| Power on | Black screen |
| 3–5 sec | Large digital clock + date |
| NO desktop, NO icons, NO cursor, NO splash |
TROUBLESHOOTING
| Issue | Fix |
|---|---|
| Blank screen | Run sudo ./LCD35-show again |
| Only /dev/fb0 | Check /boot/config.txt has dtoverlay=ili9486 |
| Permission denied /dev/fb1 | Reboot after usermod -a -G video admin |
| Clock not starting | sudo journalctl -u clock.service -b |
OPTIONAL: 12/24 HOUR TOGGLE (Touch Top-Left Corner)
Replace clock.py with this version:
bash
cat > ~/clock.py << 'EOF'
#!/usr/bin/env python3
import os, pygame, datetime, struct, time
os.environ['SDL_VIDEODRIVER'] = 'dummy'
pygame.init()
screen = pygame.Surface((480, 320))
font_time = pygame.font.SysFont('freesansbold', 100)
font_date = pygame.font.SysFont('freesansbold', 45)
WHITE, BLACK = (255,255,255), (0,0,0)
fb = open('/dev/fb1', 'wb')
def rgb_to_rgb565(r,g,b): return ((r&0xF8)<<8)|((g&0xFC)<<3)|(b>>3)
# Load format from file
fmt_file = '/home/admin/time_format.txt'
if not os.path.exists(fmt_file):
with open(fmt_file, 'w') as f: f.write('24')
def get_format():
with open(fmt_file) as f: return f.read().strip()
clock = pygame.time.Clock()
last_touch = 0
while True:
# Touch detect (top-left 50x50)
try:
with open('/dev/input/touchscreen', 'rb') as t:
t.read()
if time.time() - last_touch > 2:
fmt = '12' if get_format() == '24' else '24'
with open(fmt_file, 'w') as f: f.write(fmt)
last_touch = time.time()
except: pass
fmt = get_format()
now = datetime.datetime.now()
time_str = now.strftime("%I:%M:%S %p" if fmt == '12' else "%H:%M:%S")
date_str = now.strftime("%Y-%m-%d %A")
screen.fill(WHITE)
t = font_time.render(time_str, True, BLACK)
d = font_date.render(date_str, True, BLACK)
screen.blit(t, t.get_rect(center=(240, 140)))
screen.blit(d, d.get_rect(center=(240, 220)))
pixels = pygame.image.tostring(screen, 'RGB')
buffer = bytearray(480*320*2)
idx = 0
for i in range(0, len(pixels), 3):
r,g,b = pixels[i:i+3]
buffer[idx:idx+2] = struct.pack('<H', rgb_to_rgb565(r,g,b))
idx += 2
fb.seek(0); fb.write(buffer); fb.flush()
clock.tick(1)
EOF
Touch top-left corner → toggles 12/24h











Leave a Reply