From 1cde0968e2fd9865371ec141e8d84ba4c48fb204 Mon Sep 17 00:00:00 2001 From: RichardBarry Date: Thu, 5 Feb 2009 13:01:37 +0000 Subject: [PATCH] Continue 78K0R development. git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@676 1d2547de-c912-0410-9cb9-b8ca96c0e9e2 --- Demo/NEC_78K0R_IAR/ButtonISR.s26 | 20 +- Demo/NEC_78K0R_IAR/ButtonTask.c | 46 ++++- Demo/NEC_78K0R_IAR/FreeRTOSConfig.h | 4 +- Demo/NEC_78K0R_IAR/RegTest.s26 | 19 +- Demo/NEC_78K0R_IAR/int78K0R.h | 58 ------ Demo/NEC_78K0R_IAR/main.c | 216 ++++++++++++++-------- Demo/NEC_78K0R_IAR/rtosdemo.ewp | 6 +- Demo/NEC_78K0R_IAR/settings/rtosdemo.wsdt | 6 +- 8 files changed, 225 insertions(+), 150 deletions(-) delete mode 100644 Demo/NEC_78K0R_IAR/int78K0R.h diff --git a/Demo/NEC_78K0R_IAR/ButtonISR.s26 b/Demo/NEC_78K0R_IAR/ButtonISR.s26 index 9ddf25772..cef488cf4 100644 --- a/Demo/NEC_78K0R_IAR/ButtonISR.s26 +++ b/Demo/NEC_78K0R_IAR/ButtonISR.s26 @@ -30,6 +30,14 @@ ; ;------------------------------------------------------------------------------ +; +; This file defines a wrapper for the interrupt generated each time the button +; on the target board is pushed. The asm wrapper is used to save and restore +; the task context as a context switch may occur within the ISR itself. +; The C portion of the ISR is defined within ButtonTask.c. +; + +; Include the portSAVE_CONTEXT and portRESTORE_CONTEXT macros. #include "ISR_Support.h" PUBLIC vButtonISRWrapper @@ -37,15 +45,21 @@ RSEG CODE:CODE -vButtonISRWrapper: +vButtonISRWrapper: + ; Save the current task context. portSAVE_CONTEXT + + ; Call the C portion of the ISR. call vButtonISRHandler + + ; Restore the context of whichever task is to run next - which might be + ; different from the task that was originally interrupted. portRESTORE_CONTEXT - RETI + reti - ; Set ISR location to the Interrupt vector table. + ; Place the ISR into the vector table. COMMON INTVEC:CODE:ROOT(1) ORG 8 `??vButtonISRWrapper??INTVEC 8`: diff --git a/Demo/NEC_78K0R_IAR/ButtonTask.c b/Demo/NEC_78K0R_IAR/ButtonTask.c index a15202cd8..c5d38acdb 100644 --- a/Demo/NEC_78K0R_IAR/ButtonTask.c +++ b/Demo/NEC_78K0R_IAR/ButtonTask.c @@ -47,35 +47,73 @@ licensing and training services. */ +/* + * This file defines the button push task and ISR as described at the top of + * main.c. The ISR is called from a wrapper function defined in ButtonISR.s26. + */ + +/* Kernel includes. */ #include "FreeRTOS.h" #include "task.h" #include "semphr.h" -static xSemaphoreHandle xButtonSemaphore; +/* The LED output used by the button push task. */ +#define butLED1 P7_bit.no7 + +/* A short delay used for button debouncing. */ +#define butDEBOUNCE_DELAY ( 200 / portTICK_RATE_MS ) -#define LED01 P7_bit.no7 +/* The semaphore used to synchronise the button push task with the interrupt. */ +static xSemaphoreHandle xButtonSemaphore; +/* + * The definition of the button task itself. See the comments at the top of + * main.c. + */ void vButtonTask( void *pvParameters ) { + /* Ensure the semaphore is created before it gets used. */ vSemaphoreCreateBinary( xButtonSemaphore ); for( ;; ) { + /* Block on the semaphore to wait for an interrupt event. The semaphore + is 'given' from vButtonISRHandler() below. Using portMAX_DELAY as the + block time will cause the task to block indefinitely provided + INCLUDE_vTaskSuspend is set to 1 in FreeRTOSConfig.h. */ xSemaphoreTake( xButtonSemaphore, portMAX_DELAY ); - LED01 = !LED01; + + /* The button must have been pushed for this line to be executed. + Simply toggle the LED. */ + butLED1 = !butLED1; - vTaskDelay( 200 / portTICK_RATE_MS ); + /* Wait a short time then clear any pending button pushes as a crude + method of debouncing the switch. xSemaphoreTake() uses a block time of + zero this time so it returns immediately rather than waiting for the + interrupt to occur. */ + vTaskDelay( butDEBOUNCE_DELAY ); xSemaphoreTake( xButtonSemaphore, 0 ); } } /*-----------------------------------------------------------*/ +/* + * The C portion of the interrupt handler. Interrupts are triggered by pushing + * the button on the target board. This interrupt can cause a context switch + * so has an assembly file wrapper defined within ButtonISR.s26. + */ void vButtonISRHandler( void ) { short sHigherPriorityTaskWoken = pdFALSE; + /* 'Give' the semaphore to unblock the button task. */ xSemaphoreGiveFromISR( xButtonSemaphore, &sHigherPriorityTaskWoken ); + /* If giving the semaphore unblocked a task, and the unblocked task has a + priority that is higher than the currently running task, then + sHigherPriorityTaskWoken will have been set to pdTRUE. Passing a pdTRUE + value to portYIELD_FROM_ISR() will cause this interrupt to return directly + to the higher priority unblocked task. */ portYIELD_FROM_ISR( sHigherPriorityTaskWoken ); } /*-----------------------------------------------------------*/ diff --git a/Demo/NEC_78K0R_IAR/FreeRTOSConfig.h b/Demo/NEC_78K0R_IAR/FreeRTOSConfig.h index 64b8bea99..97fb3c442 100644 --- a/Demo/NEC_78K0R_IAR/FreeRTOSConfig.h +++ b/Demo/NEC_78K0R_IAR/FreeRTOSConfig.h @@ -50,7 +50,7 @@ #ifndef FREERTOS_CONFIG_H #define FREERTOS_CONFIG_H -/* only include in C files */ +/* Only include in C files */ #ifdef __IAR_SYSTEMS_ICC__ #pragma language=extended @@ -90,7 +90,7 @@ #define configUSE_PREEMPTION 1 -/* only use following section for C files */ +/* Only use following section for C files */ #ifdef __IAR_SYSTEMS_ICC__ #define configUSE_IDLE_HOOK 0 diff --git a/Demo/NEC_78K0R_IAR/RegTest.s26 b/Demo/NEC_78K0R_IAR/RegTest.s26 index 9b51b407c..a95758b64 100644 --- a/Demo/NEC_78K0R_IAR/RegTest.s26 +++ b/Demo/NEC_78K0R_IAR/RegTest.s26 @@ -30,6 +30,11 @@ ; ;------------------------------------------------------------------------------ + +; +; This file defines the RegTest tasks as described at the top of main.c +; + ;------------------------------------------------------------------------------ #if __CORE__ != __78K0R__ @@ -53,7 +58,7 @@ ; ; Input: NONE ; -; Call: CALL vRegTest1 +; Call: Created as a task. ; ; Output: NONE ; @@ -61,6 +66,7 @@ RSEG CODE:CODE vRegTest1: + ; First fill the registers. MOVW AX, #0x1122 MOVW BC, #0x3344 MOVW DE, #0x5566 @@ -69,10 +75,19 @@ vRegTest1: MOV ES, #0x02 loop1: + ; Continuously check that the register values remain at their expected + ; values. The BRK is to test the yield. This task runs at low priority + ; so will also regularly get preempted. BRK + + ; Compare with the expected value. CMPW AX, #0x1122 BZ +5 + ; Jump over the branch to vRegTestError() if the register contained the + ; expected value - otherwise flag an error by executing vRegTestError(). BR vRegTestError + + ; Repeat for all the registers. MOVW AX, BC CMPW AX, #0x3344 BZ +5 @@ -104,7 +119,7 @@ loop1: ; ; Input: NONE ; -; Call: CALL vRegTest1 +; Call: Created as a task. ; ; Output: NONE ; diff --git a/Demo/NEC_78K0R_IAR/int78K0R.h b/Demo/NEC_78K0R_IAR/int78K0R.h deleted file mode 100644 index 2bd33182e..000000000 --- a/Demo/NEC_78K0R_IAR/int78K0R.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - FreeRTOS.org V5.0.2 - Copyright (C) 2003-2008 Richard Barry. - - This file is part of the FreeRTOS.org distribution. - - FreeRTOS.org is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - FreeRTOS.org 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 - along with FreeRTOS.org; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - A special exception to the GPL can be applied should you wish to distribute - a combined work that includes FreeRTOS.org, without being obliged to provide - the source code for any proprietary components. See the licensing section - of http://www.FreeRTOS.org for full details of how and when the exception - can be applied. - - *************************************************************************** - *************************************************************************** - * * - * SAVE TIME AND MONEY! We can port FreeRTOS.org to your own hardware, * - * and even write all or part of your application on your behalf. * - * See http://www.OpenRTOS.com for details of the services we provide to * - * expedite your project. * - * * - *************************************************************************** - *************************************************************************** - - Please ensure to read the configuration and relevant port sections of the - online documentation. - - http://www.FreeRTOS.org - Documentation, latest information, license and - contact details. - - http://www.SafeRTOS.com - A version that is certified for use in safety - critical systems. - - http://www.OpenRTOS.com - Commercial support, development, porting, - licensing and training services. -*/ - -#ifndef INTEGER_TASKS_H -#define INTEGER_TASKS_H - -void vStartIntegerMathTasks( unsigned portBASE_TYPE uxPriority ); -portBASE_TYPE xAreIntegerMathsTaskStillRunning( void ); - -#endif - - diff --git a/Demo/NEC_78K0R_IAR/main.c b/Demo/NEC_78K0R_IAR/main.c index 45b666fcb..7c2c2e465 100644 --- a/Demo/NEC_78K0R_IAR/main.c +++ b/Demo/NEC_78K0R_IAR/main.c @@ -47,6 +47,34 @@ licensing and training services. */ +/* + * Creates all the demo application tasks, then starts the scheduler. The WEB + * documentation provides more details of the standard demo application tasks. + * In addition to the standard demo tasks, the following tasks and tests are + * defined and/or created within this file: + * + * "Check" task - This only executes every three seconds but has a high priority + * to ensure it gets processor time. Its main function is to check that all the + * standard demo tasks are still operational. If everything is running as + * expected then the check task will toggle an LED every 3 seconds. An error + * being discovered in any task will cause the toggle rate to increase to 500ms. + * + * "Reg test" tasks - These fill the registers with known values, then check + * that each register still contains its expected value. Each task uses + * different values. The tasks run with very low priority so get preempted very + * frequently. A register containing an unexpected value is indicative of an + * error in the context switching mechanism. + * + * + * Also in addition to the standard demo tasks is a button push task. This is + * a very basic task that is included as an example of how to write an interrupt + * service routine that interacts with a task. The button on the target board + * is used to generate an interrupt that 'gives' a semaphore in order to unblock + * a task. In doing so the task is synchronised with the interrupt. Each time + * the task unblocks it simply toggles an LED before entering the Blocked state + * again to wait for the next button push. + */ + /* Standard includes. */ #include #include @@ -55,8 +83,7 @@ #include "FreeRTOS.h" #include "task.h" -/* Demo file headers. */ -#include "int78K0R.h" +/* Standard demo file headers. */ #include "PollQ.h" #include "semtest.h" #include "GenQTest.h" @@ -77,57 +104,91 @@ #define mainNO_ERROR_TOGGLE_PERIOD ( ( portTickType ) 3000 / portTICK_RATE_MS ) #define mainERROR_TOGGLE_PERIOD ( ( portTickType ) 500 / portTICK_RATE_MS ) -#define LED00 P7_bit.no6 -#define LED01 P7_bit.no7 +/* The LED toggled by the check task. */ +#define mainLED_0 P7_bit.no6 -/* - * 78K0R/Kx3 Option Byte Definition - * watchdog disabled, LVI enabled, OCD interface enabled - */ -__root __far const unsigned portCHAR OptionByte[OPT_BYTES_SIZE] @ 0x00C0 = -{ - WATCHDOG_DISABLED, LVI_ENABLED, RESERVED_FF, OCD_ENABLED -}; +/* A value that is passed in as the parameter to the 'check' task. This is done +purely to check that the parameter passing mechanism is functioning correctly. */ +#define mainCHECK_PARAMETER_VALUE ( 0x345678 ) -/* Security Byte Definition */ -__root __far const unsigned portCHAR SecuIDCode[SECU_ID_SIZE] @ 0x00C4 = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; +/*-----------------------------------------------------------*/ -/* The task function for the "Check" task. */ +/* + * The function that defines the 'check' task as described at the top of this + * file. + */ static void vErrorChecks( void *pvParameters ); -/* 78K0R/Kx3 low level init Initialization of the System Clock */ +/* + * This function is called from the C startup routine to setup the processor - + * in particular the clock source. + */ int __low_level_init(void); +/* + * Functions that define the RegTest tasks as described at the top of this file. + */ extern void vRegTest1( void *pvParameters ); extern void vRegTest2( void *pvParameters ); + +/* + * Function that defines the button push task as described at the top of this + * file. + */ extern void vButtonTask( void *pvParameters ); +/*-----------------------------------------------------------*/ + +/* If an error is discovered by one of the RegTest tasks then this flag is set +to pdFAIL. The 'check' task then inspects this flag to detect errors within +the RegTest tasks. */ static short sRegTestStatus = pdPASS; -portSHORT main( void ) +/* 78K0R Option Byte Definition. Watchdog disabled, LVI enabled, OCD interface +enabled. */ +__root __far const unsigned portCHAR OptionByte[] @ 0x00C0 = +{ + WATCHDOG_DISABLED, LVI_ENABLED, RESERVED_FF, OCD_ENABLED +}; + +/* Security byte definition */ +__root __far const unsigned portCHAR SecuIDCode[] @ 0x00C4 = +{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; + + +/*-----------------------------------------------------------*/ + +short main( void ) { - /* Create the standard demo tasks. */ + /* Creates all the tasks, then starts the scheduler. */ + + /* First create the 'standard demo' tasks. These are used to demonstrate + API functions being used and also to test the kernel port. More information + is provided on the FreeRTOS.org WEB site. */ vStartPolledQueueTasks( mainQUEUE_POLL_PRIORITY ); vStartSemaphoreTasks(mainSEMTEST_PRIORITY); vStartGenericQueueTasks( mainGEN_QUEUE_PRIORITY ); vStartDynamicPriorityTasks(); vCreateBlockTimeTasks(); + /* Create the button push task as described at the top of this file. */ xTaskCreate( vButtonTask, "Button", configMINIMAL_STACK_SIZE, NULL, mainBUTTON_PRIORITY, NULL ); - - /* Create the tasks defined within this file. */ - xTaskCreate( vErrorChecks, "Check", configMINIMAL_STACK_SIZE, (void*)0x12345678, mainCHECK_TASK_PRIORITY, NULL ); + /* Create the RegTest tasks as described at the top of this file. */ xTaskCreate( vRegTest1, "Reg1", configMINIMAL_STACK_SIZE, NULL, 0, NULL ); xTaskCreate( vRegTest2, "Reg2", configMINIMAL_STACK_SIZE, NULL, 0, NULL ); + + /* Create the 'check' task as described at the top of this file. */ + xTaskCreate( vErrorChecks, "Check", configMINIMAL_STACK_SIZE, ( void* )mainCHECK_PARAMETER_VALUE, mainCHECK_TASK_PRIORITY, NULL ); - + /* Finally start the scheduler running. */ vTaskStartScheduler(); + /* If this line is reached then vTaskStartScheduler() returned because there + was insufficient heap memory remaining for the idle task to be created. */ for( ;; ); } /*-----------------------------------------------------------*/ @@ -136,19 +197,24 @@ static void vErrorChecks( void *pvParameters ) { portTickType xToggleRate = mainNO_ERROR_TOGGLE_PERIOD, xLastWakeTime; - /* The pointer will only actually be either 3 or 2 bytes, depending on the - memory model. */ - if( pvParameters != ( void * ) 0x12345678 ) + /* Ensure the parameter was passed in as expected. This is just a test of + the kernel port, the parameter is not actually used for anything. The + pointer will only actually be either 3 or 2 bytes, depending on the memory + model. */ + if( pvParameters != ( void * ) mainCHECK_PARAMETER_VALUE ) { xToggleRate = mainERROR_TOGGLE_PERIOD; } + /* Initialise xLastWakeTime before it is used. After this point it is not + written to directly. */ xLastWakeTime = xTaskGetTickCount(); /* Cycle for ever, delaying then checking all the other tasks are still operating without error. */ for( ;; ) { + /* Wait until it is time to check all the other tasks again. */ vTaskDelayUntil( &xLastWakeTime, xToggleRate ); if( xAreGenericQueueTasksStillRunning() != pdTRUE ) @@ -181,121 +247,114 @@ portTickType xToggleRate = mainNO_ERROR_TOGGLE_PERIOD, xLastWakeTime; xToggleRate = mainERROR_TOGGLE_PERIOD; } - /* Toggle the LED. */ - LED00 = !LED00; + /* Toggle the LED. The toggle rate will depend on whether or not an + error has been found in any tasks. */ + mainLED_0 = !mainLED_0; } } /*-----------------------------------------------------------*/ int __low_level_init(void) { -unsigned portCHAR resetflag = RESF; +unsigned portCHAR ucResetFlag = RESF; portDISABLE_INTERRUPTS(); - /* - * Clock Configuration: - * In this port, to use the internal high speed clock source of the microcontroller - * define the configCLOCK_SOURCE as 1 in FreeRTOSConfig.h. To use an external - * clock define configCLOCK_SOURCE as 0. - */ + /* Clock Configuration: + In this port, to use the internal high speed clock source of the microcontroller + define the configCLOCK_SOURCE as 1 in FreeRTOSConfig.h. To use an external + clock define configCLOCK_SOURCE as 0. */ #if configCLOCK_SOURCE == 1 { - /* - * Set XT1 and XT2 in Input Port Mode - * Set X1 and X2 in Input Port Mode - * High speed oszillation frequency 2MHz <= fMX <= 10MHz - */ + /* Set XT1 and XT2 in Input Port Mode + Set X1 and X2 in Input Port Mode + High speed oscillator frequency 2MHz <= fMX <= 10MHz */ CMC = 0x00; - /* X1 external oszillation stopped */ + /* X1 external oszillation stopped. */ MSTOP = 1; - /* enable internal high speed oszillation */ + /* Enable internal high speed oszillation. */ HIOSTOP = 0; MCM0 = 0; - /* stop internal subsystem clock */ + /* Stop internal subsystem clock. */ XTSTOP = 1; - /* Set clock speed */ + /* Set clock speed. */ CSS = 0; CKC &= (unsigned portCHAR)~0x07; CKC |= 0x00; } #else { - /* - * XT1 and XT2 pin in input port mode - * X1 and X2 pin in crystal resonator mode - * High speed oszillation frequency 10MHz < fMX <= 20MHz - */ + /* XT1 and XT2 pin in input port mode + X1 and X2 pin in crystal resonator mode + High speed oszillation frequency 10MHz < fMX <= 20MHz */ CMC = 0x41; - /* Set oscillation stabilization time */ + /* Set oscillation stabilization time. */ OSTS = 0x07; - /* Set speed mode: fMX > 10MHz for Flash memory high speed operation */ + /* Set speed mode: fMX > 10MHz for Flash memory high speed operation. */ OSMC = 0x01; - /* - * Start up X1 oscillator operation - * Internal high-speed oscillator operating - */ + /* Start up X1 oscillator operation + Internal high-speed oscillator operating. */ MSTOP = 0; - /* Check oscillation stabilization time status */ + /* Check oscillation stabilization time status. */ while(OSTC < 0x07) { - /* wait until X1 clock stabilization time */ + /* Wait until X1 clock stabilization time. */ portNOP(); } - /* Switch CPU clock to X1 oscillator */ + /* Switch CPU clock to X1 oscillator. */ MCM0 = 1; while(MCS != 1) { - /* wait until CPU and peripherals operate with fX1 clock */ + /* Wait until CPU and peripherals operate with fX1 clock. */ portNOP(); } - /* Stop the internal high-speed oscillator operation */ + /* Stop the internal high-speed oscillator operation. */ HIOSTOP = 1; - /* Stop the XT1 oscillator operation */ + /* Stop the XT1 oscillator operation. */ XTSTOP = 1; - /* - * operating frequency f = fx - * Change clock generator setting, if necessary - */ + /* Operating frequency f = fx + Change clock generator setting, if necessary. */ CKC &= 0xF8; - /* From here onwards the X1 oscillator is supplied to the CPU */ + /* From here onwards the X1 oscillator is supplied to the CPU. */ } #endif - /* LED Port Initialization - set Port Register */ + /* LED port initialization - set port register. */ P7 = 0x80; - /* Set Port Mode Register */ + /* Set port mode register. */ PM7 = 0x3F; - /* Switch Pin Initialization - enable pull-up resistor */ + /* Switch pin initialization - enable pull-up resistor. */ PU12_bit.no0 = 1; + + /* INTP0 is used by the button on the target board. */ - /* INTP0 disable */ + /* INTP0 disable. */ PMK0 = 1; - /* INTP0 IF clear */ + /* INTP0 IF clear. */ PIF0 = 0; EGN0_bit.no0 = 1; - /* INTP0 priority low */ + /* INTP0 priority low. */ PPR10 = 0; PPR00 = 1; - /* enable ext. INTP0 interrupt */ + /* Enable ext. INTP0 interrupt */ PMK0 = 0; return pdTRUE; @@ -304,13 +363,20 @@ unsigned portCHAR resetflag = RESF; void vRegTestError( void ) { + /* Called by the RegTest tasks if an error is found. lRegTestStatus is + inspected by the check task. */ sRegTestStatus = pdFAIL; + + /* Do not return from here as the reg test tasks clobber all registers so + function calls may not function correctly. */ for( ;; ); } /*-----------------------------------------------------------*/ void vApplicationStackOverflowHook( void ) { + /* This will get called if an overflow is detected in the stack of a task. + Inspect pxCurrentTCB to see which was the offending task. */ for( ;; ); } diff --git a/Demo/NEC_78K0R_IAR/rtosdemo.ewp b/Demo/NEC_78K0R_IAR/rtosdemo.ewp index fff9da6f9..7a9882afd 100644 --- a/Demo/NEC_78K0R_IAR/rtosdemo.ewp +++ b/Demo/NEC_78K0R_IAR/rtosdemo.ewp @@ -71,7 +71,7 @@