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