LCD Colour Palette System Reference Guide
This guide explains how the colour palette system works and how to use different colour schemes in your LCD applications.
Why Colour Palettes?
Instead of storing full 16-bit RGB colour values (which would use too much memory), the LCD driver uses a colour palette system:
Your Code Display Buffer LCD Screen
┌──────────────────┐ ┌──────────────┐ ┌──────────┐
│ Colour Index 0 │ ───> │ [0][0][0]... │ ──────> │ Black │
│ Colour Index 2 │ │ [2][2][2]... │ │ Red │
│ (etc.) │ │ │ │ (physical)
└──────────────────┘ └──────────────┘ └──────────┘
│
LCD_Set_Palette()
│
┌─────▼──────┐
│ Palette │
│ [0] = 0x000│ (Black)
│ [1] = 0xFFF│ (White)
│ [2] = 0xF00│ (Red)
│ ... │
└────────────┘
Key Principle: The buffer stores indices (0-15), not colours. The palette maps those indices to actual colours.
The Colour Index System
The display buffer stores values 0-15, each representing a colour from the palette.
// In your code:
LCD_Fill_Buffer(2); // Fill buffer with value 2
// What the palette does:
// If PALETTE_DEFAULT: 2 = Red
// If PALETTE_GREYSCALE: 2 = Dark grey
// If PALETTE_VINTAGE: 2 = Brownish tone
// The LCD displays the colour mapped by the current palette
Index Reference
| Index | Usage |
|---|---|
| 0 | Usually background/darkest |
| 1 | Usually brightest |
| 2-15 | Various colours |
| 255 (in sprites) | Transparent - don’t draw |
Available Palettes
1. PALETTE_DEFAULT - Standard Colours
The default palette provides standard, vibrant colours:
Index Colour Name Hex Code Visual
0 Black 0x000
1 White 0xFFF
2 Red 0xF00
3 Green 0x0F0
4 Blue 0x00F
5 Yellow 0xFF0
6 Cyan 0x0FF
7 Magenta 0xF0F
8 Dark Red 0x800
9 Dark Green 0x080
10 Dark Blue 0x008
11 Orange 0xF80
12 Purple 0x808
13 Teal 0x088
14 Brown 0x840
15 Grey 0x888
Best for: Games, educational apps, vibrant visual demonstrations
2. PALETTE_GREYSCALE - Black to White Gradient
A grayscale palette ranging from black to white:
Index Brightness Level Hex Code Visual
0 Black 0x000
1 Very Dark 0x111
2 Dark 0x222
3 Dark-Medium 0x333
4 Medium-Dark 0x444
5 Medium 0x555
6 Medium-Light 0x666
7 Light-Medium 0x777
8 Light 0x888
9 Light-Bright 0x999
10 Bright-Light 0xAAA
11 Bright 0xBBB
12 Very Bright 0xCCC
13 Brighter 0xDDD
14 Very Bright 0xEEE
15 White 0xFFF
Best for: Data visualization, charts, medical/industrial displays
Smooth gradient example:
LCD_Set_Palette(PALETTE_GREYSCALE);
// Draw a gradient from dark to light
for (int i = 0; i <= 15; i++) {
LCD_Draw_Rect(10 + i*15, 50, 14, 100, i, 1); // Gradual brightening
}
LCD_Refresh(&cfg0);
3. PALETTE_VINTAGE - Warm, Muted Tones
A palette with warm, retro colours inspired by vintage computing:
Index Colour Name Hex Code Appearance
0 Warm Black 0x111 Deep, rich black
1 Cream 0xFEA Warm off-white
2 Rust Red 0xB33 Muted red
3 Sage Green 0x8B5 Muted green
4 Slate Blue 0x558 Muted blue
5 Mustard Yellow 0xCC8 Warm yellow
6 Teal 0x8BB Teal tone
7 Mauve 0xB8B Purplish grey
8 Dark Rust 0x844 Dark red-brown
9 Forest Green 0x464 Dark green
10 Navy Blue 0x224 Dark blue
11 Gold 0xB84 Burnished gold
12 Purple 0x665 Muted purple
13 Cyan-Green 0x589 Teal-cyan
14 Terracotta 0x953 Earthy orange
15 Ash Grey 0x999 Neutral grey
Best for: Retro games, comfortable user interfaces, warm aesthetics
Vintage game example:
LCD_Set_Palette(PALETTE_VINTAGE);
LCD_Fill_Buffer(0); // Warm black background
// Old-school game title
LCD_printString("LUNAR LANDER", 20, 20, 1, 4); // Cream text
LCD_Draw_Rect(30, 80, 180, 100, 8, 0); // Rust red border
LCD_Refresh(&cfg0);
4. PALETTE_CUSTOM - User-Defined Colours
You can create your own custom palette by modifying the palette definition in the LCD driver (usually in LCD.h).
// Custom palette for a space theme
// (This would go in LCD.h or your configuration)
const uint16_t PALETTE_CUSTOM_DATA[16] = {
0x000, // 0: Black space
0x0FF, // 1: Cyan stars
0xF0F, // 2: Magenta nebula
0xFF0, // 3: Yellow Sun
0xFFF, // 4: White bright stars
0x088, // 5: Dark teal
0x800, // 6: Dark red
// ... etc for indices 7-15
};
Then use it:
LCD_Set_Palette(PALETTE_CUSTOM);
LCD_Refresh(&cfg0);
Switching Palettes at Runtime
You can change palettes during program execution. All colours immediately shift to the new palette:
// Start with default
LCD_Set_Palette(PALETTE_DEFAULT);
LCD_Fill_Buffer(2); // Red fill
LCD_Refresh(&cfg0);
HAL_Delay(2000);
// Switch to greyscale - same content, different colours!
LCD_Set_Palette(PALETTE_GREYSCALE);
LCD_Refresh(&cfg0); // Now it's dark grey (medium index)
HAL_Delay(2000);
Using Colour Indices Effectively
Semantic Colour Use
Instead of hardcoding numbers, use colour indices meaningfully:
// Less clear:
LCD_printString("Error", 10, 10, 2, 3); // What colour is 2?
// Better - define constants:
#define COLOUR_TEXT_NORMAL 1 // White
#define COLOUR_TEXT_ERROR 2 // Red (in default palette)
#define COLOUR_TEXT_SUCCESS 3 // Green
#define COLOUR_BACKGROUND 0 // Black
LCD_Fill_Buffer(COLOUR_BACKGROUND);
LCD_printString("Error", 10, 10, COLOUR_TEXT_ERROR, 3);
LCD_Refresh(&cfg0);
Palette-Aware Design
Design your code to work with any palette:
void draw_game_screen(void) {
LCD_Fill_Buffer(0); // Always index 0 (background)
LCD_printString("Score", 10, 10, 1, 3); // Index 1 (foreground)
// Draw player
LCD_Draw_Sprite_Colour(100, 100, 8, 8, PLAYER_SPRITE, 2); // Index 2 (primary)
// Draw enemies
LCD_Draw_Sprite_Colour(50, 50, 8, 8, ENEMY_SPRITE, 4); // Index 4 (secondary)
LCD_Refresh(&cfg0);
}
// Now this works with any palette!
LCD_Set_Palette(PALETTE_DEFAULT);
draw_game_screen(); // Displays in default colours
HAL_Delay(3000);
LCD_Set_Palette(PALETTE_VINTAGE);
draw_game_screen(); // Same screen, warm tones
HAL_Delay(3000);
Performance and Memory Notes
Switching palettes is very fast - it just remaps the colour values, doesn’t redraw pixels.
// Fast: just change palette
LCD_Set_Palette(PALETTE_GREYSCALE); // Instant (µs)
LCD_Refresh(&cfg0); // Still ~30-50ms for transfer
// Slow: redraw everything
LCD_Fill_Buffer(0);
// Draw lots of stuff
LCD_Refresh(&cfg0); // Much slower
This makes palettes excellent for:
- Theme switching
- Time-based effects
- Mode changes (pause menu, level complete, etc.)
- Accessibility features
RGB to 4-bit Index Conversion
If you want to add a custom palette,
Creating Custom Palette Colours
Step 1: Find Your RGB565 Colour
Use an online RGB565 converter you can find colours here or whole palettes [here] (https://lospec.com/palette-list) to get the hex value. For example:
- Bright green:
0x07E0 - Sky blue:
0x87FF - Orange:
0xFD20
Step 2: Add to LCD.h with Bytes Swapped
Open ST7789V2_Driver_STM32L4/Core/Inc/LCD.h and add your colour as a define with the bytes swapped:
// Add your custom colours at the top of LCD.h, near other colour definitions
#define MY_BRIGHT_GREEN 0xE007 // Original: 0x07E0, bytes swapped
#define MY_SKY_BLUE 0xFF87 // Original: 0x87FF, bytes swapped
#define MY_ORANGE 0x20FD // Original: 0xFD20, bytes swapped
Step 3: Use in Your Palette
Add these colour definitions to your custom palette array:
// In LCD.h, in the palette array section:
const uint16_t PALETTE_CUSTOM_DATA[16] = {
0x000, // 0: Black (background)
0xFFF, // 1: White (text)
MY_BRIGHT_GREEN, // 2: Your custom green
MY_SKY_BLUE, // 3: Your custom blue
MY_ORANGE, // 4: Your custom orange
// ... rest of palette
};
Step 4: Use the Index in Your Code
Now you can use the colour index in your drawing functions:
LCD_Fill_Buffer(0); // Black background
LCD_printString("Nature", 10, 10, 2, 3); // Green text (index 2)
LCD_Draw_Circle(100, 100, 30, 3, 1); // Blue circle (index 3)
LCD_Draw_Rect(50, 150, 80, 60, 4, 1); // Orange rectangle (index 4)
LCD_Refresh(&cfg0);
Quick Reference: Byte Swapping
To swap bytes in RGB565:
Original: 0xABCD
Swapped: 0xCDAB
In code: uint16_t swapped = ((original & 0xFF) << 8) | ((original >> 8) & 0xFF);