/* FreeRTOS V8.2.0rc1 - Copyright (C) 2014 Real Time Engineers Ltd. All rights reserved VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. This file is part of the FreeRTOS distribution. FreeRTOS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License (version 2) as published by the Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. >>! NOTE: The modification to the GPL is included to allow you to !<< >>! distribute a combined work that includes FreeRTOS without being !<< >>! obliged to provide the source code for proprietary components !<< >>! outside of the FreeRTOS kernel. !<< FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Full license text is available on the following link: http://www.freertos.org/a00114.html 1 tab == 4 spaces! *************************************************************************** * * * Having a problem? Start by reading the FAQ "My application does * * not run, what could be wrong?". Have you defined configASSERT()? * * * * http://www.FreeRTOS.org/FAQHelp.html * * * *************************************************************************** *************************************************************************** * * * FreeRTOS provides completely free yet professionally developed, * * robust, strictly quality controlled, supported, and cross * * platform software that is more than just the market leader, it * * is the industry's de facto standard. * * * * Help yourself get started quickly while simultaneously helping * * to support the FreeRTOS project by purchasing a FreeRTOS * * tutorial book, reference manual, or both: * * http://www.FreeRTOS.org/Documentation * * * *************************************************************************** *************************************************************************** * * * Investing in training allows your team to be as productive as * * possible as early as possible, lowering your overall development * * cost, and enabling you to bring a more robust product to market * * earlier than would otherwise be possible. Richard Barry is both * * the architect and key author of FreeRTOS, and so also the world's * * leading authority on what is the world's most popular real time * * kernel for deeply embedded MCU designs. Obtaining your training * * from Richard ensures your team will gain directly from his in-depth * * product knowledge and years of usage experience. Contact Real Time * * Engineers Ltd to enquire about the FreeRTOS Masterclass, presented * * by Richard Barry: http://www.FreeRTOS.org/contact * * *************************************************************************** *************************************************************************** * * * You are receiving this top quality software for free. Please play * * fair and reciprocate by reporting any suspected issues and * * participating in the community forum: * * http://www.FreeRTOS.org/support * * * * Thank you! * * * *************************************************************************** http://www.FreeRTOS.org - Documentation, books, training, latest versions, license and Real Time Engineers Ltd. contact details. http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, including FreeRTOS+Trace - an indispensable productivity tool, a DOS compatible FAT file system, and our tiny thread aware UDP/IP stack. http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS licenses offer ticketed support, indemnification and commercial middleware. http://www.SafeRTOS.com - High Integrity Systems also provide a safety engineered and independently SIL3 certified version for use in safety and mission critical applications that require provable dependability. 1 tab == 4 spaces! */ /* Scheduler includes. */ #include "FreeRTOS.h" #include "task.h" #include "queue.h" #include "semphr.h" /* Hardware specifics. */ #include "iodefine.h" #include "lcd.h" /* States used by the LCD tasks. */ #define lcdRIGHT_TO_LEFT 0U #define lcdLEFT_TO_RIGHT 1U #define lcdRUNNING 0U /* Characters on each line. */ #define lcdSTRING_LEN 8 /* Commands sent from the IRQ to the task controlling the second line of the display. */ #define lcdSHIFT_BACK_COMMAND 0x01U #define lcdSTART_STOP_COMMAND 0x02U #define lcdSHIFT_FORWARD_COMMAND 0x03U /* The length of the queue used to send commands from the ISRs. */ #define lcdCOMMAND_QUEUE_LENGTH 32U /* Defines the minimum time that must pass between consecutive button presses to accept a button press as a unique press rather than just a bounce. */ #define lcdMIN_TIME_BETWEEN_INTERRUPTS_MS ( 125UL / portTICK_PERIOD_MS ) /* Button interrupt handlers. */ #pragma interrupt ( prvIRQ1_Handler( vect = 65, enable ) ) static void prvIRQ1_Handler( void ); #pragma interrupt ( prvIRQ3_Handler( vect = 67, enable ) ) static void prvIRQ3_Handler( void ); #pragma interrupt ( prvIRQ4_Handler(vect = 68, enable ) ) static void prvIRQ4_Handler( void ); /* * Setup the IO needed for the buttons to generate interrupts. */ static void prvSetupButtonIOAndInterrupts( void ); /* * A task that simply scrolls a string from left to right, then back from the * right to the left. This is done on the first line of the display. */ static void prvLCDTaskLine1( void *pvParameters ); /* * If no buttons are pushed, then this task acts as per prvLCDTaskLine1(), but * using the second line of the display. * * Using the buttons, it is possible to start and stop the scrolling of the * text. Once the scrolling has been stopped, other buttons can be used to * manually scroll the text either left or right. */ static void prvLCDTaskLine2( void *pvParameters ); /* * Looks at the direction the string is currently being scrolled in, and moves * the index into the portion of the string that can be seen on the display * either forward or backward as appropriate. */ static prvScrollString( unsigned char *pucDirection, unsigned short *pusPosition, size_t xStringLength ); /* * Displays lcdSTRING_LEN characters starting from pcString on the line of the * display requested by ucLine. */ static void prvDisplayNextString( unsigned char ucLine, char *pcString ); /* * Called from the IRQ interrupts, which are generated on button pushes. Send * ucCommand to the task on the button command queue if * lcdMIN_TIME_BETWEEN_INTERRUPTS_MS milliseconds have passed since the button * was last pushed (for debouncing). */ static portBASE_TYPE prvSendCommandOnDebouncedInput( TickType_t *pxTimeLastInterrupt, unsigned char ucCommand ); /*-----------------------------------------------------------*/ /* The queue used to pass commands from the button interrupt handlers to the prvLCDTaskLine2() task. */ static QueueHandle_t xButtonCommandQueue = NULL; /* The mutex used to ensure only one task writes to the display at any one time. */ static SemaphoreHandle_t xLCDMutex = NULL; /* The string that is scrolled up and down the first line of the display. */ static const char cDataString1[] = " http://www.FreeRTOS.org "; /* The string that is scrolled/nudged up and down the second line of the display. */ 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........"; /* Structures passed into the two tasks to inform them which line to use on the display, how long to delay for, and which string to use. */ struct _LCD_Params xLCDLine1 = { LCD_LINE1, 215, ( char * ) cDataString1 }; struct _LCD_Params xLCDLine2 = { LCD_LINE2, 350, ( char * ) cDataString2 }; /*-----------------------------------------------------------*/ void vStartButtonAndLCDDemo( void ) { prvSetupButtonIOAndInterrupts(); InitialiseDisplay(); /* Create the mutex used to guard the LCD. */ xLCDMutex = xSemaphoreCreateMutex(); configASSERT( xLCDMutex ); /* Create the queue used to pass commands from the IRQ interrupts to the prvLCDTaskLine2() task. */ xButtonCommandQueue = xQueueCreate( lcdCOMMAND_QUEUE_LENGTH, sizeof( unsigned char ) ); configASSERT( xButtonCommandQueue ); /* Start the two tasks as described at the top of this file. */ xTaskCreate( prvLCDTaskLine1, "LCD1", configMINIMAL_STACK_SIZE * 3, ( void * ) &xLCDLine1, tskIDLE_PRIORITY + 1, NULL ); xTaskCreate( prvLCDTaskLine2, "LCD2", configMINIMAL_STACK_SIZE * 3, ( void * ) &xLCDLine2, tskIDLE_PRIORITY + 2, NULL ); } /*-----------------------------------------------------------*/ static void prvLCDTaskLine1( void *pvParameters ) { struct _LCD_Params *pxLCDParamaters = ( struct _LCD_Params * ) pvParameters; unsigned short usPosition = 0U; unsigned char ucDirection = lcdRIGHT_TO_LEFT; for( ;; ) { vTaskDelay( pxLCDParamaters->Speed / portTICK_PERIOD_MS ); /* Write the string. */ prvDisplayNextString( pxLCDParamaters->Line, &( pxLCDParamaters->ptr_str[ usPosition ] ) ); /* Move the string in whichever direction the scroll is currently going in. */ prvScrollString( &ucDirection, &usPosition, strlen( pxLCDParamaters->ptr_str ) ); } } /*-----------------------------------------------------------*/ static void prvLCDTaskLine2( void *pvParameters ) { struct _LCD_Params *pxLCDParamaters = ( struct _LCD_Params * ) pvParameters; unsigned short usPosition = 0U; unsigned char ucDirection = lcdRIGHT_TO_LEFT, ucStatus = lcdRUNNING, ucQueueData; TickType_t xDelayTicks = ( pxLCDParamaters->Speed / portTICK_PERIOD_MS ); for(;;) { /* Wait for a message from an IRQ handler. */ if( xQueueReceive( xButtonCommandQueue, &ucQueueData, xDelayTicks ) != pdPASS ) { /* A message was not received before xDelayTicks ticks passed, so generate the next string to display and display it. */ prvDisplayNextString( pxLCDParamaters->Line, &( pxLCDParamaters->ptr_str[ usPosition ] ) ); /* Move the string in whichever direction the scroll is currently going in. */ prvScrollString( &ucDirection, &usPosition, strlen( pxLCDParamaters->ptr_str ) ); } else { /* A command was received. Process it. */ switch( ucQueueData ) { case lcdSTART_STOP_COMMAND : /* If the LCD is running, top it. If the LCD is stopped, start it. */ ucStatus = !ucStatus; if( ucStatus == lcdRUNNING ) { xDelayTicks = ( pxLCDParamaters->Speed / portTICK_PERIOD_MS ); } else { xDelayTicks = portMAX_DELAY; } break; case lcdSHIFT_BACK_COMMAND : if( ucStatus != lcdRUNNING ) { /* If not already at the start of the display.... */ if( usPosition != 0U ) { /* ....move the display position back by one char. */ usPosition--; prvDisplayNextString( pxLCDParamaters->Line, &( pxLCDParamaters->ptr_str[ usPosition ] ) ); } } break; case lcdSHIFT_FORWARD_COMMAND : if( ucStatus != lcdRUNNING ) { /* If not already at the end of the display.... */ if( usPosition != ( strlen( pxLCDParamaters->ptr_str ) - ( lcdSTRING_LEN - 1 ) ) ) { /* ....move the display position forward by one char. */ usPosition++; prvDisplayNextString( pxLCDParamaters->Line, &( pxLCDParamaters->ptr_str[ usPosition ] ) ); } } break; } } } } /*-----------------------------------------------------------*/ void prvSetupButtonIOAndInterrupts( void ) { /* Configure SW 1-3 pin settings */ PORT3.PDR.BIT.B1 = 0; /* Switch 1 - Port 3.1 - IRQ1 */ PORT3.PDR.BIT.B3 = 0; /* Switch 2 - Port 3.3 - IRQ3 */ PORT3.PDR.BIT.B4 = 0; /* Switch 3 - Port 3.4 - IRQ4 */ PORT3.PMR.BIT.B1 = 1; PORT3.PMR.BIT.B3 = 1; PORT3.PMR.BIT.B4 = 1; MPC.PWPR.BIT.B0WI = 0; /* Writing to the PFSWE bit is enabled */ MPC.PWPR.BIT.PFSWE = 1; /* Writing to the PFS register is enabled */ MPC.P31PFS.BIT.ISEL = 1; MPC.P33PFS.BIT.ISEL = 1; MPC.P34PFS.BIT.ISEL = 1; /* IRQ1 */ ICU.IER[ 0x08 ].BIT.IEN1 = 1; ICU.IPR[ 65 ].BIT.IPR = configMAX_SYSCALL_INTERRUPT_PRIORITY - 1; ICU.IR[ 65 ].BIT.IR = 0; ICU.IRQCR[ 1 ].BIT.IRQMD = 2; /* Rising edge */ /* IRQ3 */ ICU.IER[ 0x08 ].BIT.IEN3 = 1; ICU.IPR[ 67 ].BIT.IPR = configMAX_SYSCALL_INTERRUPT_PRIORITY - 1; ICU.IR[ 67 ].BIT.IR = 0; ICU.IRQCR[ 3 ].BIT.IRQMD = 2; /* Rising edge */ /* IRQ4 */ ICU.IER[ 0x08 ].BIT.IEN4 = 1; ICU.IPR[ 68 ].BIT.IPR = configMAX_SYSCALL_INTERRUPT_PRIORITY - 1; ICU.IR[ 68 ].BIT.IR = 0; ICU.IRQCR[ 4 ].BIT.IRQMD = 2; /* Rising edge */ } /*-----------------------------------------------------------*/ static prvScrollString( unsigned char *pucDirection, unsigned short *pusPosition, size_t xStringLength ) { /* Check which way to scroll. */ if( *pucDirection == lcdRIGHT_TO_LEFT ) { /* Move to the next character. */ ( *pusPosition )++; /* Has the end of the string been reached? */ if( ( *pusPosition ) == ( xStringLength - ( lcdSTRING_LEN - 1 ) ) ) { /* Switch direction. */ *pucDirection = lcdLEFT_TO_RIGHT; ( *pusPosition )--; } } else { /* Move (backward) to the next character. */ ( *pusPosition )--; if( *pusPosition == 0U ) { /* Switch Direction. */ *pucDirection = lcdRIGHT_TO_LEFT; } } } /*-----------------------------------------------------------*/ static void prvDisplayNextString( unsigned char ucLine, char *pcString ) { static char cSingleLine[ lcdSTRING_LEN + 1 ]; xSemaphoreTake( xLCDMutex, portMAX_DELAY ); strncpy( cSingleLine, pcString, lcdSTRING_LEN ); DisplayString( ucLine, cSingleLine ); xSemaphoreGive( xLCDMutex ); } /*-----------------------------------------------------------*/ static portBASE_TYPE prvSendCommandOnDebouncedInput( TickType_t *pxTimeLastInterrupt, unsigned char ucCommand ) { portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; TickType_t xCurrentTickCount; /* Check the time now for debouncing purposes. */ xCurrentTickCount = xTaskGetTickCountFromISR(); /* Has enough time passed since the button was last push to accept it as a unique press? */ if( ( xCurrentTickCount - *pxTimeLastInterrupt ) > lcdMIN_TIME_BETWEEN_INTERRUPTS_MS ) { xQueueSendToBackFromISR( xButtonCommandQueue, &ucCommand, &xHigherPriorityTaskWoken ); } /* Remember the time now, so debounce can be performed again on the next interrupt. */ *pxTimeLastInterrupt = xCurrentTickCount; return xHigherPriorityTaskWoken; } /*-----------------------------------------------------------*/ static void prvIRQ1_Handler( void ) { static TickType_t xTimeLastInterrupt = 0UL; static const unsigned char ucCommand = lcdSHIFT_BACK_COMMAND; portBASE_TYPE xHigherPriorityTaskWoken; xHigherPriorityTaskWoken = prvSendCommandOnDebouncedInput( &xTimeLastInterrupt, ucCommand ); portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); } /*-----------------------------------------------------------*/ static void prvIRQ3_Handler(void) { static TickType_t xTimeLastInterrupt = 0UL; static const unsigned char ucCommand = lcdSTART_STOP_COMMAND; portBASE_TYPE xHigherPriorityTaskWoken; xHigherPriorityTaskWoken = prvSendCommandOnDebouncedInput( &xTimeLastInterrupt, ucCommand ); portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); } /*-----------------------------------------------------------*/ static void prvIRQ4_Handler(void) { static TickType_t xTimeLastInterrupt = 0UL; static const unsigned char ucCommand = lcdSHIFT_FORWARD_COMMAND; portBASE_TYPE xHigherPriorityTaskWoken; xHigherPriorityTaskWoken = prvSendCommandOnDebouncedInput( &xTimeLastInterrupt, ucCommand ); portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); }