gbmanager/src/lcd.cpp

103 lines
3.0 KiB
C++

#include "pico/binary_info.h"
#include "lcd.h"
// commands
constexpr int LCD_CLEARDISPLAY = 0x01;
constexpr int LCD_RETURNHOME = 0x02;
constexpr int LCD_ENTRYMODESET = 0x04;
constexpr int LCD_DISPLAYCONTROL = 0x08;
constexpr int LCD_CURSORSHIFT = 0x10;
constexpr int LCD_FUNCTIONSET = 0x20;
constexpr int LCD_SETCGRAMADDR = 0x40;
constexpr int LCD_SETDDRAMADDR = 0x80;
// flags for display entry mode
constexpr int LCD_ENTRYSHIFTINCREMENT = 0x01;
constexpr int LCD_ENTRYLEFT = 0x02;
// flags for display and cursor control
constexpr int LCD_BLINKON = 0x01;
constexpr int LCD_CURSORON = 0x02;
constexpr int LCD_DISPLAYON = 0x04;
// flags for function set
constexpr int LCD_5x10DOTS = 0x04;
constexpr int LCD_2LINE = 0x08;
constexpr int LCD_8BITMODE = 0x10;
constexpr int LCD_BACKLIGHT = 0x08;
constexpr int LCD_ENABLE_BIT = 0x04;
LCD::LCD(i2c_inst_t *i2c, const uint gpio_sda, const uint gpio_scl,
const uint8_t i2c_addr, uint8_t num_cols, uint8_t num_lines)
: i2c{i2c}, i2c_addr{i2c_addr}, num_cols{num_cols}, num_lines{num_lines} {
i2c_init(i2c, 400 * 1000);
gpio_set_function(gpio_sda, GPIO_FUNC_I2C);
gpio_set_function(gpio_scl, GPIO_FUNC_I2C);
gpio_pull_up(gpio_sda);
gpio_pull_up(gpio_scl);
// Make the I2C pins available to picotool
bi_decl(bi_2pins_with_func(gpio_sda, gpio_scl, GPIO_FUNC_I2C));
sendByte(0x03, Mode::COMMAND);
sendByte(0x03, Mode::COMMAND);
sendByte(0x03, Mode::COMMAND);
sendByte(0x02, Mode::COMMAND);
sendByte(LCD_ENTRYMODESET | LCD_ENTRYLEFT, Mode::COMMAND);
sendByte(LCD_FUNCTIONSET | LCD_2LINE, Mode::COMMAND);
sendByte(LCD_DISPLAYCONTROL | LCD_DISPLAYON, Mode::COMMAND);
clear();
}
// Go to location on LCD
void LCD::setCursor(int line, int position) {
int val = (line == 0) ? 0x80 + position : 0xC0 + position;
sendByte(val, Mode::COMMAND);
cursor_x = line;
cursor_y = position;
}
void LCD::sendChar(char val) { sendByte(val, Mode::CHARACTER); }
void LCD::sendString(const std::string &str) {
for (const char &c : str) {
if (c == '\n') {
cursor_y++;
setCursor(cursor_y, 0);
} else {
sendChar(c);
cursor_x++;
}
}
}
void LCD::clear() { sendByte(LCD_CLEARDISPLAY, Mode::COMMAND); }
void LCD::i2cWriteByte(uint8_t val) {
i2c_write_blocking(i2c, i2c_addr, &val, 1, false);
}
void LCD::toggleEnable(uint8_t val) {
// Toggle enable pin on LCD display
// We cannot do this too quickly or things don't work
constexpr uint64_t DELAY_US = 600;
sleep_us(DELAY_US);
i2cWriteByte(val | LCD_ENABLE_BIT);
sleep_us(DELAY_US);
i2cWriteByte(val & ~LCD_ENABLE_BIT);
sleep_us(DELAY_US);
}
// The display is sent a byte as two separate nibble transfers
void LCD::sendByte(uint8_t val, Mode mode) {
uint8_t high = static_cast<int>(mode) | (val & 0xF0) | LCD_BACKLIGHT;
uint8_t low = static_cast<int>(mode) | ((val << 4) & 0xF0) | LCD_BACKLIGHT;
i2cWriteByte(high);
toggleEnable(high);
i2cWriteByte(low);
toggleEnable(low);
}