From 39687aa7c7b138d2a1ce2551f2400bade3b1a6fb Mon Sep 17 00:00:00 2001 From: James McKenzie Date: Sun, 2 Aug 2015 23:30:06 +0100 Subject: fis --- app/lcd.c | 344 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 344 insertions(+) create mode 100644 app/lcd.c (limited to 'app/lcd.c') 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 (); +} -- cgit v1.2.3