#include <stdint.h>
// Base address for I2C hardware registers (ESP32-specific)
#define I2C_BASE_ADDR 0x3FF53000
// Register offsets
#define I2C_FIFO_REG (I2C_BASE_ADDR + 0x100)
#define I2C_SCL_LOW_PERIOD (I2C_BASE_ADDR + 0x0)
#define I2C_SCL_HIGH_PERIOD (I2C_BASE_ADDR + 0x38)
#define I2C_CMD_REG(n) (I2C_BASE_ADDR + 0x58 + ((n) * 4))
#define I2C_CTRL_REG (I2C_BASE_ADDR + 0x04)
#define I2C_FIFO_CONF_REG (I2C_BASE_ADDR + 0x18)
#define I2C_INT_CLR_REG (I2C_BASE_ADDR + 0x24)
#define I2C_INT_RAW_REG (I2C_BASE_ADDR + 0x20)
#define I2C_STATUS_REG (I2C_BASE_ADDR + 0x2C)
#define I2C_ADDR 0x27 // LCD I2C address (adjust as per your LCD module)
#define WRITE_BIT 0x0
#define BIT(x) (1 << (x))
#define LCD_BACKLIGHT 0x08 // Backlight control bit
#define LCD_ENABLE_BIT 0x04 // Enable pin control bit
#define LCD_COLUMNS 20 // Number of columns on the LCD
#define LCD_LINES 4 // Number of lines on the LCD
// Functions to access registers
#define REG_WRITE(addr, val) (*((volatile unsigned int *)(addr)) = (val))
#define REG_READ(addr) (*((volatile unsigned int *)(addr)))
// Delay function
static void delay(int count) {
while (count--) {
asm volatile ("nop");
}
}
// I2C Master Initialization
void i2c_init() {
REG_WRITE(I2C_SCL_LOW_PERIOD, 40); // Configure SCL low period
REG_WRITE(I2C_SCL_HIGH_PERIOD, 40); // Configure SCL high period
REG_WRITE(I2C_FIFO_CONF_REG, BIT(10)); // Configure FIFO
REG_WRITE(I2C_INT_CLR_REG, 0xFFFFFFFF); // Clear interrupts
REG_WRITE(I2C_CTRL_REG, BIT(4)); // Enable I2C master mode
}
// I2C Master Write Byte
void i2c_master_write_byte(uint8_t *data, uint8_t length) {
// Clear any pending interrupts
REG_WRITE(I2C_INT_CLR_REG, 0xFFFFFFFF);
// Write address with write bit to FIFO
REG_WRITE(I2C_FIFO_REG, (I2C_ADDR << 1) | WRITE_BIT);
// Write data to FIFO
for (uint8_t i = 0; i < length; i++) {
REG_WRITE(I2C_FIFO_REG, data[i]);
}
// Configure I2C commands
REG_WRITE(I2C_CMD_REG(0), (0x0 << 11)); // Start
REG_WRITE(I2C_CMD_REG(1), (0x1 << 11) | (length & 0xFF)); // Write data
REG_WRITE(I2C_CMD_REG(2), (0x3 << 11)); // Stop
// Start the I2C transaction
REG_WRITE(I2C_CTRL_REG, BIT(5));
// Wait for the transaction to complete
while (REG_READ(I2C_STATUS_REG) & BIT(9)) {
delay(1000); // Simple delay loop
}
}
// LCD Functions
void lcd_expanderWrite(uint8_t data) {
uint8_t payload[1] = {data | LCD_BACKLIGHT};
i2c_master_write_byte(payload, 1);
}
void lcd_pulseEnable(uint8_t data) {
lcd_expanderWrite(data | LCD_ENABLE_BIT); // Set enable bit
delay(1);
lcd_expanderWrite(data & ~LCD_ENABLE_BIT); // Clear enable bit
delay(5);
}
void lcd_write4Bits(uint8_t value) {
lcd_expanderWrite(value);
lcd_pulseEnable(value);
}
void lcd_send(uint8_t value, uint8_t mode) {
uint8_t highNibble = value & 0xF0;
uint8_t lowNibble = (value << 4) & 0xF0;
lcd_write4Bits(highNibble | mode);
lcd_write4Bits(lowNibble | mode);
}
void lcd_send_command(uint8_t command) {
lcd_send(command, 0);
}
void lcd_send_data(uint8_t data) {
lcd_send(data, 0x01);
}
void lcd_backlight() {
lcd_expanderWrite(LCD_BACKLIGHT); // Turn on backlight
}
// Initialize the LCD
void lcd_init() {
i2c_init();
delay(50); // Wait for LCD to power up
lcd_send_command(0x33); // Initialize sequence
lcd_send_command(0x32); // Set to 4-bit mode
lcd_send_command(0x28); // 2-line, 5x7 matrix
lcd_send_command(0x0C); // Display on, cursor off
lcd_send_command(0x06); // Increment cursor
lcd_send_command(0x01); // Clear display
delay(2); // Wait for clear display command to complete
}
// Print a string on the LCD
void lcd_print(const char *str) {
while (*str) {
lcd_send_data(*str++);
}
}
// Set cursor position
void lcd_set_cursor(uint8_t col, uint8_t row) {
uint8_t row_offsets[] = {0x00, 0x40, 0x14, 0x54};
if (row >= LCD_LINES) row = LCD_LINES - 1; // Limit to 4 rows
lcd_send_command(0x80 | (col + row_offsets[row]));
}
// Main Function
void setup() {
lcd_init();
lcd_backlight();
// Display messages
lcd_set_cursor(3, 0);
lcd_print("Hello, world!");
lcd_set_cursor(2, 1);
lcd_print("Wokwi IoT Sim");
lcd_set_cursor(5, 2);
lcd_print("Simulator");
lcd_set_cursor(7, 3);
lcd_print("Enjoy!");
}
void loop() {
// Infinite loop
}