rusEFI
An attempt to build an Engine Control Unit
lcd_HD44780.cpp
Go to the documentation of this file.
1 /**
2  * @file lcd_HD44780.cpp
3  * @brief HD44780 character display driver
4  *
5  * see http://en.wikipedia.org/wiki/Hitachi_HD44780_LCD_controller
6  * @date 13.12.2013
7  * @author Andrey Belomutskiy, (c) 2012-2020
8  */
9 
10 #include "global.h"
11 
12 #if EFI_HD44780_LCD
13 
14 #include "lcd_HD44780.h"
15 #include "pin_repository.h"
16 #include "string.h"
17 
18 #include "engine.h"
19 
21 
22 enum {
29 
30 // LCD_2X16_8_BIT_BUS = 0x30,
31 // LCD_2X16_LINE_ONE = 0x20,
32 // LCD_2X16_LINES_TWO = 0x28,
33 // LCD_2X16_FONT_5X8 = 0x20,
34 // LCD_2X16_FONT_5X10 = 0x24,
35 // LCD_2X16_DISPLAY_HOME = 0x02,
36 // LCD_2X16_DISPLAY_RIGHT = 0x1C,
37 // LCD_2X16_DISPLAY_LEFT = 0x18,
38 // LCD_2X16_DISPLAY_SHIFT = 0x05,
39 // LCD_2X16_CURSOR_ON = 0x0A,
40 // LCD_2X16_CURSOR_BLINK = 0x09,
41 // LCD_2X16_CURSOR_RIGHT = 0x14,
42 // LCD_2X16_CURSOR_LEFT = 0x10,
43 // LCD_2X16_SHIFT_LEFT = 0x04,
44 // LCD_2X16_CGRAM_ADDR = 0x40,
45 // LCD_2X16_BUSY_FLAG = 0x80,
46 // LCD_2X16_COMMAND = 0x01,
47 // LCD_2X16_DATA = 0x00,
48 } /*lcd_HD44780_command*/;
49 
50 // http://web.alfredstate.edu/weimandn/lcd/lcd_addressing/lcd_addressing_index.html
51 static const int lineStart[] = { 0, 0x40, 0x14, 0x54 };
52 
53 static int BUSY_WAIT_DELAY = FALSE;
54 static int currentRow = 0;
55 static int currentColumn = 0;
56 
57 static void lcdSleep(int period) {
58  if (BUSY_WAIT_DELAY) {
59  // this mode is useful for displaying messages to report OS fatal issues
60 
61  int ticks = CORE_CLOCK / 1000000 * period;
62  int a = 0;
63  for (int i = 0; i < ticks; i++)
64  a += i;
65  // the purpose of this code is to fool the compiler so that the loop is not optimized away
66  efiAssertVoid(CUSTOM_ERR_6656, a != 0, "true");
67 
68  } else {
69  chThdSleepMicroseconds(period);
70  }
71 }
72 
73 //static char txbuf[1];
74 #define LCD_PORT_EXP_ADDR 0x20
75 
76 // todo: use this method wider!
77 static void writePad(const char *msg, brain_pin_e pin, int bit) {
78  palWritePad(getHwPort(msg, pin), getHwPin(msg, pin), bit);
79 }
80 
81 static bool lcd_HD44780_is_enabled(void) {
82  /* check for valid LCD setting */
84  (isBrainPinValid(CONFIG(HD44780_rs))) &&
85  (isBrainPinValid(CONFIG(HD44780_e))) &&
86  (isBrainPinValid(CONFIG(HD44780_db4))) &&
87  (isBrainPinValid(CONFIG(HD44780_db5))) &&
88  (isBrainPinValid(CONFIG(HD44780_db6))) &&
89  (isBrainPinValid(CONFIG(HD44780_db7))));
90 }
91 
92 //-----------------------------------------------------------------------------
93 static void lcd_HD44780_write(uint8_t data) {
95  writePad("lcd", CONFIG(HD44780_db7),
96  data & 0x80 ? 1 : 0);
97  writePad("lcd", CONFIG(HD44780_db6),
98  data & 0x40 ? 1 : 0);
99  writePad("lcd", CONFIG(HD44780_db5),
100  data & 0x20 ? 1 : 0);
101  writePad("lcd", CONFIG(HD44780_db4),
102  data & 0x10 ? 1 : 0);
103 
104  writePad("lcd", CONFIG(HD44780_e), 1); // En high
105  lcdSleep(10); // enable pulse must be >450ns
106  writePad("lcd", CONFIG(HD44780_e), 0); // En low
107  lcdSleep(40); // commands need > 37us to settle
108  } else {
109 
110  // LCD D4_pin -> P4
111  // LCD D5_pin -> P5
112  // LCD D6_pin -> P6
113  // LCD D7_pin -> P7
114  // LCD Pin RS -> P0
115  // LCD Pin RW -> P1
116  // LCD Pin E -> P2
117 
118  // todo: finish all this stuff
119  }
120 }
121 
122 //-----------------------------------------------------------------------------
123 static void lcd_HD44780_write_command(uint8_t data) {
124  palClearPad(getHwPort("lcd", CONFIG(HD44780_rs)), getHwPin("lcd", CONFIG(HD44780_rs)));
125 
126  lcd_HD44780_write(data);
127  lcd_HD44780_write(data << 4);
128 }
129 
130 //-----------------------------------------------------------------------------
131 static void lcd_HD44780_write_data(uint8_t data) {
132  palSetPad(getHwPort("lcd", CONFIG(HD44780_rs)), getHwPin("lcd", CONFIG(HD44780_rs)));
133 
134  lcd_HD44780_write(data);
135  lcd_HD44780_write(data << 4);
136  currentColumn++;
137 
138  palClearPad(getHwPort("lcd", CONFIG(HD44780_rs)), getHwPin("lcd", CONFIG(HD44780_rs)));
139 }
140 
141 //-----------------------------------------------------------------------------
142 void lcd_HD44780_set_position(uint8_t row, uint8_t column) {
143  if (!lcd_HD44780_is_enabled())
144  return;
145 
146  efiAssertVoid(CUSTOM_ERR_6657, row <= engineConfiguration->HD44780height, "invalid row");
147  currentRow = row;
148  currentColumn = column;
150 }
151 
153  if (!lcd_HD44780_is_enabled())
154  return 0;
155 
156  return currentRow;
157 }
158 
160  if (!lcd_HD44780_is_enabled())
161  return 0;
162 
163  return currentColumn;
164 }
165 
166 void lcd_HD44780_print_char(char data) {
167  if (!lcd_HD44780_is_enabled())
168  return;
169 
170  if (data == '\n') {
172  } else {
174  }
175 }
176 
177 void lcd_HD44780_print_string(const char* string) {
178  if (!lcd_HD44780_is_enabled())
179  return;
180 
181  while (*string != 0x00)
182  lcd_HD44780_print_char(*string++);
183 }
184 
185 //getHwPin(CONFIG(HD44780_db7))
186 static void lcdInfo(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
187  efiPrintf("HD44780 RS=%s", hwPortname(CONFIG(HD44780_rs)));
188  efiPrintf("HD44780 E=%s", hwPortname(CONFIG(HD44780_e)));
189  efiPrintf("HD44780 D4=%s", hwPortname(CONFIG(HD44780_db4)));
190  efiPrintf("HD44780 D5=%s", hwPortname(CONFIG(HD44780_db5)));
191  efiPrintf("HD44780 D6=%s", hwPortname(CONFIG(HD44780_db6)));
192  efiPrintf("HD44780 D7=%s", hwPortname(CONFIG(HD44780_db7)));
193 }
194 
202 }
203 
205  if (lcd_HD44780_is_enabled()) {
206  // initialize hardware lines
207  efiSetPadMode("lcd RS", CONFIG(HD44780_rs), PAL_MODE_OUTPUT_PUSHPULL);
208  efiSetPadMode("lcd E", CONFIG(HD44780_e), PAL_MODE_OUTPUT_PUSHPULL);
209  efiSetPadMode("lcd DB4", CONFIG(HD44780_db4), PAL_MODE_OUTPUT_PUSHPULL);
210  efiSetPadMode("lcd DB5", CONFIG(HD44780_db5), PAL_MODE_OUTPUT_PUSHPULL);
211  efiSetPadMode("lcd DB6", CONFIG(HD44780_db6), PAL_MODE_OUTPUT_PUSHPULL);
212  efiSetPadMode("lcd DB7", CONFIG(HD44780_db7), PAL_MODE_OUTPUT_PUSHPULL);
213  // and zero values
214  writePad("lcd", CONFIG(HD44780_rs), 0);
215  writePad("lcd", CONFIG(HD44780_e), 0);
216  writePad("lcd", CONFIG(HD44780_db4), 0);
217  writePad("lcd", CONFIG(HD44780_db5), 0);
218  writePad("lcd", CONFIG(HD44780_db6), 0);
219  writePad("lcd", CONFIG(HD44780_db7), 0);
220  }
221 }
222 
224  addConsoleAction("lcdinfo", lcdInfo);
225 
227  return;
228  }
229 
231  warning(CUSTOM_ERR_DISPLAY_MODE, "Unexpected displayMode %d", engineConfiguration->displayMode);
232  // I2C pins need initialization, code needs more work & testing
233  return;
234  }
235 
236  efiPrintf("lcd_HD44780_init %d", engineConfiguration->displayMode);
237 
238  if (!lcd_HD44780_is_enabled())
239  return;
240 
242 
243  chThdSleepMilliseconds(20); // LCD needs some time to wake up
245  chThdSleepMilliseconds(1);
248 
249  lcd_HD44780_write(LCD_HD44780_4_BIT_BUS); // 4 bit, 2 line
250  chThdSleepMicroseconds(40);
251 
252  lcd_HD44780_write(LCD_HD44780_4_BIT_BUS); // 4 bit, 2 line
253  lcd_HD44780_write(0x80);
254  chThdSleepMicroseconds(40);
255 
256  lcd_HD44780_write_command(0x08); // display and cursor control
257  chThdSleepMicroseconds(40);
258 
260  chThdSleepMilliseconds(2);
261 
263  chThdSleepMilliseconds(2);
264 
266 
268  efiPrintf("lcd_HD44780_init() done");
269 }
270 
271 void lcdShowPanicMessage(char *message) {
272  /* this is not a good idea to access config data
273  * when everything goes wrong... */
274  if (!lcd_HD44780_is_enabled())
275  return;
276 
277  BUSY_WAIT_DELAY = TRUE;
279  lcd_HD44780_print_string("PANIC\n");
280  lcd_HD44780_print_string(message);
281 }
282 
283 #endif /* EFI_HD44780_LCD */
int getCurrentHD44780row(void)
void efiSetPadMode(const char *msg, brain_pin_e brainPin, iomode_t mode)
Definition: io_pins.cpp:70
static bool lcd_HD44780_is_enabled(void)
Definition: lcd_HD44780.cpp:81
brain_pin_e
static void lcdInfo(DECLARE_ENGINE_PARAMETER_SIGNATURE)
int getCurrentHD44780column(void)
void lcd_HD44780_init()
EXTERNC ioportmask_t getHwPin(const char *msg, brain_pin_e brainPin)
static void lcd_HD44780_write_data(uint8_t data)
static int currentRow
Definition: lcd_HD44780.cpp:54
static void writePad(const char *msg, brain_pin_e pin, int bit)
Definition: lcd_HD44780.cpp:77
bool isBrainPinValid(brain_pin_e brainPin)
static void lcd_HD44780_write_command(uint8_t data)
void lcd_HD44780_print_char(char data)
const char * hwPortname(brain_pin_e brainPin)
void efiSetPadUnused(brain_pin_e brainPin)
Definition: io_pins.cpp:84
void lcdShowPanicMessage(char *message)
void stopHD44780_pins()
EXTERNC ioportid_t getHwPort(const char *msg, brain_pin_e brainPin)
void lcd_HD44780_set_position(uint8_t row, uint8_t column)
engine_configuration_s & activeConfiguration
EXTERN_ENGINE
Definition: lcd_HD44780.cpp:20
engine_configuration_s * engineConfiguration
static int BUSY_WAIT_DELAY
Definition: lcd_HD44780.cpp:53
static void lcdSleep(int period)
Definition: lcd_HD44780.cpp:57
static void lcd_HD44780_write(uint8_t data)
Definition: lcd_HD44780.cpp:93
void startHD44780_pins()
bool warning(obd_code_e code, const char *fmt,...)
static const int lineStart[]
Definition: lcd_HD44780.cpp:51
static int currentColumn
Definition: lcd_HD44780.cpp:55
I/O pin registry header.
static const char * msg
void addConsoleAction(const char *token, Void callback)
Register console action without parameters.
void lcd_HD44780_print_string(const char *string)