summaryrefslogtreecommitdiffstats
path: root/app/lcd.c
diff options
context:
space:
mode:
Diffstat (limited to 'app/lcd.c')
-rw-r--r--app/lcd.c344
1 files changed, 344 insertions, 0 deletions
diff --git a/app/lcd.c b/app/lcd.c
new file mode 100644
index 0000000..714e850
--- /dev/null
+++ b/app/lcd.c
@@ -0,0 +1,344 @@
+#include "project.h"
+
+#define FOO do { printf("lcd:%x\r\n",__LINE__); usart1_drain(); } while (0)
+
+#define PCF8574_I2C_ADDRESS 0x27
+
+#define LINE_RS 0x1
+#define LINE_RnW 0x2
+#define LINE_EN 0x4
+#define LINE_BACKLIGHT 0x8
+
+#define LCD_CLEAR 0x1
+#define LCD_HOME 0x2
+
+#define LCD_DISP 0x8
+#define LCD_DISP_ON 0x4
+#define LCD_DISP_CURSOR 0x2
+#define LCD_DISP_CURSOR_BLINK 0x1
+
+#define LCD_FUNC 0x20
+#define LCD_FUNC_8BIT 0x10
+#define LCD_FUNC_4BIT 0x00
+#define LCD_FUNC_2ROWS 0x08
+#define LCD_FUNC_1ROW 0x00
+#define LCD_FUNC_5x10 0x04
+#define LCD_FUNC_5X7 0x00
+
+#define LCD_SET_DDRAM_ADDR 0x80
+
+#define LCD_H_SHIFT 5
+#define LCD_RS (1 << LCD_H_SHIFT)
+#define LCD_W 16
+#define LCD_W_MASK (LCD_RS -1 )
+#define LCD_H 2
+#define LCD_SZ (LCD_H << LCD_H_SHIFT)
+#define LCD_POS(c,r) (((r) << LCD_H_SHIFT ) +(c))
+
+#define BYTES_PER_BYTE 6
+
+#define DMA_BUF_SZ (BYTES_PER_BYTE * ( (1 + LCD_W) *LCD_H + 1))
+
+
+static int backlight;
+uint8_t fb[LCD_H][LCD_W];
+uint8_t shadow[LCD_H][LCD_W];
+
+static int pos;
+
+
+static void
+clock_nibble (uint8_t n)
+{
+ if (backlight)
+ n |= LINE_BACKLIGHT;
+ i2c_bb_send_data (n);
+ i2c_bb_send_data (LINE_EN | n);
+ i2c_bb_send_data (n);
+}
+
+
+static void
+write_reg (uint8_t c, int r)
+{
+ uint8_t b;
+
+ b = c & 0xf0;
+ if (r)
+ b |= LINE_RS;
+
+ clock_nibble (b);
+
+ b = (c & 0xf) << 4;
+ if (r)
+ b |= LINE_RS;
+
+ clock_nibble (b);
+}
+
+static void
+send_data (uint8_t c)
+{
+ write_reg (c, 1);
+}
+
+
+static void
+send_command (uint8_t c)
+{
+ write_reg (c, 0);
+}
+
+static void
+send_one_command (uint8_t cmd, int delay)
+{
+ i2c_bb_start_transaction (PCF8574_I2C_ADDRESS, I2C_WRITE);
+ send_command (cmd);
+ i2c_bb_stop ();
+ if (delay)
+ delay_ms (delay);
+}
+
+
+
+static void
+cls (void)
+{
+ send_one_command (LCD_CLEAR, 2);
+}
+
+#if 0
+static void
+home (void)
+{
+ send_one_command (LCD_HOME, 2);
+}
+#endif
+
+static void
+on (void)
+{
+ send_one_command (LCD_DISP | LCD_DISP_ON /* | LCD_DISP_CURSOR */ , 4);
+}
+
+static void
+off (void)
+{
+ send_one_command (LCD_DISP, 4);
+}
+
+static int
+lcd_addr (int x, int y)
+{
+ return x + ((y & 1) << 6) + ((y & 2) ? 20 : 0);
+}
+
+
+#if 0
+static void
+move (uint8_t c, uint8_t r)
+{
+ send_one_command (LCD_SET_DDRAM_ADDR | lcd_addr (c, r), 2);
+}
+#endif
+
+
+void
+lcd_refresh (void)
+{
+ int c, r;
+ int addr;
+
+
+ i2c_bb_start_transaction (PCF8574_I2C_ADDRESS, I2C_WRITE);
+
+
+ for (r = 0; r < LCD_H; ++r)
+ {
+ for (c = 0; c < LCD_W; ++c)
+ {
+
+ if (shadow[r][c] != fb[r][c])
+ {
+
+ addr = lcd_addr (c, r);
+
+ if (addr != pos)
+ {
+ send_command (LCD_SET_DDRAM_ADDR | addr);
+ pos = addr;
+ }
+
+ send_data (shadow[r][c]);
+ fb[r][c] = shadow[r][c];
+
+ pos++;
+ }
+
+ }
+ }
+
+ i2c_bb_stop ();
+}
+
+void
+lcd_tick (void)
+{
+ static int u;
+
+ u++;
+
+ if (u < 100)
+ return;
+
+ u = 0;
+
+ if (!memcmp (shadow, fb, sizeof (fb)))
+ return;
+
+ lcd_refresh ();
+}
+
+
+
+
+
+
+void
+lcd_write_char (uint8_t c, int x, int y)
+{
+ shadow[y][x] = c;
+}
+
+
+void
+lcd_erase (int x, int y, int w)
+{
+ uint8_t *ptr = &shadow[y][x];
+ while (w--)
+ *ptr = ' ';
+}
+
+void
+lcd_erase_line (int w, int y)
+{
+ lcd_erase (0, y, w);
+}
+
+void
+lcd_erase_all (void)
+{
+ int y;
+ for (y = 0; y < LCD_H; ++y)
+ {
+ lcd_erase (0, 0, LCD_W);
+ }
+}
+
+void
+lcd_write (char *c, int x, int y)
+{
+ while (*c)
+ {
+ lcd_write_char (*(c++), x++, y);
+ if (x == LCD_W)
+ break;
+ }
+}
+
+#if 0
+static void
+lcd_scroll (uint8_t * p)
+{
+ int i;
+ for (i = 0; i < 3; ++i)
+ {
+ memcpy (p, p + LCD_RS, LCD_W);
+ p += LCD_RS;
+ }
+ memset (p, ' ', LCD_W);
+}
+
+void
+lcd_putc (uint8_t c)
+{
+
+ switch (c)
+ {
+ case '\r':
+ pos &= ~LCD_W_MASK;
+ break;
+ case '\n':
+ pos &= ~LCD_W_MASK;
+ pos += LCD_RS;
+ break;
+ default:
+ buf[pos] = c;
+ pos++;
+ }
+
+
+ if ((pos & LCD_W_MASK) == LCD_W)
+ {
+ pos &= ~LCD_W_MASK;
+ pos += LCD_RS;
+ }
+
+ if (pos == LCD_SZ)
+ {
+ lcd_scroll (buf);
+ pos -= LCD_RS;
+ }
+
+
+}
+#endif
+
+void
+lcd_backlight (int i)
+{
+ backlight = i;
+
+ i2c_bb_start_transaction (PCF8574_I2C_ADDRESS, I2C_WRITE);
+ i2c_bb_send_data (backlight ? LINE_BACKLIGHT : 0);
+ i2c_bb_stop ();
+}
+
+
+
+
+
+
+void
+lcd_reset (void)
+{
+ i2c_bb_start_transaction (PCF8574_I2C_ADDRESS, I2C_WRITE);
+ clock_nibble (0x30);
+ delay_ms (5);
+ clock_nibble (0x30);
+ delay_us (64);
+ clock_nibble (0x30);
+ delay_us (64);
+ clock_nibble (0x20);
+
+ send_command (LCD_FUNC | LCD_FUNC_4BIT | LCD_FUNC_2ROWS | LCD_FUNC_5X7);
+ i2c_bb_stop ();
+ on ();
+ cls ();
+}
+
+void
+lcd_init (void)
+{
+ lcd_backlight (0);
+ lcd_reset ();
+ lcd_backlight (1);
+
+}
+
+void
+lcd_shutdown (void)
+{
+ lcd_backlight (0);
+ off ();
+}