2 * FreeRTOS Kernel V10.0.0
\r
3 * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
\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
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
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
23 * http://www.FreeRTOS.org
\r
24 * http://aws.amazon.com/freertos
\r
26 * 1 tab == 4 spaces!
\r
29 /* Scheduler includes. */
\r
30 #include "FreeRTOS.h"
\r
35 /* Hardware specifics. */
\r
36 #include "iodefine.h"
\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
44 /* Characters on each line. */
\r
45 #define lcdSTRING_LEN 8
\r
47 /* Commands sent from the IRQ to the task controlling the second line of the
\r
49 #define lcdSHIFT_BACK_COMMAND 0x01U
\r
50 #define lcdSTART_STOP_COMMAND 0x02U
\r
51 #define lcdSHIFT_FORWARD_COMMAND 0x03U
\r
53 /* The length of the queue used to send commands from the ISRs. */
\r
54 #define lcdCOMMAND_QUEUE_LENGTH 32U
\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
60 /* Button interrupt handlers. */
\r
61 #pragma interrupt ( prvIRQ1_Handler( vect = 65, enable ) )
\r
62 static void prvIRQ1_Handler( void );
\r
64 #pragma interrupt ( prvIRQ3_Handler( vect = 67, enable ) )
\r
65 static void prvIRQ3_Handler( void );
\r
67 #pragma interrupt ( prvIRQ4_Handler(vect = 68, enable ) )
\r
68 static void prvIRQ4_Handler( void );
\r
71 * Setup the IO needed for the buttons to generate interrupts.
\r
73 static void prvSetupButtonIOAndInterrupts( void );
\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
79 static void prvLCDTaskLine1( void *pvParameters );
\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
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
89 static void prvLCDTaskLine2( void *pvParameters );
\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
96 static prvScrollString( unsigned char *pucDirection, unsigned short *pusPosition, size_t xStringLength );
\r
99 * Displays lcdSTRING_LEN characters starting from pcString on the line of the
\r
100 * display requested by ucLine.
\r
102 static void prvDisplayNextString( unsigned char ucLine, char *pcString );
\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
110 static portBASE_TYPE prvSendCommandOnDebouncedInput( TickType_t *pxTimeLastInterrupt, unsigned char ucCommand );
\r
112 /*-----------------------------------------------------------*/
\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
118 /* The mutex used to ensure only one task writes to the display at any one
\r
120 static SemaphoreHandle_t xLCDMutex = NULL;
\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
125 /* The string that is scrolled/nudged up and down the second line of the
\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
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
133 LCD_LINE1, 215, ( char * ) cDataString1
\r
136 struct _LCD_Params xLCDLine2 =
\r
138 LCD_LINE2, 350, ( char * ) cDataString2
\r
142 /*-----------------------------------------------------------*/
\r
144 void vStartButtonAndLCDDemo( void )
\r
146 prvSetupButtonIOAndInterrupts();
\r
147 InitialiseDisplay();
\r
149 /* Create the mutex used to guard the LCD. */
\r
150 xLCDMutex = xSemaphoreCreateMutex();
\r
151 configASSERT( xLCDMutex );
\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
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
162 /*-----------------------------------------------------------*/
\r
164 static void prvLCDTaskLine1( void *pvParameters )
\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
172 vTaskDelay( pxLCDParamaters->Speed / portTICK_PERIOD_MS );
\r
174 /* Write the string. */
\r
175 prvDisplayNextString( pxLCDParamaters->Line, &( pxLCDParamaters->ptr_str[ usPosition ] ) );
\r
177 /* Move the string in whichever direction the scroll is currently going
\r
179 prvScrollString( &ucDirection, &usPosition, strlen( pxLCDParamaters->ptr_str ) );
\r
182 /*-----------------------------------------------------------*/
\r
184 static void prvLCDTaskLine2( void *pvParameters )
\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
193 /* Wait for a message from an IRQ handler. */
\r
194 if( xQueueReceive( xButtonCommandQueue, &ucQueueData, xDelayTicks ) != pdPASS )
\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
200 /* Move the string in whichever direction the scroll is currently
\r
202 prvScrollString( &ucDirection, &usPosition, strlen( pxLCDParamaters->ptr_str ) );
\r
206 /* A command was received. Process it. */
\r
207 switch( ucQueueData )
\r
209 case lcdSTART_STOP_COMMAND :
\r
211 /* If the LCD is running, top it. If the LCD is stopped, start
\r
213 ucStatus = !ucStatus;
\r
215 if( ucStatus == lcdRUNNING )
\r
217 xDelayTicks = ( pxLCDParamaters->Speed / portTICK_PERIOD_MS );
\r
221 xDelayTicks = portMAX_DELAY;
\r
226 case lcdSHIFT_BACK_COMMAND :
\r
228 if( ucStatus != lcdRUNNING )
\r
230 /* If not already at the start of the display.... */
\r
231 if( usPosition != 0U )
\r
233 /* ....move the display position back by one char. */
\r
235 prvDisplayNextString( pxLCDParamaters->Line, &( pxLCDParamaters->ptr_str[ usPosition ] ) );
\r
241 case lcdSHIFT_FORWARD_COMMAND :
\r
243 if( ucStatus != lcdRUNNING )
\r
245 /* If not already at the end of the display.... */
\r
246 if( usPosition != ( strlen( pxLCDParamaters->ptr_str ) - ( lcdSTRING_LEN - 1 ) ) )
\r
248 /* ....move the display position forward by one
\r
251 prvDisplayNextString( pxLCDParamaters->Line, &( pxLCDParamaters->ptr_str[ usPosition ] ) );
\r
259 /*-----------------------------------------------------------*/
\r
261 void prvSetupButtonIOAndInterrupts( void )
\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
268 PORT3.PMR.BIT.B1 = 1;
\r
269 PORT3.PMR.BIT.B3 = 1;
\r
270 PORT3.PMR.BIT.B4 = 1;
\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
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
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
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
296 /*-----------------------------------------------------------*/
\r
298 static prvScrollString( unsigned char *pucDirection, unsigned short *pusPosition, size_t xStringLength )
\r
300 /* Check which way to scroll. */
\r
301 if( *pucDirection == lcdRIGHT_TO_LEFT )
\r
303 /* Move to the next character. */
\r
304 ( *pusPosition )++;
\r
306 /* Has the end of the string been reached? */
\r
307 if( ( *pusPosition ) == ( xStringLength - ( lcdSTRING_LEN - 1 ) ) )
\r
309 /* Switch direction. */
\r
310 *pucDirection = lcdLEFT_TO_RIGHT;
\r
311 ( *pusPosition )--;
\r
316 /* Move (backward) to the next character. */
\r
317 ( *pusPosition )--;
\r
318 if( *pusPosition == 0U )
\r
320 /* Switch Direction. */
\r
321 *pucDirection = lcdRIGHT_TO_LEFT;
\r
325 /*-----------------------------------------------------------*/
\r
327 static void prvDisplayNextString( unsigned char ucLine, char *pcString )
\r
329 static char cSingleLine[ lcdSTRING_LEN + 1 ];
\r
331 xSemaphoreTake( xLCDMutex, portMAX_DELAY );
\r
332 strncpy( cSingleLine, pcString, lcdSTRING_LEN );
\r
333 DisplayString( ucLine, cSingleLine );
\r
334 xSemaphoreGive( xLCDMutex );
\r
336 /*-----------------------------------------------------------*/
\r
338 static portBASE_TYPE prvSendCommandOnDebouncedInput( TickType_t *pxTimeLastInterrupt, unsigned char ucCommand )
\r
340 portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
\r
341 TickType_t xCurrentTickCount;
\r
343 /* Check the time now for debouncing purposes. */
\r
344 xCurrentTickCount = xTaskGetTickCountFromISR();
\r
346 /* Has enough time passed since the button was last push to accept it as a
\r
348 if( ( xCurrentTickCount - *pxTimeLastInterrupt ) > lcdMIN_TIME_BETWEEN_INTERRUPTS_MS )
\r
350 xQueueSendToBackFromISR( xButtonCommandQueue, &ucCommand, &xHigherPriorityTaskWoken );
\r
353 /* Remember the time now, so debounce can be performed again on the next
\r
355 *pxTimeLastInterrupt = xCurrentTickCount;
\r
357 return xHigherPriorityTaskWoken;
\r
359 /*-----------------------------------------------------------*/
\r
361 static void prvIRQ1_Handler( void )
\r
363 static TickType_t xTimeLastInterrupt = 0UL;
\r
364 static const unsigned char ucCommand = lcdSHIFT_BACK_COMMAND;
\r
365 portBASE_TYPE xHigherPriorityTaskWoken;
\r
367 xHigherPriorityTaskWoken = prvSendCommandOnDebouncedInput( &xTimeLastInterrupt, ucCommand );
\r
368 portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
\r
370 /*-----------------------------------------------------------*/
\r
372 static void prvIRQ3_Handler(void)
\r
374 static TickType_t xTimeLastInterrupt = 0UL;
\r
375 static const unsigned char ucCommand = lcdSTART_STOP_COMMAND;
\r
376 portBASE_TYPE xHigherPriorityTaskWoken;
\r
378 xHigherPriorityTaskWoken = prvSendCommandOnDebouncedInput( &xTimeLastInterrupt, ucCommand );
\r
379 portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
\r
381 /*-----------------------------------------------------------*/
\r
383 static void prvIRQ4_Handler(void)
\r
385 static TickType_t xTimeLastInterrupt = 0UL;
\r
386 static const unsigned char ucCommand = lcdSHIFT_FORWARD_COMMAND;
\r
387 portBASE_TYPE xHigherPriorityTaskWoken;
\r
389 xHigherPriorityTaskWoken = prvSendCommandOnDebouncedInput( &xTimeLastInterrupt, ucCommand );
\r
390 portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
\r