1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
|
//*****************************************************************************
//
// scheduler.c - A simple task scheduler
//
// Copyright (c) 2010-2014 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 2.1.0.12573 of the Tiva Utility Library.
//
//*****************************************************************************
#include <stdbool.h>
#include <stdint.h>
#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 uint32_t g_ui32SchedulerTickCount;
//*****************************************************************************
//
//! 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_ui32SchedulerTickCount++;
}
//*****************************************************************************
//
//! Initializes the task scheduler.
//!
//! \param ui32TicksPerSecond 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(uint32_t ui32TicksPerSecond)
{
ASSERT(ui32TicksPerSecond);
//
// Configure SysTick for a periodic interrupt.
//
SysTickPeriodSet(SysCtlClockGet() / ui32TicksPerSecond);
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)
{
uint32_t ui32Loop;
tSchedulerTask *pi16Task;
//
// Loop through each task in the task table.
//
for(ui32Loop = 0; ui32Loop < g_ui32SchedulerNumTasks; ui32Loop++)
{
//
// Get a pointer to the task information.
//
pi16Task = &g_psSchedulerTable[ui32Loop];
//
// Is this task active and, if so, is it time to call it's function?
//
if(pi16Task->bActive &&
(SchedulerElapsedTicksGet(pi16Task->ui32LastCall) >=
pi16Task->ui32FrequencyTicks))
{
//
// Remember the timestamp at which we make the function call.
//
pi16Task->ui32LastCall = g_ui32SchedulerTickCount;
//
// Call the task function, passing the provided parameter.
//
pi16Task->pfnFunction(pi16Task->pvParam);
}
}
}
//*****************************************************************************
//
//! Enables a task and allows the scheduler to call it periodically.
//!
//! \param ui32Index 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(uint32_t ui32Index, bool bRunNow)
{
//
// Is the task index passed valid?
//
if(ui32Index < g_ui32SchedulerNumTasks)
{
//
// Yes - mark the task as active.
//
g_psSchedulerTable[ui32Index].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[ui32Index].ui32LastCall =
(g_ui32SchedulerTickCount -
g_psSchedulerTable[ui32Index].ui32FrequencyTicks);
}
else
{
//
// Cause the task to run after one full time period.
//
g_psSchedulerTable[ui32Index].ui32LastCall =
g_ui32SchedulerTickCount;
}
}
}
//*****************************************************************************
//
//! Disables a task and prevents the scheduler from calling it.
//!
//! \param ui32Index 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(uint32_t ui32Index)
{
//
// Is the task index passed valid?
//
if(ui32Index < g_ui32SchedulerNumTasks)
{
//
// Yes - mark the task as inactive.
//
g_psSchedulerTable[ui32Index].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.
//
//*****************************************************************************
uint32_t
SchedulerTickCountGet(void)
{
return(g_ui32SchedulerTickCount);
}
//*****************************************************************************
//
//! Returns the number of ticks elapsed since the provided tick count.
//!
//! \param ui32TickCount 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 ui32TickCount
//! 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 ui32TickCount. 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.
//
//*****************************************************************************
uint32_t
SchedulerElapsedTicksGet(uint32_t ui32TickCount)
{
//
// Determine the calculation based upon whether the global tick count has
// wrapped since the passed ui32TickCount.
//
return(SchedulerElapsedTicksCalc(ui32TickCount, g_ui32SchedulerTickCount));
}
//*****************************************************************************
//
//! Returns the number of ticks elapsed between two times.
//!
//! \param ui32TickStart is the system tick count for the start of the period.
//! \param ui32TickEnd 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.
//
//*****************************************************************************
uint32_t
SchedulerElapsedTicksCalc(uint32_t ui32TickStart, uint32_t ui32TickEnd)
{
return((ui32TickEnd > ui32TickStart) ? (ui32TickEnd - ui32TickStart) :
((0xFFFFFFFF - ui32TickStart) + ui32TickEnd + 1));
}
//*****************************************************************************
//
// Close the Doxygen group.
//! @}
//
//*****************************************************************************
|