]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/dsPIC_MPLAB/lcd.c
f29518b2c4637b91a3b832b4deb6d9245479a836
[freertos] / FreeRTOS / Demo / dsPIC_MPLAB / lcd.c
1 /*\r
2  * FreeRTOS Kernel V10.2.0\r
3  * Copyright (C) 2019 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  *\r
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
6  * this software and associated documentation files (the "Software"), to deal in\r
7  * the Software without restriction, including without limitation the rights to\r
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
9  * the Software, and to permit persons to whom the Software is furnished to do so,\r
10  * subject to the following conditions:\r
11  *\r
12  * The above copyright notice and this permission notice shall be included in all\r
13  * copies or substantial portions of the Software.\r
14  *\r
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
21  *\r
22  * http://www.FreeRTOS.org\r
23  * http://aws.amazon.com/freertos\r
24  *\r
25  * 1 tab == 4 spaces!\r
26  */\r
27 \r
28 /* Scheduler includes. */\r
29 #include "FreeRTOS.h"\r
30 #include "task.h"\r
31 #include "queue.h"\r
32 \r
33 /* Demo includes. */\r
34 #include "lcd.h"\r
35 \r
36 /*\r
37  * The LCD is written to by more than one task so is controlled by this\r
38  * 'gatekeeper' task.  This is the only task that is actually permitted to\r
39  * access the LCD directly.  Other tasks wanting to display a message send\r
40  * the message to the gatekeeper.\r
41  */\r
42 static void vLCDTask( void *pvParameters );\r
43 \r
44 /*\r
45  * Setup the peripherals required to communicate with the LCD.\r
46  */\r
47 static void prvSetupLCD( void );\r
48 \r
49 /*\r
50  * Move to the first (0) or second (1) row of the LCD.\r
51  */\r
52 static void prvLCDGotoRow( unsigned short usRow );\r
53 \r
54 /*\r
55  * Write a string of text to the LCD.\r
56  */\r
57 static void prvLCDPutString( char *pcString );\r
58 \r
59 /*\r
60  * Clear the LCD.\r
61  */\r
62 static void prvLCDClear( void );\r
63 \r
64 /*-----------------------------------------------------------*/\r
65 \r
66 /* Brief delay to permit the LCD to catch up with commands. */\r
67 #define lcdVERY_SHORT_DELAY     ( 1 )\r
68 #define lcdSHORT_DELAY          ( 4 / portTICK_PERIOD_MS )\r
69 #define lcdLONG_DELAY           ( 15 / portTICK_PERIOD_MS )\r
70 \r
71 /* LCD commands. */\r
72 #define lcdCLEAR                        ( 0x01 )\r
73 #define lcdHOME                         ( 0x02 )\r
74 #define lcdLINE2                        ( 0xc0 )\r
75 \r
76 /* SFR that seems to be missing from the standard header files. */\r
77 #define PMAEN                           *( ( unsigned short * ) 0x60c )\r
78 \r
79 /* LCD R/W signal. */\r
80 #define  lcdRW  LATDbits.LATD5\r
81 \r
82 /* LCD lcdRS signal. */\r
83 #define  lcdRS  LATBbits.LATB15\r
84 \r
85 /* LCD lcdE signal . */\r
86 #define  lcdE   LATDbits.LATD4\r
87 \r
88 /* Control signal pin direction. */\r
89 #define  RW_TRIS        TRISDbits.TRISD5\r
90 #define  RS_TRIS        TRISBbits.TRISB15\r
91 #define  E_TRIS         TRISDbits.TRISD4\r
92 \r
93 /* Port for LCD data */\r
94 #define  lcdDATA      LATE\r
95 #define  lcdDATAPORT  PORTE\r
96 \r
97 /* I/O setup for data Port. */\r
98 #define  TRISDATA  TRISE\r
99 \r
100 /* The length of the queue used to send messages to the LCD gatekeeper task. */\r
101 #define lcdQUEUE_SIZE           3\r
102 /*-----------------------------------------------------------*/\r
103 \r
104 /* The queue used to send messages to the LCD task. */\r
105 QueueHandle_t xLCDQueue;\r
106 \r
107 static void prvLCDCommand( char cCommand );\r
108 static void prvLCDData( char cChar );\r
109 \r
110 /*-----------------------------------------------------------*/\r
111 \r
112 QueueHandle_t xStartLCDTask( void )\r
113 {\r
114         /* Create the queue used by the LCD task.  Messages for display on the LCD\r
115         are received via this queue. */\r
116         xLCDQueue = xQueueCreate( lcdQUEUE_SIZE, sizeof( xLCDMessage ) );\r
117 \r
118         /* Start the task that will write to the LCD.  The LCD hardware is\r
119         initialised from within the task itself so delays can be used. */\r
120         xTaskCreate( vLCDTask, "LCD", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL );\r
121 \r
122         return xLCDQueue;\r
123 }\r
124 /*-----------------------------------------------------------*/\r
125 \r
126 static void prvLCDGotoRow( unsigned short usRow )\r
127 {\r
128         if( usRow == 0 )\r
129         {\r
130                 prvLCDCommand( lcdHOME );\r
131         }\r
132         else\r
133         {\r
134                 prvLCDCommand( lcdLINE2 );\r
135         }\r
136 }\r
137 /*-----------------------------------------------------------*/\r
138 \r
139 static void prvLCDCommand( char cCommand )\r
140 {\r
141         /* Prepare RD0 - RD7. */\r
142         lcdDATA &= 0xFF00;\r
143 \r
144         /* Command byte to lcd. */\r
145     lcdDATA |= cCommand;\r
146 \r
147         /* Ensure lcdRW is 0. */\r
148         lcdRW = 0;\r
149     lcdRS = 0;\r
150 \r
151         /* Toggle lcdE line. */\r
152     lcdE = 1;\r
153     vTaskDelay( lcdVERY_SHORT_DELAY );\r
154     lcdE = 0;\r
155 \r
156         vTaskDelay( lcdSHORT_DELAY );\r
157 }\r
158 /*-----------------------------------------------------------*/\r
159 \r
160 static void prvLCDData( char cChar )\r
161 {\r
162         /* ensure lcdRW is 0. */\r
163         lcdRW = 0;\r
164 \r
165         /* Assert register select to 1. */\r
166     lcdRS = 1;\r
167 \r
168         /* Prepare RD0 - RD7. */\r
169         lcdDATA &= 0xFF00;\r
170 \r
171         /* Data byte to lcd. */\r
172     lcdDATA |= cChar;\r
173     lcdE = 1;\r
174         Nop();\r
175     Nop();\r
176     Nop();\r
177 \r
178         /* Toggle lcdE signal. */\r
179     lcdE = 0;\r
180 \r
181         /* Negate register select to 0. */\r
182     lcdRS = 0;\r
183 \r
184         vTaskDelay( lcdVERY_SHORT_DELAY );\r
185 }\r
186 /*-----------------------------------------------------------*/\r
187 \r
188 static void prvLCDPutString( char *pcString )\r
189 {\r
190         /* Write out each character with appropriate delay between each. */\r
191         while( *pcString )\r
192         {\r
193                 prvLCDData( *pcString );\r
194                 pcString++;\r
195                 vTaskDelay( lcdSHORT_DELAY );\r
196         }\r
197 }\r
198 /*-----------------------------------------------------------*/\r
199 \r
200 static void prvLCDClear( void )\r
201 {\r
202         prvLCDCommand( lcdCLEAR );\r
203 }\r
204 /*-----------------------------------------------------------*/\r
205 \r
206 static void prvSetupLCD( void )\r
207 {\r
208         /* Wait for proper power up. */\r
209         vTaskDelay( lcdLONG_DELAY );\r
210 \r
211         /* Set initial states for the data and control pins */\r
212         LATE &= 0xFF00;\r
213 \r
214         /* R/W state set low. */\r
215     lcdRW = 0;\r
216 \r
217         /* lcdRS state set low. */\r
218         lcdRS = 0;\r
219 \r
220         /* lcdE state set low. */\r
221         lcdE = 0;\r
222 \r
223         /* Set data and control pins to outputs */\r
224         TRISE &= 0xFF00;\r
225 \r
226         /* lcdRW pin set as output. */\r
227         RW_TRIS = 0;\r
228 \r
229         /* lcdRS pin set as output. */\r
230         RS_TRIS = 0;\r
231 \r
232         /* lcdE pin set as output. */\r
233         E_TRIS = 0;\r
234 \r
235         /* 1st LCD initialization sequence */\r
236         lcdDATA &= 0xFF00;\r
237     lcdDATA |= 0x0038;\r
238     lcdE = 1;\r
239     Nop();\r
240     Nop();\r
241     Nop();\r
242 \r
243         /* Toggle lcdE signal. */\r
244     lcdE = 0;\r
245 \r
246         vTaskDelay( lcdSHORT_DELAY );\r
247         vTaskDelay( lcdSHORT_DELAY );\r
248         vTaskDelay( lcdSHORT_DELAY );\r
249 \r
250         /* 2nd LCD initialization sequence */\r
251         lcdDATA &= 0xFF00;\r
252     lcdDATA |= 0x0038;\r
253     lcdE = 1;\r
254     Nop();\r
255     Nop();\r
256     Nop();\r
257 \r
258         /* Toggle lcdE signal. */\r
259     lcdE = 0;\r
260 \r
261     vTaskDelay( lcdSHORT_DELAY );\r
262 \r
263         /* 3rd LCD initialization sequence */\r
264         lcdDATA &= 0xFF00;\r
265     lcdDATA |= 0x0038;\r
266     lcdE = 1;\r
267     Nop();\r
268     Nop();\r
269     Nop();\r
270 \r
271         /* Toggle lcdE signal. */\r
272     lcdE = 0;\r
273 \r
274         vTaskDelay( lcdSHORT_DELAY );\r
275 \r
276 \r
277         /* Function set. */\r
278     prvLCDCommand( 0x38 );\r
279 \r
280         /* Display on/off control, cursor blink off (0x0C). */\r
281     prvLCDCommand( 0x0C );\r
282 \r
283         /* Entry mode set (0x06). */\r
284     prvLCDCommand( 0x06 );\r
285 \r
286         prvLCDCommand( lcdCLEAR );\r
287 }\r
288 /*-----------------------------------------------------------*/\r
289 \r
290 static void vLCDTask( void *pvParameters )\r
291 {\r
292 xLCDMessage xMessage;\r
293 unsigned short usRow = 0;\r
294 \r
295         /* Initialise the hardware.  This uses delays so must not be called prior\r
296         to the scheduler being started. */\r
297         prvSetupLCD();\r
298 \r
299         /* Welcome message. */\r
300         prvLCDPutString( "www.FreeRTOS.org" );\r
301 \r
302         for( ;; )\r
303         {\r
304                 /* Wait for a message to arrive that requires displaying. */\r
305                 while( xQueueReceive( xLCDQueue, &xMessage, portMAX_DELAY ) != pdPASS );\r
306 \r
307                 /* Clear the current display value. */\r
308                 prvLCDClear();\r
309 \r
310                 /* Switch rows each time so we can see that the display is still being\r
311                 updated. */\r
312                 prvLCDGotoRow( usRow & 0x01 );\r
313                 usRow++;\r
314                 prvLCDPutString( xMessage.pcMessage );\r
315 \r
316                 /* Delay the requested amount of time to ensure the text just written\r
317                 to the LCD is not overwritten. */\r
318                 vTaskDelay( xMessage.xMinDisplayTime );\r
319         }\r
320 }\r
321 \r
322 \r
323 \r
324 \r