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