diff --git a/src/Makefile b/src/Makefile index b316bb66..92667b2a 100644 --- a/src/Makefile +++ b/src/Makefile @@ -5,4 +5,4 @@ src-$(CONFIG_HAVE_GPIO) += gpiocmds.c stepper.c endstop.c src-$(CONFIG_HAVE_GPIO_ADC) += adccmds.c src-$(CONFIG_HAVE_GPIO_SPI) += spicmds.c src-$(CONFIG_HAVE_GPIO_HARD_PWM) += pwmcmds.c -src-$(CONFIG_HAVE_USER_INTERFACE) += lcd_st7920.c +src-$(CONFIG_HAVE_USER_INTERFACE) += lcd_st7920.c lcd_hd44780.c diff --git a/src/lcd_hd44780.c b/src/lcd_hd44780.c new file mode 100644 index 00000000..9c23814b --- /dev/null +++ b/src/lcd_hd44780.c @@ -0,0 +1,132 @@ +// Commands for sending messages to a 4-bit hd44780 lcd driver +// +// Copyright (C) 2018 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU GPLv3 license. + +#include "basecmd.h" // oid_alloc +#include "board/gpio.h" // gpio_out_write +#include "board/irq.h" // irq_disable +#include "board/misc.h" // timer_from_us +#include "command.h" // DECL_COMMAND +#include "sched.h" // DECL_SHUTDOWN + +struct hd44780 { + uint32_t last_cmd_time, cmd_wait_ticks; + uint8_t last; + struct gpio_out rs, e, d4, d5, d6, d7; +}; + + +/**************************************************************** + * Transmit functions + ****************************************************************/ + +// Write 4 bits to the hd44780 using the 4bit parallel interface +static __always_inline void +hd44780_xmit_bits(uint8_t toggle, struct gpio_out e, struct gpio_out d4 + , struct gpio_out d5, struct gpio_out d6, struct gpio_out d7) +{ + gpio_out_toggle(e); + if (toggle & 0x10) + gpio_out_toggle(d4); + if (toggle & 0x20) + gpio_out_toggle(d5); + if (toggle & 0x40) + gpio_out_toggle(d6); + if (toggle & 0x80) + gpio_out_toggle(d7); + gpio_out_toggle(e); +} + +// Transmit 8 bits to the chip +static void +hd44780_xmit_byte(struct hd44780 *h, uint8_t data) +{ + struct gpio_out e = h->e, d4 = h->d4, d5 = h->d5, d6 = h->d6, d7 = h->d7; + hd44780_xmit_bits(h->last ^ data, e, d4, d5, d6, d7); + h->last = data << 4; + hd44780_xmit_bits(data ^ h->last, e, d4, d5, d6, d7); +} + +// Transmit a series of bytes to the chip +static void +hd44780_xmit(struct hd44780 *h, uint8_t len, uint8_t *data) +{ + uint32_t last_cmd_time=h->last_cmd_time, cmd_wait_ticks=h->cmd_wait_ticks; + while (len--) { + uint8_t b = *data++; + while (timer_read_time() - last_cmd_time < cmd_wait_ticks) + irq_poll(); + hd44780_xmit_byte(h, b); + last_cmd_time = timer_read_time(); + } + h->last_cmd_time = last_cmd_time; +} + + +/**************************************************************** + * Interface + ****************************************************************/ + +void +command_config_hd44780(uint32_t *args) +{ + struct hd44780 *h = oid_alloc(args[0], command_config_hd44780, sizeof(*h)); + h->rs = gpio_out_setup(args[1], 0); + h->e = gpio_out_setup(args[2], 0); + h->d4 = gpio_out_setup(args[3], 0); + h->d5 = gpio_out_setup(args[4], 0); + h->d6 = gpio_out_setup(args[5], 0); + h->d7 = gpio_out_setup(args[6], 0); + + // Calibrate cmd_wait_ticks + irq_disable(); + uint32_t start = timer_read_time(); + hd44780_xmit_byte(h, 0); + uint32_t end = timer_read_time(); + irq_enable(); + uint32_t diff = end - start, delay_ticks = args[7]; + if (delay_ticks > diff) + h->cmd_wait_ticks = delay_ticks - diff; +} +DECL_COMMAND(command_config_hd44780, + "config_hd44780 oid=%c rs_pin=%u e_pin=%u" + " d4_pin=%u d5_pin=%u d6_pin=%u d7_pin=%u delay_ticks=%u"); + +void +command_hd44780_send_cmds(uint32_t *args) +{ + struct hd44780 *h = oid_lookup(args[0], command_config_hd44780); + gpio_out_write(h->rs, 0); + uint8_t len = args[1], *cmds = (void*)(size_t)args[2]; + hd44780_xmit(h, len, cmds); +} +DECL_COMMAND(command_hd44780_send_cmds, "hd44780_send_cmds oid=%c cmds=%*s"); + +void +command_hd44780_send_data(uint32_t *args) +{ + struct hd44780 *h = oid_lookup(args[0], command_config_hd44780); + gpio_out_write(h->rs, 1); + uint8_t len = args[1], *data = (void*)(size_t)args[2]; + hd44780_xmit(h, len, data); +} +DECL_COMMAND(command_hd44780_send_data, "hd44780_send_data oid=%c data=%*s"); + +void +hd44780_shutdown(void) +{ + uint8_t i; + struct hd44780 *h; + foreach_oid(i, h, command_config_hd44780) { + gpio_out_write(h->rs, 0); + gpio_out_write(h->e, 0); + gpio_out_write(h->d4, 0); + gpio_out_write(h->d5, 0); + gpio_out_write(h->d6, 0); + gpio_out_write(h->d7, 0); + h->last = 0; + } +} +DECL_SHUTDOWN(hd44780_shutdown);