Last active
March 14, 2024 01:29
-
-
Save pgaskin/0ca4e5ef1baa00485cfaf06b69e56b2d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "pico/stdlib.h" | |
#include "hardware/i2c.h" | |
#include "fnk0079.h" | |
int main() { | |
i2c_init(i2c0, 100 * 1000); | |
gpio_set_function(4, GPIO_FUNC_I2C); | |
gpio_set_function(5, GPIO_FUNC_I2C); | |
gpio_pull_up(4); | |
gpio_pull_up(5); | |
fnk0079 lcd; | |
if (fnk0079_probe(i2c0, 0x27)) { | |
// display not connected or error | |
} | |
fnk0079_init(&lcd, i2c0, 0x27, 20, 4); | |
fnk0079_backlight(&lcd, true); | |
fnk0079_display_control(&lcd, true, false, false); | |
fnk0079_writes(&lcd, "test"); | |
fnk0079_write(&lcd, '1'); | |
fnk0079_write(&lcd, '2'); | |
fnk0079_write(&lcd, '3'); | |
busy_wait_ms(2000); | |
fnk0079_backlight(&lcd, false); | |
busy_wait_ms(2000); | |
fnk0079_backlight(&lcd, true); | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Minimal RPi Pico driver for the FNK0079 I2C LCD display board. Might also | |
* work with other HD44780 boards. | |
* | |
* Loosely based on https://github.com/Freenove/Freenove_LCD_Module. | |
*/ | |
#include <stdbool.h> | |
#include <stdint.h> | |
#include "hardware/i2c.h" | |
#include "fnk0079.h" | |
int fnk0079_probe(i2c_inst_t *i2c, uint8_t addr) { | |
uint8_t buf; | |
int tries = 8; | |
while (i2c_read_blocking(i2c, addr, &buf, 1, false) < 1) { | |
if (!--tries) { | |
return -1; // not connected or error | |
} | |
busy_wait_ms(250); | |
} | |
return 0; | |
} | |
int fnk0079_init(fnk0079 *lcd, i2c_inst_t *i2c, uint8_t addr, uint8_t cols, uint8_t rows) { | |
// addr 0x27 is 20x4 black board, blank chip | |
// similar to the HD44780 | |
int rc; | |
// clamp dimensions | |
if (cols > 20) cols = 20; | |
if (rows > 4) rows = 4; | |
// init the struct | |
*lcd = (struct fnk0079) { | |
.i2c = i2c, | |
.addr = addr, | |
.cols = cols, | |
.rows = rows, | |
.backlight = false, | |
}; | |
// hardware requires at least 40ms before accepting commands | |
busy_wait_ms(40); | |
// reset expander | |
fnk0079_cmd(lcd, 0); | |
busy_wait_ms(1000); | |
// ensure it's in 4-bit mode | |
if ((rc = fnk0079_clear(lcd))) goto err; | |
if ((rc = fnk0079_clear(lcd))) goto err; | |
if ((rc = fnk0079_clear(lcd))) goto err; | |
if ((rc = fnk0079_function(lcd, false, false, false))) goto err; | |
// explicitly reset to defaults | |
if ((rc = fnk0079_function(lcd, false, false, false))) goto err; | |
if ((rc = fnk0079_display_control(lcd, false, false, false))) goto err; | |
if ((rc = fnk0079_clear(lcd))) goto err; | |
if ((rc = fnk0079_entry_mode(lcd, true, false))) goto err; | |
if ((rc = fnk0079_home(lcd))) goto err; | |
// done | |
return 0; | |
err: | |
lcd->i2c = NULL; | |
return rc; | |
} | |
int fnk0079_writes(fnk0079 *lcd, const char *s) { | |
int rc; | |
if (s) while (*s) if ((rc = fnk0079_write(lcd, *s++))) return rc; | |
return 0; | |
} | |
int fnk0079_clear(fnk0079 *lcd) { | |
int rc = fnk0079_cmd(lcd, 0x01); // CLEARDISPLAY | |
if (!rc) busy_wait_ms(2); | |
return rc; | |
} | |
int fnk0079_home(fnk0079 *lcd) { | |
int rc = fnk0079_cmd(lcd, 0x02); // RETURNHOME | |
if (!rc) busy_wait_ms(2); | |
return rc; | |
} | |
int fnk0079_entry_mode(fnk0079 *lcd, bool leftToRight, bool shiftIncrement) { | |
return fnk0079_cmd(lcd, 0x04 // ENTRYMODESET | |
| (shiftIncrement ? 0x01 : 0x00) // inc : dec | |
| (leftToRight ? 0x02 : 0x00) // ltr : rtl | |
); | |
} | |
int fnk0079_display_control(fnk0079 *lcd, bool on, bool cursor, bool blink) { | |
return fnk0079_cmd(lcd, 0x08 // DISPLAYCONTROL | |
| (blink ? 0x01 : 0x00) // on : off | |
| (cursor ? 0x02 : 0x00) // on : off | |
| (on ? 0x04 : 0x00) // on : off | |
); | |
} | |
int fnk0079_move(fnk0079 *lcd, bool scroll, bool left, bool allLines) { | |
return fnk0079_cmd(lcd, 0x10 // CURSORSHIFT | |
| (left ? 0x02 : 0x00) // left : right | |
| (allLines ? 0x04 : 0x00) // all : current | |
| (scroll ? 0x08 : 0x00) // scroll : move | |
); | |
} | |
int fnk0079_function(fnk0079 *lcd, bool eightBit, bool twoLine, bool fiveTenDots) { | |
return fnk0079_cmd(lcd, 0x20 // FUNCTIONSET | |
| (fiveTenDots ? 0x04 : 0x00) // 5x10dots : 5x8dots | |
| (twoLine ? 0x08 : 0x00) // 2line : 1line | |
| (eightBit ? 0x10 : 0x00) // 8bit : 4bit | |
); | |
} | |
int fnk0079_character(fnk0079 *lcd, uint8_t idx, const uint8_t *ch) { | |
int rc; | |
if ((rc = | |
fnk0079_cmd(lcd, 0x40 // SETCGRAMADDR | |
| ((idx&0x7) << 3) // location 0-7 | |
) | |
)) { | |
return rc; | |
} | |
for (int i = 0; i < 8; i++) { | |
if ((rc = fnk0079_write(lcd, ch[i]))) { | |
return rc; | |
} | |
} | |
return 0; | |
} | |
int fnk0079_position(fnk0079 *lcd, uint8_t col, uint8_t row) { | |
if (!lcd->i2c) return -1; | |
if (row >= lcd->rows) | |
row = lcd->rows; | |
return fnk0079_cmd(lcd, 0x80 // SETDDRAMADDR | |
| (col + (uint8_t[]){0, 64, 20, 84}[row-1]) | |
); | |
} | |
int fnk0079_backlight(fnk0079 *lcd, bool on) { | |
lcd->backlight = on; | |
return fnk0079_cmd(lcd, 0); | |
} | |
int fnk0079_cmd(fnk0079 *lcd, uint8_t cmd) { | |
return fnk0079_send(lcd, cmd, false); | |
} | |
int fnk0079_write(fnk0079 *lcd, uint8_t ch) { | |
return fnk0079_send(lcd, ch, true); | |
} | |
int fnk0079_send(fnk0079 *lcd, uint8_t value, bool data) { | |
if (!lcd->i2c) return -1; | |
int rc; | |
uint8_t buf[4] = { | |
(uint8_t)((0xF0 & (value<<0)) | (lcd->backlight ? 0x08 : 0x00) | 0x04 | (data ? 0x01 : 0x00)), | |
(uint8_t)((0xF0 & (value<<0)) | (lcd->backlight ? 0x08 : 0x00) | 0x00 | (data ? 0x01 : 0x00)), | |
(uint8_t)((0xF0 & (value<<4)) | (lcd->backlight ? 0x08 : 0x00) | 0x04 | (data ? 0x01 : 0x00)), | |
(uint8_t)((0xF0 & (value<<4)) | (lcd->backlight ? 0x08 : 0x00) | 0x00 | (data ? 0x01 : 0x00)), | |
}; | |
if ((rc = i2c_write_timeout_us(lcd->i2c, lcd->addr, buf, sizeof(buf), false, 5000)) != sizeof(buf)) return rc; | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#ifdef __cplusplus | |
extern "C" { | |
#include <stdbool.h> | |
#include <stdint.h> | |
#endif | |
typedef struct i2c_inst i2c_inst_t; | |
typedef struct fnk0079 { | |
i2c_inst_t *i2c; | |
uint8_t addr; | |
uint8_t cols; | |
uint8_t rows; | |
bool backlight; | |
} fnk0079; | |
int fnk0079_probe(i2c_inst_t *i2c, uint8_t addr); | |
int fnk0079_init(fnk0079 *lcd, i2c_inst_t *i2c, uint8_t addr, uint8_t cols, uint8_t rows); | |
int fnk0079_writes(fnk0079 *lcd, const char *s); | |
int fnk0079_clear(fnk0079 *lcd); | |
int fnk0079_home(fnk0079 *lcd); | |
int fnk0079_entry_mode(fnk0079 *lcd, bool leftToRight, bool shiftIncrement); | |
int fnk0079_display_control(fnk0079 *lcd, bool on, bool cursor, bool blink); | |
int fnk0079_move(fnk0079 *lcd, bool scroll, bool left, bool allLines); | |
int fnk0079_function(fnk0079 *lcd, bool eightBit, bool twoLine, bool fiveTenDots); | |
int fnk0079_character(fnk0079 *lcd, uint8_t idx, const uint8_t *ch); | |
int fnk0079_position(fnk0079 *lcd, uint8_t col, uint8_t row); | |
int fnk0079_backlight(fnk0079 *lcd, bool on); | |
int fnk0079_cmd(fnk0079 *lcd, uint8_t cmd); | |
int fnk0079_write(fnk0079 *lcd, uint8_t ch); | |
int fnk0079_send(fnk0079 *lcd, uint8_t value, bool data); | |
#ifdef __cplusplus | |
} | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment