/* | |
FreeRTOS V7.4.1 - Copyright (C) 2013 Real Time Engineers Ltd. | |
FEATURES AND PORTS ARE ADDED TO FREERTOS ALL THE TIME. PLEASE VISIT | |
http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. | |
*************************************************************************** | |
* * | |
* FreeRTOS tutorial books are available in pdf and paperback. * | |
* Complete, revised, and edited pdf reference manuals are also * | |
* available. * | |
* * | |
* Purchasing FreeRTOS documentation will not only help you, by * | |
* ensuring you get running as quickly as possible and with an * | |
* in-depth knowledge of how to use FreeRTOS, it will also help * | |
* the FreeRTOS project to continue with its mission of providing * | |
* professional grade, cross platform, de facto standard solutions * | |
* for microcontrollers - completely free of charge! * | |
* * | |
* >>> See http://www.FreeRTOS.org/Documentation for details. <<< * | |
* * | |
* Thank you for using FreeRTOS, and thank you for your support! * | |
* * | |
*************************************************************************** | |
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. See the GNU General Public License for more | |
details. You should have received a copy of the GNU General Public License | |
and the FreeRTOS license exception along with FreeRTOS; if not it can be | |
viewed here: http://www.freertos.org/a00114.html and also obtained by | |
writing to Real Time Engineers Ltd., contact details for whom are available | |
on the FreeRTOS WEB site. | |
1 tab == 4 spaces! | |
*************************************************************************** | |
* * | |
* Having a problem? Start by reading the FAQ "My application does * | |
* not run, what could be wrong?" * | |
* * | |
* http://www.FreeRTOS.org/FAQHelp.html * | |
* * | |
*************************************************************************** | |
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, and our new | |
fully thread aware and reentrant UDP/IP stack. | |
http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High | |
Integrity Systems, who sell the code with commercial support, | |
indemnification and middleware, under the OpenRTOS brand. | |
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. | |
*/ | |
/* 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_RATE_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( portTickType *pxTimeLastInterrupt, unsigned char ucCommand ); | |
/*-----------------------------------------------------------*/ | |
/* The queue used to pass commands from the button interrupt handlers to the | |
prvLCDTaskLine2() task. */ | |
static xQueueHandle xButtonCommandQueue = NULL; | |
/* The mutex used to ensure only one task writes to the display at any one | |
time. */ | |
static xSemaphoreHandle 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_RATE_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; | |
portTickType xDelayTicks = ( pxLCDParamaters->Speed / portTICK_RATE_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_RATE_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( portTickType *pxTimeLastInterrupt, unsigned char ucCommand ) | |
{ | |
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; | |
portTickType 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 portTickType 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 portTickType 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 portTickType xTimeLastInterrupt = 0UL; | |
static const unsigned char ucCommand = lcdSHIFT_FORWARD_COMMAND; | |
portBASE_TYPE xHigherPriorityTaskWoken; | |
xHigherPriorityTaskWoken = prvSendCommandOnDebouncedInput( &xTimeLastInterrupt, ucCommand ); | |
portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); | |
} | |