ESR-2025/i2c_lcd.c

133 lines
3.4 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "i2c_lcd.h"
#include <driverlib.h>
#include <msp430.h>
/* Adjust to your modules I²C address (often 0x27 or 0x3F) */
#define LCD_I2C_ADDR 0x27
/* PCF8574 pin ↔ LCD pin mapping (change if your backpack is different) */
#define P_RS 0x01 /* P0 → RS */
#define P_RW 0x02 /* P1 → RW */
#define P_EN 0x04 /* P2 → E */
#define P_BL 0x08 /* P3 → Backlight */
#define DATA_MASK 0xF0
/** spin until BUS not busy, or timeoutCycles hits zero */
static bool waitI2CBusyClear(uint32_t timeoutCycles)
{
/* keep looping while the BUSY bit remains set */
while ((EUSCI_B_I2C_isBusBusy(EUSCI_B0_BASE) == EUSCI_B_I2C_BUS_BUSY)
&& --timeoutCycles)
;
return (timeoutCycles != 0);
}
static void i2cWriteByte(uint8_t b)
{
/* make sure bus is free */
if (!waitI2CBusyClear(50000)) return;
/* generate START + send first byte */
EUSCI_B_I2C_masterSendMultiByteStart(EUSCI_B0_BASE, b);
/* wait until the byte is actually out and bus goes busy→idle */
if (!waitI2CBusyClear(50000)) return;
/* STOP to free the bus again */
EUSCI_B_I2C_masterSendMultiByteStop(EUSCI_B0_BASE);
/* optional small delay for the expander to settle */
__delay_cycles(50);
}
static void pulse(uint8_t data)
{
i2cWriteByte(data | P_EN);
__delay_cycles(200);
i2cWriteByte(data & ~P_EN);
__delay_cycles(200);
}
/* send upper or lower nibble with control bits */
static void write4(uint8_t nibble, uint8_t control)
{
uint8_t out = (nibble << 4) & DATA_MASK;
out |= control | P_BL;
i2cWriteByte(out);
pulse(out);
}
static void send(uint8_t value, uint8_t mode)
{
write4(value >> 4, mode);
write4(value & 0x0F, mode);
}
/** Commands (mode = 0), data (mode = P_RS) */
static inline void cmd(uint8_t c) { send(c, 0); }
static inline void data(uint8_t d){ send(d, P_RS); }
void lcdInit(void)
{
/* 1) Init the MSP I²C peripheral on B0 (P1.6=SCL, P1.7=SDA) */
GPIO_setAsPeripheralModuleFunctionInputPin(
GPIO_PORT_P1,
GPIO_PIN6 | GPIO_PIN7,
GPIO_PRIMARY_MODULE_FUNCTION
);
EUSCI_B_I2C_initMasterParam i2cCfg = {
.selectClockSource = EUSCI_B_I2C_CLOCKSOURCE_SMCLK,
.i2cClk = CS_getSMCLK(),
.dataRate = EUSCI_B_I2C_SET_DATA_RATE_100KBPS,
.byteCounterThreshold = 1,
.autoSTOPGeneration = EUSCI_B_I2C_NO_AUTO_STOP,
};
EUSCI_B_I2C_initMaster(EUSCI_B0_BASE, &i2cCfg);
EUSCI_B_I2C_setSlaveAddress(EUSCI_B0_BASE, LCD_I2C_ADDR);
EUSCI_B_I2C_enable(EUSCI_B0_BASE);
__delay_cycles(50000);
/* 4-bit init sequence */
write4(0x03, 0);
__delay_cycles(50000);
write4(0x03, 0);
__delay_cycles(50000);
write4(0x03, 0);
__delay_cycles(50000);
write4(0x02, 0);
__delay_cycles(50000);
/* function set: 2-line, 5×8 dots */
cmd(0x28);
/* display off */
cmd(0x08);
/* clear */
cmd(0x01);
__delay_cycles(20000);
/* entry mode: cursor moves right */
cmd(0x06);
/* display on, cursor off, blink off */
cmd(0x0C);
}
void lcdPrint(const char *str)
{
while (*str) {
data((uint8_t)*str++);
}
}
void lcdPutChar(char c)
{
data((uint8_t)c);
}
void lcdSetCursor(uint8_t row, uint8_t col)
{
/* DDRAM addresses: 0x00 + col for row0, 0x40 + col for row1 */
uint8_t addr = (row == 0 ? 0x00 : 0x40) + col;
cmd(0x80 | addr);
}