Task 10.1: 4-bit Mode LCD Interfacing
Optimize LCD interfacing by using 4-bit mode instead of 8-bit mode. This uses only 4 data lines instead of 8, saving GPIO pins.
Learning Objectives
By the end of this task, you will:
- 🎯 Understand 4-bit vs 8-bit LCD modes
- 🎯 Reduce GPIO usage significantly (8 pins → 4 pins)
- 🎯 Implement nibble-based data transmission
- 🎯 Master LCD initialization sequence for 4-bit mode
- 🎯 Build resource-efficient display driver
Prerequisites
- ✅ Complete Lab 10 (8-bit LCD basics)
- ✅ Understand LCD command protocol
- ✅ Familiar with GPIO output control
Hardware Required
| Component | Details |
|---|---|
| Microcontroller | STM32F407VG |
| Display | 16x2 LCD (HD44780 compatible) |
| Pins | D4-D7 (4 data lines), RS, EN, RW (optional) |
| Power | 5V for LCD |
Theory: 4-bit Mode
4-bit vs 8-bit
8-bit mode:
├─ Uses 8 data lines (D0-D7)
├─ High GPIO pin usage
└─ Faster data transmission
4-bit mode:
├─ Uses 4 data lines (D4-D7)
├─ Lower GPIO requirement (same board versatility)
├─ Data sent in two 4-bit "nibbles"
└─ Slower but plenty fast for LCD
Nibble Transmission
To send byte 0xAB (10101011):
4-bit mode:
Step 1: Send high nibble (1010) on D4-D7
└─ RS=0 (command), EN pulse
Step 2: Send low nibble (1011) on D4-D7
└─ RS=0 (command), EN pulse
8-bit mode (for comparison):
Step 1: Send entire 0xAB at once on D0-D7
└─ Much faster but uses more pins
Initialization Sequence
The 4-bit initialization is special:
LCD powers up in 8-bit mode by default
To switch to 4-bit mode:
1. Send 0x30 three times (8-bit command)
2. Send 0x20 (switches to 4-bit mode)
3. Send 0x28 (function set: 4-bit, 2 lines, 5x8 font)
4. Send 0x0C (display ON, cursor OFF)
5. Send 0x01 (clear display)
6. Send 0x06 (entry mode: increment, no shift)
Complete Code
#define RCC_AHB1ENR *(volatile unsigned int*)(0x40023800 + 0x30)
#define GPIOD_MODER *(volatile unsigned int*)(0x40020C00 + 0x00)
#define GPIOD_ODR *(volatile unsigned int*)(0x40020C00 + 0x14)
// Pin definitions
#define RS (1<<0) // PD0
#define EN (1<<1) // PD1
// D4-D7 on PD4-PD7
void delay_ms(int ms) {
for (volatile int i = 0; i < ms * 10000; i++);
}
void lcd_pulse_enable(void) {
GPIOD_ODR |= EN;
delay_ms(1);
GPIOD_ODR &= ~EN;
delay_ms(1);
}
void send_nibble(unsigned char nibble) {
// Clear D4-D7
GPIOD_ODR &= ~(0xF << 4);
// Set high nibble bits
GPIOD_ODR |= ((nibble & 0xF) << 4);
lcd_pulse_enable();
}
void send_byte_4bit(unsigned char byte, int is_data) {
if (is_data)
GPIOD_ODR |= RS; // RS=1 for data
else
GPIOD_ODR &= ~RS; // RS=0 for command
delay_ms(1);
// Send high nibble
send_nibble((byte >> 4) & 0xF);
delay_ms(1);
// Send low nibble
send_nibble(byte & 0xF);
delay_ms(1);
}
void lcd_init_4bit(void) {
RCC_AHB1ENR |= (1 << 3); // Enable GPIOD
// Configure PD0-PD7 as outputs
GPIOD_MODER &= ~(0xFF << 0);
GPIOD_MODER |= (0x55 << 0);
delay_ms(20);
// Initialization sequence for 4-bit mode
// Must send three 0x3 commands (each time high nibble)
send_nibble(0x3);
delay_ms(5);
send_nibble(0x3);
delay_ms(5);
send_nibble(0x3);
delay_ms(1);
send_nibble(0x2); // Switch to 4-bit mode
delay_ms(1);
// Now use normal send_byte functions
send_byte_4bit(0x28, 0); // Function set: 4-bit, 2 lines, 5x8 dot
send_byte_4bit(0x0C, 0); // Display ON, cursor OFF
send_byte_4bit(0x01, 0); // Clear display
send_byte_4bit(0x06, 0); // Entry mode: increment cursor
}
void lcd_write_char(char c) {
send_byte_4bit(c, 1); // is_data = 1 (character)
}
void lcd_write_string(char *str) {
while (*str) {
lcd_write_char(*str++);
}
}
int main(void) {
lcd_init_4bit();
lcd_write_string("Hello 4-bit!");
while (1) {
// Application code
}
return 0;
}
Expected Output
LCD Display:
┌─────────────────┐
│ Hello 4-bit! │
│ │
└─────────────────┘
GPIO Savings
8-bit mode:
D0-D7: 8 pins
RS: 1 pin
EN: 1 pin
────────────────
Total: 10+ pins
4-bit mode:
D4-D7: 4 pins
RS: 1 pin
EN: 1 pin
────────────────
Total: 6 pins (40% savings)
Common Mistakes
| Issue | Solution |
|---|---|
| LCD doesn't initialize | Verify three 0x3 commands sent |
| Display garbled | Check nibble order - high then low |
| No text displayed | Verify character versus command mode (RS) |
| Slow communication | May be intentional - 4-bit is inherently slower |
Key Takeaways
✨ Important:
- 4-bit mode uses half the GPIO pins
- Nibble transmission sends data twice (high, then low)
- Initialization sequence is special and must be exact
- RS pin distinguishes commands from data
- Performance is still adequate for LCD speeds
Challenge Exercises
Challenge 1: Multi-line Display
Display different text on line 1 and line 2 using cursor addressing.
Challenge 2: Display Sensor Data
Show temperature or ADC readings updated on display.
Challenge 3: Custom Characters
Create and display custom character patterns on LCD.
Next Steps
✨ Congratulations on completing the STM32 embedded systems course! You've mastered GPIO, timers, interrupts, and interfacing!