//**************************************************************************** // // scheduler.c - A simple task scheduler // // Copyright (c) 2010-2012 Texas Instruments Incorporated. All rights reserved. // Software License Agreement // // Texas Instruments (TI) is supplying this software for use solely and // exclusively on TI's microcontroller products. The software is owned by // TI and/or its suppliers, and is protected under applicable copyright // laws. You may not combine this software with "viral" open-source // software in order to form a larger program. // // THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS. // NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT // NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY // CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL // DAMAGES, FOR ANY REASON WHATSOEVER. // // This is part of revision 9453 of the Stellaris Firmware Development Package. // //**************************************************************************** #include "inc/hw_types.h" #include "inc/hw_ints.h" #include "driverlib/systick.h" #include "driverlib/sysctl.h" #include "driverlib/interrupt.h" #include "driverlib/debug.h" #include "utils/scheduler.h" //***************************************************************************** // //! \addtogroup scheduler_api //! @{ // //***************************************************************************** static volatile unsigned long g_ulSchedulerTickCount; //**************************************************************************** // //! Handles the SysTick interrupt on behalf of the scheduler module. //! //! Applications using the scheduler module must ensure that this function is //! hooked to the SysTick interrupt vector. //! //! \return None. // //**************************************************************************** void SchedulerSysTickIntHandler(void) { g_ulSchedulerTickCount++; } //**************************************************************************** // //! Initializes the task scheduler. //! //! \param ulTicksPerSecond sets the basic frequency of the SysTick interrupt //! used by the scheduler to determine when to run the various task functions. //! //! This function must be called during application startup to configure the //! SysTick timer. This is used by the scheduler module to determine when each //! of the functions provided in the g_psSchedulerTable array is called. //! //! The caller is responsible for ensuring that SchedulerSysTickIntHandler() //! has previously been installed in the SYSTICK vector in the vector table //! and must also ensure that interrupts are enabled at the CPU level. //! //! Note that this call does not start the scheduler calling the configured //! functions. All function calls are made in the context of later calls to //! SchedulerRun(). This call merely configures the SysTick interrupt that is //! used by the scheduler to determine what the current system time is. //! //! \return None. // //**************************************************************************** void SchedulerInit(unsigned long ulTicksPerSecond) { ASSERT(ulTicksPerSecond); // // Configure SysTick for a periodic interrupt. // SysTickPeriodSet(SysCtlClockGet() / ulTicksPerSecond); SysTickEnable(); SysTickIntEnable(); } //**************************************************************************** // //! Instructs the scheduler to update its task table and make calls to //! functions needing called. //! //! This function must be called periodically by the client to allow the //! scheduler to make calls to any configured task functions if it is their //! time to be called. The call must be made at least as frequently as the //! most frequent task configured in the g_psSchedulerTable array. //! //! Although the scheduler makes use of the SysTick interrupt, all calls to //! functions configured in \e g_psSchedulerTable are made in the context of //! SchedulerRun(). //! //! \return None. // //**************************************************************************** void SchedulerRun(void) { unsigned long ulLoop; tSchedulerTask *psTask; // // Loop through each task in the task table. // for(ulLoop = 0; ulLoop < g_ulSchedulerNumTasks; ulLoop++) { // // Get a pointer to the task information. // psTask = &g_psSchedulerTable[ulLoop]; // // Is this task active and, if so, is it time to call it's function? // if(psTask->bActive && (SchedulerElapsedTicksGet(psTask->ulLastCall) >= psTask->ulFrequencyTicks)) { // // Remember the timestamp at which we make the function call. // psTask->ulLastCall = g_ulSchedulerTickCount; // // Call the task function, passing the provided parameter. // psTask->pfnFunction(psTask->pvParam); } } } //**************************************************************************** // //! Enables a task and allows the scheduler to call it periodically. //! //! \param ulIndex is the index of the task which is to be enabled in the //! global \e g_psSchedulerTable array. //! \param bRunNow is \b true if the task is to be run on the next call to //! SchedulerRun() or \b false if one whole period is to elapse before //! the task is run. //! //! This function marks one of the configured tasks as enabled and causes //! SchedulerRun() to call that task periodically. The caller may choose to //! have the enabled task run for the first time on the next call to //! SchedulerRun() or to wait one full task period before making the first //! call. //! //! \return None. // //**************************************************************************** void SchedulerTaskEnable(unsigned long ulIndex, tBoolean bRunNow) { // // Is the task index passed valid? // if(ulIndex < g_ulSchedulerNumTasks) { // // Yes - mark the task as active. // g_psSchedulerTable[ulIndex].bActive = true; // // Set the last call time to ensure that the function is called either // next time the scheduler is run or after the desired number of ticks // depending upon the value of the bRunNow parameter. // if(bRunNow) { // // Cause the task to run on the next call to SchedulerRun(). // g_psSchedulerTable[ulIndex].ulLastCall = (g_ulSchedulerTickCount - g_psSchedulerTable[ulIndex].ulFrequencyTicks); } else { // // Cause the task to run after one full time period. // g_psSchedulerTable[ulIndex].ulLastCall = g_ulSchedulerTickCount; } } } //**************************************************************************** // //! Disables a task and prevents the scheduler from calling it. //! //! \param ulIndex is the index of the task which is to be disabled in the //! global \e g_psSchedulerTable array. //! //! This function marks one of the configured tasks as inactive and prevents //! SchedulerRun() from calling it. The task may be reenabled by calling //! SchedulerTaskEnable(). //! //! \return None. // //**************************************************************************** void SchedulerTaskDisable(unsigned long ulIndex) { // // Is the task index passed valid? // if(ulIndex < g_ulSchedulerNumTasks) { // // Yes - mark the task as inactive. // g_psSchedulerTable[ulIndex].bActive = false; } } //**************************************************************************** // //! Returns the current system time in ticks since power on. //! //! This function may be called by a client to retrieve the current system //! time. The value returned is a count of ticks elapsed since the system //! last booted. //! //! \return Tick count since last boot. // //**************************************************************************** unsigned long SchedulerTickCountGet(void) { return(g_ulSchedulerTickCount); } //**************************************************************************** // //! Returns the number of ticks elapsed since the provided tick count. //! //! \param ulTickCount is the tick count from which to determine the elapsed //! time. //! //! This function may be called by a client to determine how much time has //! passed since a particular tick count provided in the \e ulTickCount //! parameter. This function takes into account wrapping of the global tick //! counter and assumes that the provided tick count always represents a time //! in the past. The returned value will, of course, be wrong if the tick //! counter has wrapped more than once since the passed \e ulTickCount. As a //! result, please do not use this function if you are dealing with timeouts //! of 497 days or longer (assuming you use a 10mS tick period). //! //! \return The number of ticks elapsed since the provided tick count. // //**************************************************************************** unsigned long SchedulerElapsedTicksGet(unsigned long ulTickCount) { // // Determine the calculation based upon whether the global tick count has // wrapped since the passed ulTickCount. // return(SchedulerElapsedTicksCalc(ulTickCount, g_ulSchedulerTickCount)); } //**************************************************************************** // //! Returns the number of ticks elapsed between two times. //! //! \param ulTickStart is the system tick count for the start of the period. //! \param ulTickEnd is the system tick count for the end of the period. //! //! This function may be called by a client to determine the number of ticks //! which have elapsed between provided starting and ending tick counts. The //! function takes into account wrapping cases where the end tick count is //! lower than the starting count assuming that the ending tick count always //! represents a later time than the starting count. //! //! \return The number of ticks elapsed between the provided start and end //! counts. // //**************************************************************************** unsigned long SchedulerElapsedTicksCalc(unsigned long ulTickStart, unsigned long ulTickEnd) { return((ulTickEnd > ulTickStart) ? (ulTickEnd - ulTickStart) : ((0xFFFFFFFF - ulTickStart) + ulTickEnd + 1)); } //***************************************************************************** // // Close the Doxygen group. //! @} // //*****************************************************************************