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