diff --git a/gbmanager.cpp b/gbmanager.cpp index ab2fa55..ba705cc 100644 --- a/gbmanager.cpp +++ b/gbmanager.cpp @@ -13,12 +13,9 @@ int main() { // Enable UART so we can print status output stdio_init_all(); - uint8_t data = 0; - int ret{0}; - auto myLCD = LCD(i2c1, I2C_SDA_PIN, I2C_SCL_PIN, I2C_ADDR); - myLCD.backlight_on(); - - std::cout << "FINISHED!" << std::endl; + myLCD.sendString("Hallo, Welt"); + myLCD.clear(); + myLCD.sendString("le"); } \ No newline at end of file diff --git a/lcd.cpp b/lcd.cpp index 54c0577..bbc7380 100644 --- a/lcd.cpp +++ b/lcd.cpp @@ -1,18 +1,104 @@ #include "lcd.h" -constexpr uint8_t SHIFT_BACKLIGHT = 3; +// 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_addr{i2c_addr}, num_cols{num_cols}, num_lines{num_lines} { + : i2c{i2c}, i2c_addr{i2c_addr}, num_cols{num_cols}, num_lines{num_lines} +{ i2c_init(i2c1, 100 * 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); + + 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(); } -int LCD::backlight_off() { +// go to location on LCD +void LCD::setCursor(int line, int position) { + int val = (line == 0) ? 0x80 + position : 0xC0 + position; + sendByte(val, Mode::COMMAND); +} + +void LCD::sendChar(char val) { + sendByte(val, Mode::CHARACTER); +} + +void LCD::sendString(const std::string &str) { + for (const char &c : str) { + sendChar(c); + } +} + +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(mode) | (val & 0xF0) | LCD_BACKLIGHT; + uint8_t low = static_cast(mode) | ((val << 4) & 0xF0) | LCD_BACKLIGHT; + + i2cWriteByte(high); + toggleEnable(high); + i2cWriteByte(low); + toggleEnable(low); +} + +int LCD::backlight_off() +{ uint8_t data = 0; int ret{0}; @@ -21,11 +107,12 @@ int LCD::backlight_off() { return ret; } -int LCD::backlight_on() { - uint8_t data = 1 << SHIFT_BACKLIGHT; +int LCD::backlight_on() +{ int ret{0}; + /*uint8_t data = 1 << SHIFT_BACKLIGHT; - ret = i2c_write_blocking(i2c1, i2c_addr, &data, 1, false); + ret = i2c_write_blocking(i2c1, i2c_addr, &data, 1, false);*/ return ret; } \ No newline at end of file diff --git a/lcd.h b/lcd.h index 72d173b..87fe3d9 100644 --- a/lcd.h +++ b/lcd.h @@ -1,17 +1,34 @@ #ifndef LCD_H #define LCD_H +#include + #include "hardware/i2c.h" #include "pico/stdlib.h" -class LCD { +enum class Mode +{ + COMMAND, + CHARACTER +}; + +class LCD +{ public: LCD(i2c_inst_t *i2c, const uint gpio_sda, const uint gpio_scl, const uint8_t i2c_addr, uint8_t num_cols = 16, uint8_t num_lines = 2); int backlight_off(); int backlight_on(); + void sendString(const std::string &str); + void setCursor(int line, int position); + void clear(); private: + void sendByte(uint8_t val, Mode mode); + void toggleEnable(uint8_t val); + void i2cWriteByte(uint8_t val); + void sendChar(char val); + i2c_inst_t *i2c; uint8_t i2c_addr; uint8_t num_cols; uint8_t num_lines;