]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/RX200_RX210-RSK_Renesas/RTOSDemo/ButtonAndLCD.c
Update to MIT licensed FreeRTOS V10.0.0 - see https://www.freertos.org/History.txt
[freertos] / FreeRTOS / Demo / RX200_RX210-RSK_Renesas / RTOSDemo / ButtonAndLCD.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 #include "semphr.h"\r
34 \r
35 /* Hardware specifics. */\r
36 #include "iodefine.h"\r
37 #include "lcd.h"\r
38 \r
39 /* States used by the LCD tasks. */\r
40 #define lcdRIGHT_TO_LEFT        0U\r
41 #define lcdLEFT_TO_RIGHT        1U\r
42 #define lcdRUNNING                      0U\r
43 \r
44 /* Characters on each line. */\r
45 #define lcdSTRING_LEN           8 \r
46 \r
47 /* Commands sent from the IRQ to the task controlling the second line of the\r
48 display. */\r
49 #define lcdSHIFT_BACK_COMMAND           0x01U\r
50 #define lcdSTART_STOP_COMMAND           0x02U\r
51 #define lcdSHIFT_FORWARD_COMMAND        0x03U\r
52 \r
53 /* The length of the queue used to send commands from the ISRs. */\r
54 #define lcdCOMMAND_QUEUE_LENGTH         32U\r
55 \r
56 /* Defines the minimum time that must pass between consecutive button presses\r
57 to accept a button press as a unique press rather than just a bounce. */\r
58 #define lcdMIN_TIME_BETWEEN_INTERRUPTS_MS ( 125UL / portTICK_PERIOD_MS )\r
59 \r
60 /* Button interrupt handlers. */\r
61 #pragma interrupt ( prvIRQ1_Handler( vect = 65, enable ) )\r
62 static void prvIRQ1_Handler( void );\r
63 \r
64 #pragma interrupt ( prvIRQ3_Handler( vect = 67, enable ) )\r
65 static void prvIRQ3_Handler( void );\r
66 \r
67 #pragma interrupt ( prvIRQ4_Handler(vect = 68, enable ) )\r
68 static void prvIRQ4_Handler( void );\r
69 \r
70 /* \r
71  * Setup the IO needed for the buttons to generate interrupts. \r
72  */\r
73 static void prvSetupButtonIOAndInterrupts( void );\r
74 \r
75 /*\r
76  * A task that simply scrolls a string from left to right, then back from the\r
77  * right to the left.  This is done on the first line of the display.\r
78  */\r
79 static void prvLCDTaskLine1( void *pvParameters );\r
80 \r
81 /*\r
82  * If no buttons are pushed, then this task acts as per prvLCDTaskLine1(), but\r
83  * using the second line of the display.\r
84  *\r
85  * Using the buttons, it is possible to start and stop the scrolling of the \r
86  * text.  Once the scrolling has been stopped, other buttons can be used to\r
87  * manually scroll the text either left or right.\r
88  */ \r
89 static void prvLCDTaskLine2( void *pvParameters );\r
90 \r
91 /*\r
92  * Looks at the direction the string is currently being scrolled in, and moves\r
93  * the index into the portion of the string that can be seen on the display\r
94  * either forward or backward as appropriate. \r
95  */\r
96 static prvScrollString( unsigned char *pucDirection, unsigned short *pusPosition, size_t xStringLength );\r
97 \r
98 /* \r
99  * Displays lcdSTRING_LEN characters starting from pcString on the line of the\r
100  * display requested by ucLine.\r
101  */\r
102 static void prvDisplayNextString( unsigned char ucLine, char *pcString );\r
103 \r
104 /*\r
105  * Called from the IRQ interrupts, which are generated on button pushes.  Send\r
106  * ucCommand to the task on the button command queue if \r
107  * lcdMIN_TIME_BETWEEN_INTERRUPTS_MS milliseconds have passed since the button\r
108  * was last pushed (for debouncing). \r
109  */\r
110 static portBASE_TYPE prvSendCommandOnDebouncedInput( TickType_t *pxTimeLastInterrupt, unsigned char ucCommand );\r
111 \r
112 /*-----------------------------------------------------------*/\r
113 \r
114 /* The queue used to pass commands from the button interrupt handlers to the\r
115 prvLCDTaskLine2() task. */\r
116 static QueueHandle_t xButtonCommandQueue = NULL;\r
117 \r
118 /* The mutex used to ensure only one task writes to the display at any one\r
119 time. */\r
120 static SemaphoreHandle_t xLCDMutex = NULL;\r
121 \r
122 /* The string that is scrolled up and down the first line of the display. */\r
123 static const char cDataString1[] = "        http://www.FreeRTOS.org        ";\r
124 \r
125 /* The string that is scrolled/nudged up and down the second line of the \r
126 display. */\r
127 static const char cDataString2[] = "........Rx210 Highlights....1.56 DMips/MHz....DSP functions....1.62V-5.5V operation....200 uA/MHz....Up to 512 kBytes Flash....up to 64 kbytes SRAM....EE Dataflash with 100k w/e....1.3 uA in Real Time Clock Mode....Powerful Motor control timer....4 x 16-bit timers....4 x 8-bit timers....Full Real Time Clock calendar with calibration and alarm functions....Up to 16 channels 1 uS 12-bit ADC, with Dual group programmable SCAN, 3 sample and holds, sample accumulate function....DMA controller....Data Transfer Controller....Up to 9 serial Channels....Up to 6 USARTs ( with Simple I2C / SPI )....USART ( with unique Frame based protocol support )....Multimaster IIC....RSPI....Temperature Sensor....Event Link Controller....Comparators....Safety features include CRC....March X....Dual watchdog Timers with window and independent oscillator....ADC self test....I/O Pin Test....Supported with E1 on chip debugger and RSK210 evaluation system....Rx210 Highlights........";\r
128 \r
129 /* Structures passed into the two tasks to inform them which line to use on the\r
130 display, how long to delay for, and which string to use. */\r
131 struct _LCD_Params xLCDLine1 = \r
132 {\r
133         LCD_LINE1, 215, ( char * ) cDataString1 \r
134 };\r
135 \r
136 struct _LCD_Params xLCDLine2 = \r
137 {\r
138         LCD_LINE2, 350, ( char * ) cDataString2\r
139 };\r
140 \r
141 \r
142 /*-----------------------------------------------------------*/\r
143 \r
144 void vStartButtonAndLCDDemo( void )\r
145 {\r
146         prvSetupButtonIOAndInterrupts();\r
147         InitialiseDisplay();\r
148 \r
149         /* Create the mutex used to guard the LCD. */\r
150         xLCDMutex = xSemaphoreCreateMutex();\r
151         configASSERT( xLCDMutex );\r
152         \r
153         /* Create the queue used to pass commands from the IRQ interrupts to the\r
154         prvLCDTaskLine2() task. */\r
155         xButtonCommandQueue = xQueueCreate( lcdCOMMAND_QUEUE_LENGTH, sizeof( unsigned char ) );\r
156         configASSERT( xButtonCommandQueue );\r
157 \r
158         /* Start the two tasks as described at the top of this file. */\r
159         xTaskCreate( prvLCDTaskLine1, "LCD1", configMINIMAL_STACK_SIZE * 3, ( void * ) &xLCDLine1, tskIDLE_PRIORITY + 1, NULL );\r
160         xTaskCreate( prvLCDTaskLine2, "LCD2", configMINIMAL_STACK_SIZE * 3, ( void * ) &xLCDLine2, tskIDLE_PRIORITY + 2, NULL );\r
161 }\r
162 /*-----------------------------------------------------------*/\r
163 \r
164 static void prvLCDTaskLine1( void *pvParameters )\r
165 {\r
166 struct _LCD_Params *pxLCDParamaters = ( struct _LCD_Params * ) pvParameters;\r
167 unsigned short usPosition = 0U;\r
168 unsigned char ucDirection = lcdRIGHT_TO_LEFT;\r
169         \r
170         for( ;; )\r
171         {\r
172                 vTaskDelay( pxLCDParamaters->Speed / portTICK_PERIOD_MS );              \r
173 \r
174                 /* Write the string. */\r
175                 prvDisplayNextString( pxLCDParamaters->Line, &( pxLCDParamaters->ptr_str[ usPosition ] ) );\r
176 \r
177                 /* Move the string in whichever direction the scroll is currently going\r
178                 in. */\r
179                 prvScrollString( &ucDirection, &usPosition, strlen( pxLCDParamaters->ptr_str ) );\r
180         }\r
181 }\r
182 /*-----------------------------------------------------------*/\r
183 \r
184 static void prvLCDTaskLine2( void *pvParameters )\r
185 {\r
186 struct _LCD_Params *pxLCDParamaters = ( struct _LCD_Params * ) pvParameters;\r
187 unsigned short usPosition = 0U;\r
188 unsigned char ucDirection = lcdRIGHT_TO_LEFT, ucStatus = lcdRUNNING, ucQueueData;\r
189 TickType_t xDelayTicks = ( pxLCDParamaters->Speed / portTICK_PERIOD_MS );\r
190         \r
191         for(;;)\r
192         {\r
193                 /* Wait for a message from an IRQ handler. */\r
194                 if( xQueueReceive( xButtonCommandQueue, &ucQueueData, xDelayTicks ) != pdPASS )\r
195                 {\r
196                         /* A message was not received before xDelayTicks ticks passed, so\r
197                         generate the next string to display and display it. */\r
198                         prvDisplayNextString( pxLCDParamaters->Line, &( pxLCDParamaters->ptr_str[ usPosition ] ) );\r
199                         \r
200                         /* Move the string in whichever direction the scroll is currently \r
201                         going in. */\r
202                         prvScrollString( &ucDirection, &usPosition, strlen( pxLCDParamaters->ptr_str ) );                       \r
203                 }\r
204                 else\r
205                 {\r
206                         /* A command was received.  Process it. */\r
207                         switch( ucQueueData )\r
208                         {\r
209                                 case lcdSTART_STOP_COMMAND :\r
210 \r
211                                         /* If the LCD is running, top it.  If the LCD is stopped, start\r
212                                         it. */\r
213                                         ucStatus = !ucStatus;\r
214                                         \r
215                                         if( ucStatus == lcdRUNNING )\r
216                                         {\r
217                                                 xDelayTicks = ( pxLCDParamaters->Speed / portTICK_PERIOD_MS );\r
218                                         }\r
219                                         else\r
220                                         {\r
221                                                 xDelayTicks = portMAX_DELAY;\r
222                                         }\r
223                                         break;\r
224 \r
225                                         \r
226                                 case lcdSHIFT_BACK_COMMAND :\r
227 \r
228                                         if( ucStatus != lcdRUNNING )\r
229                                         {\r
230                                                 /* If not already at the start of the display.... */\r
231                                                 if( usPosition != 0U )\r
232                                                 {\r
233                                                         /* ....move the display position back by one char. */\r
234                                                         usPosition--;                                                                                           \r
235                                                         prvDisplayNextString( pxLCDParamaters->Line, &( pxLCDParamaters->ptr_str[ usPosition ] ) );\r
236                                                 }\r
237                                         }\r
238                                         break;\r
239                                 \r
240                                 \r
241                                 case lcdSHIFT_FORWARD_COMMAND :\r
242 \r
243                                         if( ucStatus != lcdRUNNING )\r
244                                         {\r
245                                                 /* If not already at the end of the display.... */\r
246                                                 if( usPosition != ( strlen( pxLCDParamaters->ptr_str ) - ( lcdSTRING_LEN - 1 ) ) )\r
247                                                 {\r
248                                                         /* ....move the display position forward by one \r
249                                                         char. */\r
250                                                         usPosition++;\r
251                                                         prvDisplayNextString( pxLCDParamaters->Line, &( pxLCDParamaters->ptr_str[ usPosition ] ) );\r
252                                                 }\r
253                                         }\r
254                                         break;\r
255                         }\r
256                 }\r
257         }\r
258 }\r
259 /*-----------------------------------------------------------*/\r
260 \r
261 void prvSetupButtonIOAndInterrupts( void )\r
262 {\r
263         /* Configure SW 1-3 pin settings */\r
264         PORT3.PDR.BIT.B1 = 0;           /* Switch 1 - Port 3.1 - IRQ1 */\r
265         PORT3.PDR.BIT.B3 = 0;           /* Switch 2 - Port 3.3 - IRQ3 */\r
266         PORT3.PDR.BIT.B4 = 0;           /* Switch 3 - Port 3.4 - IRQ4 */\r
267 \r
268         PORT3.PMR.BIT.B1 = 1;\r
269         PORT3.PMR.BIT.B3 = 1;\r
270         PORT3.PMR.BIT.B4 = 1;\r
271 \r
272         MPC.PWPR.BIT.B0WI = 0;          /* Writing to the PFSWE bit is enabled */\r
273         MPC.PWPR.BIT.PFSWE = 1;         /* Writing to the PFS register is enabled */\r
274         MPC.P31PFS.BIT.ISEL = 1;\r
275         MPC.P33PFS.BIT.ISEL = 1;\r
276         MPC.P34PFS.BIT.ISEL = 1;\r
277 \r
278         /* IRQ1 */\r
279         ICU.IER[ 0x08 ].BIT.IEN1 = 1;   \r
280         ICU.IPR[ 65 ].BIT.IPR = configMAX_SYSCALL_INTERRUPT_PRIORITY - 1;\r
281         ICU.IR[ 65 ].BIT.IR = 0;\r
282         ICU.IRQCR[ 1 ].BIT.IRQMD = 2;   /* Rising edge */\r
283 \r
284         /* IRQ3 */\r
285         ICU.IER[ 0x08 ].BIT.IEN3 = 1;   \r
286         ICU.IPR[ 67 ].BIT.IPR = configMAX_SYSCALL_INTERRUPT_PRIORITY - 1;\r
287         ICU.IR[ 67 ].BIT.IR = 0;\r
288         ICU.IRQCR[ 3 ].BIT.IRQMD = 2;   /* Rising edge */\r
289 \r
290         /* IRQ4 */\r
291         ICU.IER[ 0x08 ].BIT.IEN4 = 1;   \r
292         ICU.IPR[ 68 ].BIT.IPR = configMAX_SYSCALL_INTERRUPT_PRIORITY - 1;\r
293         ICU.IR[ 68 ].BIT.IR = 0;\r
294         ICU.IRQCR[ 4 ].BIT.IRQMD = 2;   /* Rising edge */\r
295 }\r
296 /*-----------------------------------------------------------*/\r
297 \r
298 static prvScrollString( unsigned char *pucDirection, unsigned short *pusPosition, size_t xStringLength )\r
299 {\r
300         /* Check which way to scroll. */\r
301         if( *pucDirection == lcdRIGHT_TO_LEFT )\r
302         {\r
303                 /* Move to the next character. */\r
304                 ( *pusPosition )++;\r
305                 \r
306                 /* Has the end of the string been reached? */\r
307                 if( ( *pusPosition ) == ( xStringLength - ( lcdSTRING_LEN - 1 ) ) )\r
308                 {\r
309                         /* Switch direction. */\r
310                         *pucDirection = lcdLEFT_TO_RIGHT;\r
311                         ( *pusPosition )--;                             \r
312                 }\r
313         }\r
314         else\r
315         {\r
316                 /* Move (backward) to the next character. */\r
317                 ( *pusPosition )--;\r
318                 if( *pusPosition == 0U )\r
319                 {\r
320                         /* Switch Direction. */\r
321                         *pucDirection = lcdRIGHT_TO_LEFT;                               \r
322                 }\r
323         }\r
324 }\r
325 /*-----------------------------------------------------------*/\r
326 \r
327 static void prvDisplayNextString( unsigned char ucLine, char *pcString )\r
328 {\r
329 static char cSingleLine[ lcdSTRING_LEN + 1 ];\r
330 \r
331         xSemaphoreTake( xLCDMutex, portMAX_DELAY );\r
332         strncpy( cSingleLine, pcString, lcdSTRING_LEN );\r
333         DisplayString( ucLine, cSingleLine );\r
334         xSemaphoreGive( xLCDMutex );\r
335 }\r
336 /*-----------------------------------------------------------*/\r
337 \r
338 static portBASE_TYPE prvSendCommandOnDebouncedInput( TickType_t *pxTimeLastInterrupt, unsigned char ucCommand )\r
339 {\r
340 portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;\r
341 TickType_t xCurrentTickCount;\r
342         \r
343         /* Check the time now for debouncing purposes. */\r
344         xCurrentTickCount = xTaskGetTickCountFromISR();\r
345         \r
346         /* Has enough time passed since the button was last push to accept it as a\r
347         unique press? */\r
348         if( ( xCurrentTickCount - *pxTimeLastInterrupt ) > lcdMIN_TIME_BETWEEN_INTERRUPTS_MS )\r
349         {\r
350                 xQueueSendToBackFromISR( xButtonCommandQueue, &ucCommand, &xHigherPriorityTaskWoken );\r
351         }\r
352 \r
353         /* Remember the time now, so debounce can be performed again on the next\r
354         interrupt. */   \r
355         *pxTimeLastInterrupt = xCurrentTickCount;\r
356         \r
357         return xHigherPriorityTaskWoken;\r
358 }\r
359 /*-----------------------------------------------------------*/\r
360 \r
361 static void prvIRQ1_Handler( void )\r
362 {\r
363 static TickType_t xTimeLastInterrupt = 0UL;\r
364 static const unsigned char ucCommand = lcdSHIFT_BACK_COMMAND;\r
365 portBASE_TYPE xHigherPriorityTaskWoken;\r
366 \r
367         xHigherPriorityTaskWoken = prvSendCommandOnDebouncedInput( &xTimeLastInterrupt, ucCommand );\r
368         portYIELD_FROM_ISR( xHigherPriorityTaskWoken );\r
369 }\r
370 /*-----------------------------------------------------------*/\r
371 \r
372 static void prvIRQ3_Handler(void)\r
373 {\r
374 static TickType_t xTimeLastInterrupt = 0UL;\r
375 static const unsigned char ucCommand = lcdSTART_STOP_COMMAND;\r
376 portBASE_TYPE xHigherPriorityTaskWoken;\r
377 \r
378         xHigherPriorityTaskWoken = prvSendCommandOnDebouncedInput( &xTimeLastInterrupt, ucCommand );\r
379         portYIELD_FROM_ISR( xHigherPriorityTaskWoken );\r
380 }\r
381 /*-----------------------------------------------------------*/\r
382 \r
383 static void prvIRQ4_Handler(void)\r
384 {\r
385 static TickType_t xTimeLastInterrupt = 0UL;\r
386 static const unsigned char ucCommand = lcdSHIFT_FORWARD_COMMAND;\r
387 portBASE_TYPE xHigherPriorityTaskWoken;\r
388 \r
389         xHigherPriorityTaskWoken = prvSendCommandOnDebouncedInput( &xTimeLastInterrupt, ucCommand );\r
390         portYIELD_FROM_ISR( xHigherPriorityTaskWoken );\r
391 }\r
392 \r