PIC24 Support Libraries
esos_lcd44780.c
1 /*
2  * "Copyright (c) 2013 Robert B. Reese, Bryan A. Jones, J. W. Bruce ("AUTHORS")"
3  * All rights reserved.
4  * (R. Reese, reese_AT_ece.msstate.edu, Mississippi State University)
5  * (B. A. Jones, bjones_AT_ece.msstate.edu, Mississippi State University)
6  * (J. W. Bruce, jwbruce_AT_ece.msstate.edu, Mississippi State University)
7  *
8  * Permission to use, copy, modify, and distribute this software and its
9  * documentation for any purpose, without fee, and without written agreement is
10  * hereby granted, provided that the above copyright notice, the following
11  * two paragraphs and the authors appear in all copies of this software.
12  *
13  * IN NO EVENT SHALL THE "AUTHORS" BE LIABLE TO ANY PARTY FOR
14  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
15  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE "AUTHORS"
16  * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
17  *
18  * THE "AUTHORS" SPECIFICALLY DISCLAIMS ANY WARRANTIES,
19  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
20  * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
21  * ON AN "AS IS" BASIS, AND THE "AUTHORS" HAS NO OBLIGATION TO
22  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
23  *
24  * Please maintain this header in its entirety when copying/modifying
25  * these files.
26  *
27  *
28  */
29 
30  /**
31  * \addtogroup ESOS_Task_LCD_Service
32  * @{
33  */
34 
35 #include "esos_lcd44780.h"
36 #include "esos_pic24_lcd44780.h"
37 #include <esos.h>
38 #include <stdlib.h>
39 
40 // Main data structure for updating lcd44780
41 struct {
42  BOOL b_cursorPositionNeedsUpdate;
43  uint8_t u8_cursorRow;
44  uint8_t u8_cursorCol;
45 
46  BOOL b_cursorShownNeedsUpdate;
47  BOOL b_cursorShown;
48 
49  BOOL b_cursorBlinkNeedsUpdate;
50  BOOL b_cursorBlink;
51 
52  BOOL b_displayVisibleNeedsUpdate;
53  BOOL b_displayVisible;
54 
55  BOOL ab_lcdBufferNeedsUpdate[ESOS_LCD44780_MEM_HEIGHT][ESOS_LCD44780_MEM_WIDTH];
56  char aac_lcdBuffer[ESOS_LCD44780_MEM_HEIGHT][ESOS_LCD44780_MEM_WIDTH];
57 
58  BOOL ab_customCharNeedsUpdate[ESOS_LCD44780_NUM_CUSTOM_CHARS];
59  esos_lcd44780_char_t ast_customChar[ESOS_LCD44780_NUM_CUSTOM_CHARS];
60 } esos_lcd44780_vars;
61 
62 // Hidden LCD character moduel service/housekeeping task
63 ESOS_USER_TASK( __esos_lcd44780_service )
64 {
65  // Can first initialized the LCD module hardware and setup the LCD service software structures
66  // Also manages the LCD character module got ESOS
67  // The LCD service hidden task will need to maintain a buffer containing the LCD character display
69 
70 
71  // TODO: remove the magic numbers in this section
72  ESOS_TASK_WAIT_TICKS(100); // Wait >15 msec after power is applied
73  ESOS_TASK_WAIT_LCD44780_WRITE_COMMAND_NOWAIT(0x30);
74  ESOS_TASK_WAIT_TICKS(10); // must wait 5ms, busy flag not available
75  ESOS_TASK_WAIT_LCD44780_WRITE_COMMAND_NOWAIT(0x30);
76  ESOS_TASK_WAIT_TICKS(1); // must wait 160us, busy flag not available
77  ESOS_TASK_WAIT_LCD44780_WRITE_COMMAND_NOWAIT(0x30);
78  ESOS_TASK_WAIT_TICKS(1); // must wait 160us, busy flag not available
79  ESOS_TASK_WAIT_LCD44780_WRITE_COMMAND(0x38);
80  ESOS_TASK_WAIT_LCD44780_WRITE_COMMAND(0x10);
81  ESOS_TASK_WAIT_LCD44780_WRITE_COMMAND(0x0C);
82  ESOS_TASK_WAIT_LCD44780_WRITE_COMMAND(0x06);
83 
84  // Send startup sequence from datasheet
85  ESOS_TASK_WAIT_LCD44780_WRITE_COMMAND( ESOS_LCD44780_CMD_DISPLAY_ON_OFF);
86  ESOS_TASK_WAIT_LCD44780_WRITE_COMMAND( ESOS_LCD44780_CMD_FUNCTION_SET | 0b00011100);
87  ESOS_TASK_WAIT_LCD44780_WRITE_COMMAND( ESOS_LCD44780_CMD_DISPLAY_ON_OFF |
88  ESOS_LCD44780_CMD_DISPLAY_ON_OFF_CUR |
89  ESOS_LCD44780_CMD_DISPLAY_ON_OFF_DISP);
90  ESOS_TASK_WAIT_LCD44780_WRITE_COMMAND( ESOS_LCD44780_CMD_ENTRY_MODE_SET |
91  ESOS_LCD44780_CMD_ENTRY_MODE_SET_INC);
92 
93  while(TRUE) {
94  static uint8_t i, u8_col, u8_row;
95 
96  if(esos_lcd44780_vars.b_cursorPositionNeedsUpdate) {
97  esos_lcd44780_vars.b_cursorPositionNeedsUpdate = FALSE;
98  ESOS_TASK_WAIT_LCD44780_SET_DATA_ADDRESS(esos_lcd44780_vars.u8_cursorRow > 0 ? 0x40 : 0x00 |
99  esos_lcd44780_vars.u8_cursorCol);
100  }
101 
102  if(esos_lcd44780_vars.b_cursorShownNeedsUpdate ||
103  esos_lcd44780_vars.b_cursorBlinkNeedsUpdate ||
104  esos_lcd44780_vars.b_displayVisibleNeedsUpdate) {
105  esos_lcd44780_vars.b_cursorShownNeedsUpdate = FALSE;
106  esos_lcd44780_vars.b_cursorBlinkNeedsUpdate = FALSE;
107  esos_lcd44780_vars.b_displayVisibleNeedsUpdate = FALSE;
108  ESOS_TASK_WAIT_LCD44780_WRITE_COMMAND( ESOS_LCD44780_CMD_DISPLAY_ON_OFF |
109  (esos_lcd44780_vars.b_cursorShown ? ESOS_LCD44780_CMD_DISPLAY_ON_OFF_CUR : 0) |
110  (esos_lcd44780_vars.b_cursorBlink ? ESOS_LCD44780_CMD_DISPLAY_ON_OFF_BLINK : 0) |
111  (esos_lcd44780_vars.b_displayVisible ? ESOS_LCD44780_CMD_DISPLAY_ON_OFF_DISP : 0));
112  }
113 
114  for(u8_row = 0; u8_row < ESOS_LCD44780_MEM_HEIGHT; ++u8_row) {
115  for(u8_col = 0; u8_col < ESOS_LCD44780_MEM_WIDTH; ++u8_col) {
116  // Update all consecutive characters that need it, but only send the address once.
117  if(esos_lcd44780_vars.ab_lcdBufferNeedsUpdate[u8_row][u8_col]) {
118  esos_lcd44780_vars.b_cursorPositionNeedsUpdate = TRUE;
119  ESOS_TASK_WAIT_LCD44780_SET_DATA_ADDRESS((u8_row > 0 ? 0x40 : 0x00) | u8_col);
120  do {
121  esos_lcd44780_vars.ab_lcdBufferNeedsUpdate[u8_row][u8_col] = FALSE;
122  ESOS_TASK_WAIT_LCD44780_WRITE_DATA(esos_lcd44780_vars.aac_lcdBuffer[u8_row][u8_col]);
123  ++u8_col;
124  ESOS_TASK_YIELD();
125  } while(esos_lcd44780_vars.ab_lcdBufferNeedsUpdate[u8_row][u8_col]
126  && u8_col < ESOS_LCD44780_MEM_WIDTH);
127  }
128  ESOS_TASK_YIELD();
129  }
130  }
131 
132  for(i = 0; i < ESOS_LCD44780_NUM_CUSTOM_CHARS; ++i) {
133  // Update all characters that need updating, but only send the CG address once.
134  if(esos_lcd44780_vars.ab_customCharNeedsUpdate[i]) {
135  // We destroy the hardware's cursor position, so fix it later.
136  esos_lcd44780_vars.b_cursorPositionNeedsUpdate = TRUE;
137  ESOS_TASK_WAIT_LCD44780_SET_CG_ADDRESS(8 * i);
138 
139  do {
140  static int n;
141 
142  esos_lcd44780_vars.ab_customCharNeedsUpdate[i] = FALSE;
143 
144  for(n = 0; n < 8; ++n) {
145  ESOS_TASK_WAIT_LCD44780_WRITE_DATA(esos_lcd44780_vars.ast_customChar[i].au8_data[n]);
146  }
147  ++i;
148  ESOS_TASK_YIELD();
149  } while(esos_lcd44780_vars.ab_customCharNeedsUpdate[i] && i < ESOS_LCD44780_NUM_CUSTOM_CHARS);
150  }
151  ESOS_TASK_YIELD();
152  }
153 
154  ESOS_TASK_YIELD();
155  }
156 
157  ESOS_TASK_END();
158 }
159 
160 void esos_lcd44780_configDisplay( void )
161 {
162  unsigned int u8_column;
163 
164  esos_lcd44780_vars.b_displayVisible = TRUE;
165  esos_lcd44780_vars.b_displayVisibleNeedsUpdate = TRUE;
166  esos_lcd44780_vars.b_cursorShown = FALSE;
167  esos_lcd44780_vars.b_cursorShownNeedsUpdate = TRUE;
168  esos_lcd44780_vars.b_cursorBlink = FALSE;
169  esos_lcd44780_vars.b_cursorBlinkNeedsUpdate = TRUE;
170 
171  esos_lcd44780_clearScreen();
172 
173  for(u8_column = 0; u8_column < ESOS_LCD44780_NUM_CUSTOM_CHARS; ++u8_column) {
174  esos_lcd44780_vars.ab_customCharNeedsUpdate[u8_column] = FALSE;
175  }
176 }
177 
178 void esos_lcd44780_init( void )
179 {
180  // Set up the hardware aspects of the HWxxx interface of the LCD module service
181  // direction, thresholds, etc
182  __esos_lcd44780_hw_configDataPinsAsOutput();
183  __ESOS_LCD44780_HW_SET_RW_WRITE();
184  __ESOS_LCD44780_HW_SET_RS_REGISTERS();
185 
186  // give HW specific code a chance to do anything else to init/config
187  __esos_lcd44780_hw_config();
188 
189  // install our LCD housekeeping task into the scheduler
190  esos_RegisterTask( __esos_lcd44780_service );
191 }
192 
193 void esos_lcd44780_clearScreen( void )
194 {
195  uint8_t u8_height;
196  uint8_t u8_width;
197  // Clears the buffer
198  for(u8_height = 0; u8_height < ESOS_LCD44780_MEM_HEIGHT; u8_height++){
199  for(u8_width = 0; u8_width < ESOS_LCD44780_MEM_WIDTH; u8_width++){
200  esos_lcd44780_vars.aac_lcdBuffer[u8_height][u8_width] = ' ';
201  esos_lcd44780_vars.ab_lcdBufferNeedsUpdate[u8_height][u8_width] = TRUE;
202  }
203  }
204 
205  esos_lcd44780_setCursor(0,0);
206  esos_lcd44780_vars.b_cursorPositionNeedsUpdate = TRUE;
207 }
208 
209 void esos_lcd44780_setCursorHome( void )
210 {
211  esos_lcd44780_setCursor(0,0);
212  esos_lcd44780_vars.b_cursorPositionNeedsUpdate = TRUE;
213 }
214 
215 void esos_lcd44780_setCursor( uint8_t u8_row, uint8_t u8_column )
216 {
217  // Move cursor to (u8_row,u8_column) without changing memory buffer or the display
218  // TODO: Write hardware-independent code here
219 }
220 
221 void esos_lcd44780_writeChar( uint8_t u8_row, uint8_t u8_column, uint8_t u8_data )
222 {
223  esos_lcd44780_vars.aac_lcdBuffer[u8_row][u8_column] = u8_data;
224  esos_lcd44780_vars.ab_lcdBufferNeedsUpdate[u8_row][u8_column] = TRUE;
225 }
226 
227 uint8_t esos_lcd44780_getChar( uint8_t u8_row, uint8_t u8_column )
228 {
229  return esos_lcd44780_vars.aac_lcdBuffer[u8_row][u8_column];
230 }
231 
232 void esos_lcd44780_writeBuffer( uint8_t u8_row, uint8_t u8_column, uint8_t *pu8_data, uint8_t u8_bufflen )
233 {
234  // Write u8_bufflen characters from pu8_data to (u8_row,u8_column)
235  // TODO: Write hardware-independent code here
236 }
237 
238 void esos_lcd44780_getBuffer( uint8_t u8_row, uint8_t u8_column, uint8_t *pu8_data, uint8_t u8_bufflen )
239 {
240  // Return pu8_data with u8_bufflen characters currently displayed beginning at (u8_row,u8_column)
241  // TODO: Write hardware-independent code here
242 }
243 
244 void esos_lcd44780_writeString( uint8_t u8_row, uint8_t u8_column, char *psz_data )
245 {
246  // Write zero-terminated string psz_data to location starting at (u8_row,u8_column)
247  // TODO: Write hardware-independent code here
248 }
249 
250 void esos_lcd44780_setCursorDisplay( BOOL u8_state )
251 {
252  // Set cursor display state to u8_state
253  // TODO: Write hardware-independent code here
254 }
255 
256 BOOL esos_lcd44780_getCursorDisplay( void )
257 {
258  // Return cursor display state
259  // TODO: Write hardware-independent code here
260 }
261 
262 void esos_lcd44780_setCursorBlink( BOOL u8_state )
263 {
264  // Set cursor blink state to u8_state
265  // TODO: Write hardware-independent code here
266 }
267 
268 BOOL esos_lcd44780_getCursorBlink( void )
269 {
270  // Return cursor blink state
271  // TODO: Write hardware-independent code here
272 }
273 
274 void esos_lcd44780_setDisplayVisible( BOOL u8_state )
275 {
276  // Set display visible state to u8_state
277  // TODO: Write hardware-independent code here
278 }
279 
280 BOOL esos_lcd44780_getDisplayVisible( void )
281 {
282  // Return display visible state
283  // TODO: Write hardware-independent code here
284 }
285 
286 void esos_lcd44780_setCustomChar( uint8_t u8_charSlot, uint8_t *pu8_charData )
287 {
288  // Set custom character memory for u8_charSlot to data in pu8_charData
289  // TODO: Write hardware-independent code here
290 }
291 
292 void esos_lcd44780_getCustomChar( uint8_t u8_charSlot, uint8_t *pu8_charData )
293 {
294  // Return pu8_charData with custom character memory for u8_charSlot
295  // TODO: Write hardware-independent code here
296 }
297 
298 BOOL esos_lcd44780_isCurrent( void )
299 {
300  uint8_t u8_row, u8_column;
301 
302  if(esos_lcd44780_vars.b_cursorPositionNeedsUpdate ||
303  esos_lcd44780_vars.b_cursorBlinkNeedsUpdate ||
304  esos_lcd44780_vars.b_displayVisibleNeedsUpdate) {
305  return FALSE;
306  }
307 
308  for(u8_row = 0; u8_row < ESOS_LCD44780_MEM_HEIGHT; ++u8_row) {
309  for(u8_column = 0; u8_column < ESOS_LCD44780_MEM_WIDTH; ++u8_column) {
310  if(esos_lcd44780_vars.ab_lcdBufferNeedsUpdate[u8_row][u8_column]) {
311  return FALSE;
312  }
313  }
314  }
315 
316  for(u8_column = 0; u8_column < ESOS_LCD44780_NUM_CUSTOM_CHARS; ++u8_column) {
317  if(esos_lcd44780_vars.ab_customCharNeedsUpdate[u8_column]) {
318  return FALSE;
319  }
320  }
321 
322  return TRUE;
323 }
324 
325 ESOS_CHILD_TASK(__esos_lcd44780_read_u8, uint8_t *pu8_data, BOOL b_isData, BOOL b_useBusyFlag)
326 {
327  ESOS_TASK_BEGIN();
328 
329  if(b_useBusyFlag) {
330  do {
331  ESOS_ALLOCATE_CHILD_TASK(th_lcd44780_child);
332  ESOS_TASK_SPAWN_AND_WAIT( th_lcd44780_child, __esos_task_wait_lcd44780_while_busy );
333  } while (FALSE);
334  }
335 
336  if( b_isData ){
337  __ESOS_LCD44780_HW_SET_RS_DATA();
338  } else {
339  __ESOS_LCD44780_HW_SET_RS_REGISTERS();
340  }
341 
342  __ESOS_LCD44780_HW_SET_RW_READ();
343  __esos_lcd44780_hw_configDataPinsAsInput();
344 
345  __ESOS_LCD44780_HW_SET_E_HIGH();
346  ESOS_TASK_YIELD();
347  *pu8_data = __esos_lcd44780_hw_getDataPins();
348  __ESOS_LCD44780_HW_SET_E_LOW();
349  ESOS_TASK_YIELD();
350 
351  ESOS_TASK_END();
352 }
353 
354 ESOS_CHILD_TASK(__esos_lcd44780_write_u8, uint8_t u8_data, BOOL b_isData, BOOL b_useBusyFlag)
355 {
356  ESOS_TASK_BEGIN();
357 
358  if(b_useBusyFlag) {
359  do {
360  ESOS_ALLOCATE_CHILD_TASK(th_lcd44780_child);
361  ESOS_TASK_SPAWN_AND_WAIT( th_lcd44780_child, __esos_task_wait_lcd44780_while_busy );
362  } while (FALSE);
363  }
364 
365  if( b_isData ){
366  __ESOS_LCD44780_HW_SET_RS_DATA();
367  } else {
368  __ESOS_LCD44780_HW_SET_RS_REGISTERS();
369  }
370 
371  __ESOS_LCD44780_HW_SET_RW_WRITE();
372  __esos_lcd44780_hw_configDataPinsAsOutput();
373 
374  __esos_lcd44780_hw_setDataPins( u8_data );
375 
376  __ESOS_LCD44780_HW_SET_E_HIGH();
377  ESOS_TASK_YIELD();
378  __ESOS_LCD44780_HW_SET_E_LOW();
379  ESOS_TASK_YIELD();
380 
381  ESOS_TASK_END();
382 }
383 
384 ESOS_CHILD_TASK( __esos_task_wait_lcd44780_while_busy )
385 {
386  static BOOL b_hw_lcd_isBusy = FALSE;
387 
388  ESOS_TASK_BEGIN();
389 
390  while ( TRUE ) {
391  __esos_lcd44780_hw_configDataPinsAsInput();
392  __ESOS_LCD44780_HW_SET_RS_REGISTERS();
393  __ESOS_LCD44780_HW_SET_RW_READ();
394  __ESOS_LCD44780_HW_SET_E_HIGH();
395  b_hw_lcd_isBusy = (__esos_lcd44780_hw_getDataPins() & 0x80);
396  __ESOS_LCD44780_HW_SET_E_LOW();
397  if ( b_hw_lcd_isBusy ){
398  ESOS_TASK_YIELD();
399  } else {
400  ESOS_TASK_EXIT();
401  }
402  };
403 
404  ESOS_TASK_END();
405 }
#define ESOS_TASK_EXIT()
Definition: esos_task.h:513
ESOS_TASK_HANDLE esos_RegisterTask(uint8_t(*taskname)(ESOS_TASK_HANDLE pstTask))
Definition: esos.c:86
#define ESOS_CHILD_TASK(taskname,...)
Definition: esos_task.h:247
BOOL
Definition: all_generic.h:402
#define ESOS_TASK_YIELD()
Definition: esos_task.h:590
#define ESOS_TASK_WAIT_TICKS(u32_duration)
Definition: esos_task.h:376
#define ESOS_ALLOCATE_CHILD_TASK(pstName)
Definition: esos_task.h:448
#define ESOS_TASK_END()
Definition: esos_task.h:272
#define ESOS_TASK_SPAWN_AND_WAIT(pstChild, pfnChild,...)
Definition: esos_task.h:436
#define ESOS_TASK_BEGIN()
Definition: esos_task.h:260
ESOS_USER_TASK(CANFactory)
Definition: esos_ecan.c:70
unsigned char uint8_t
An abbreviation for an 8-bit unsigned integer.
Definition: dataXferImpl.h:194