Skip to content

Commit

Permalink
drivers: auxdisplay: hd44780: implement busy-flag polling mechanism
Browse files Browse the repository at this point in the history
HD44780 controller can indicate via busy flag whether it's finished
processing current command. This allows for faster communication between
MCU and the HD44780, as the MCU doesn't have to wait for fixed extra
period of time in case the current command is processed earlier.
Implement this functionality.

Signed-off-by: Jan Kuliga <jtkuliga@gmail.com>
  • Loading branch information
kuliga committed Sep 17, 2024
1 parent 64fe19a commit 4801d2b
Showing 1 changed file with 77 additions and 15 deletions.
92 changes: 77 additions & 15 deletions drivers/auxdisplay/auxdisplay_hd44780.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,17 +88,75 @@ static void hd44780_pulse_enable_line(const struct device *dev)
k_sleep(K_NSEC(config->enable_line_fall_delay));
}

static void auxdisplay_hd44780_command(const struct device *dev, bool rs, uint8_t cmd,
uint8_t mode)
static inline void hd44780_set_rs_rw_lines(const struct device *dev, bool rs, bool rw)
{
const struct auxdisplay_hd44780_config *const config = dev->config;

gpio_pin_set_dt(&config->rs_gpio, rs);
if (config->rw_gpio.port) {
gpio_pin_set_dt(&config->rw_gpio, rw);
}

k_sleep(K_NSEC(config->rs_line_delay));
}

static int hd44780_db_gpios_configure(const struct device *dev, uint8_t lsb_line,
gpio_flags_t flags)
{
const struct auxdisplay_hd44780_config *config = dev->config;
int rc;

for (int line = 7; line >= lsb_line; --line) {
rc = gpio_pin_configure_dt(&config->db_gpios[line], flags);
if (rc < 0) {
return rc;
}
}

return 0;
}

static void auxdisplay_hd44780_command(const struct device *dev, bool rs,
uint8_t cmd, uint8_t mode)
{
int rc;
const struct auxdisplay_hd44780_config *config = dev->config;
int8_t i = 7;
const int lsb_line = (mode == AUXDISPLAY_HD44780_MODE_8_BIT) ? 0 : 4;
int ncommands = (mode == AUXDISPLAY_HD44780_MODE_4_BIT) ? 2 : 1;
const bool check_busy_flag = (!config->rw_gpio.port ||
mode == AUXDISPLAY_HD44780_MODE_4_BIT_ONCE) ? false : true;

Check notice on line 129 in drivers/auxdisplay/auxdisplay_hd44780.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

drivers/auxdisplay/auxdisplay_hd44780.c:129 -static void auxdisplay_hd44780_command(const struct device *dev, bool rs, - uint8_t cmd, uint8_t mode) +static void auxdisplay_hd44780_command(const struct device *dev, bool rs, uint8_t cmd, uint8_t mode) { int rc; const struct auxdisplay_hd44780_config *config = dev->config; int8_t i = 7; const int lsb_line = (mode == AUXDISPLAY_HD44780_MODE_8_BIT) ? 0 : 4; int ncommands = (mode == AUXDISPLAY_HD44780_MODE_4_BIT) ? 2 : 1; - const bool check_busy_flag = (!config->rw_gpio.port || - mode == AUXDISPLAY_HD44780_MODE_4_BIT_ONCE) ? false : true; + const bool check_busy_flag = + (!config->rw_gpio.port || mode == AUXDISPLAY_HD44780_MODE_4_BIT_ONCE) ? false + : true;
gpio_pin_set_dt(&config->rs_gpio, rs);
k_sleep(K_NSEC(config->rs_line_delay));
if (check_busy_flag) {
bool busy;

rc = hd44780_db_gpios_configure(dev, lsb_line, GPIO_INPUT | GPIO_PULL_DOWN);
if (rc < 0) {
LOG_ERR("configuration of db-gpios as inputs failed: %d", rc);
return;
}

hd44780_set_rs_rw_lines(dev, 0, 1);
do {
hd44780_pulse_enable_line(dev);

/* We don't care about the other pins. */
busy = gpio_pin_get_dt(&config->db_gpios[7]);

if (config->capabilities.mode == AUXDISPLAY_HD44780_MODE_4_BIT) {
/* In this mode we have to initiate two separate readbacks. */
hd44780_pulse_enable_line(dev);
}
} while (busy);

rc = hd44780_db_gpios_configure(dev, lsb_line, GPIO_OUTPUT);
if (rc < 0) {
LOG_ERR("configuration of db-gpios as outputs failed: %d", rc);
return;
}
}

hd44780_set_rs_rw_lines(dev, rs, 0);
while (ncommands--) {
for (int line = 7; line >= lsb_line; --line) {
gpio_pin_set_dt(&config->db_gpios[line], ((cmd & BIT(i)) ? 1 : 0));
Expand All @@ -107,6 +165,12 @@ static void auxdisplay_hd44780_command(const struct device *dev, bool rs, uint8_

hd44780_pulse_enable_line(dev);
}

if (!check_busy_flag) {
/* Sleep for a max execution time for a given instruction. */
uint16_t cmd_delay_us = (cmd == AUXDISPLAY_HD44780_CMD_CLEAR) ? 1520 : 37;
k_sleep(K_USEC(cmd_delay_us));

Check warning on line 172 in drivers/auxdisplay/auxdisplay_hd44780.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

LINE_SPACING

drivers/auxdisplay/auxdisplay_hd44780.c:172 Missing a blank line after declarations
}
}

static void hd44780_ic_initialize(const struct device *dev)
Expand Down Expand Up @@ -179,17 +243,6 @@ static int auxdisplay_hd44780_init(const struct device *dev)
return rc;
}

if (config->rw_gpio.port) {
rc = gpio_pin_configure_dt(&config->rw_gpio, GPIO_OUTPUT);

if (rc < 0) {
LOG_ERR("Configuration of RW GPIO failed: %d", rc);
return rc;
}

gpio_pin_set_dt(&config->rw_gpio, 0);
}

rc = gpio_pin_configure_dt(&config->e_gpio, GPIO_OUTPUT);

if (rc < 0) {
Expand Down Expand Up @@ -222,6 +275,15 @@ static int auxdisplay_hd44780_init(const struct device *dev)
++i;
}

if (config->rw_gpio.port) {
rc = gpio_pin_configure_dt(&config->rw_gpio, GPIO_OUTPUT);

if (rc < 0) {
LOG_ERR("Configuration of RW GPIO failed: %d", rc);
return rc;
}
}

if (config->backlight_gpio.port) {
rc = gpio_pin_configure_dt(&config->backlight_gpio, GPIO_OUTPUT);

Expand Down

0 comments on commit 4801d2b

Please sign in to comment.