-
Notifications
You must be signed in to change notification settings - Fork 1
/
EERTOS.c
204 lines (161 loc) · 5.96 KB
/
EERTOS.c
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
/***********************************************************
ЯДОРО RTOS
Автор DI-HALT http://easyelectronics.ru/
Настройка:
файл - EERTOS.h
Настроить один из таймеров на прерывание каждые N-микросекунд,
Инициализация
InitRTOS(); // Инициализируем ядро
SetTask(Task); // Запуск фоновой задачи
RunRTOS(); // Старт ядра.
//Работа
SetTimerTask(Task2,100); //Поставить задачу Task2 в очередь через 100 микросекунд или N - как таймер будет настроен
SetTask(Task); //Сразу поставить задачу в очередь
в функции main должен быть вызов фунции
TaskManager(); // Вызов диспетчера
как можно чаще. Этот вызов и есть выполнение программы
(помимо задач работающих по таймеру).
***********************************************************/
#include <stddef.h>
#include "EERTOS.h"
TPTR TimerRTOSFunc = NULL; //Функция вызываемая при каждом срабатывании таймера задач, должна быть как можно менее длительной
//RTOS Interrupt
ISR(RTOS_ISR) {
if (TimerRTOSFunc != NULL)
TimerRTOSFunc();
TimerService();
}
// Очереди задач, таймеров.
// Тип данных - указатель на функцию
volatile static TPTR TaskQueue[TaskQueueSize+1]; // очередь указателей
volatile static struct
{
TPTR GoToTask; // Указатель перехода
u16 Time; // Выдержка в мс
}
MainTimer[MainTimerQueueSize+1]; // Очередь таймеров
long unsigned int TiksCount; //счетчик тиков службы таймера
// RTOS Подготовка. Очистка очередей
inline void InitRTOS(void)
{
u08 index;
for(index=0;index!=TaskQueueSize+1;index++) // Во все позиции записываем Idle
{
TaskQueue[index] = Idle;
}
for(index=0;index!=MainTimerQueueSize+1;index++) // Обнуляем все таймеры.
{
MainTimer[index].GoToTask = Idle;
MainTimer[index].Time = 0;
}
TiksCount = 0;
}
//Пустая процедура - простой ядра.
inline void Idle(void)
{
}
// Функция установки задачи в очередь. Передаваемый параметр - указатель на функцию
void SetTask(TPTR TS)
{
u08 index = 0;
u08 nointerrupted = 0;
if ((TS == Idle) || (TS == NULL)) return;
if (STATUS_REG & (1<<Interrupt_Flag)) // Если прерывания разрешены, то запрещаем их.
{
Disable_Interrupt;
nointerrupted = 1; // И ставим флаг, что мы не в прерывании.
}
while(TaskQueue[index]!=Idle) // Прочесываем очередь задач на предмет свободной ячейки
{ // со значением Idle - конец очереди.
index++;
if (index == TaskQueueSize+1) // Если очередь переполнена то выходим не солоно хлебавши
{
if (nointerrupted) Enable_Interrupt; // Если мы не в прерывании, то разрешаем прерывания
return; // Раньше функция возвращала код ошибки - очередь переполнена. Пока убрал.
}
}
// Если нашли свободное место, то
TaskQueue[index] = TS; // Записываем в очередь задачу
if (nointerrupted) Enable_Interrupt; // И включаем прерывания если не в обработчике прерывания.
}
//Функция установки задачи по таймеру. Передаваемые параметры - указатель на функцию,
// Время выдержки в тиках системного таймера. Возвращет код ошибки.
void SetTimerTask(TPTR TS, u16 NewTime)
{
u08 index=0;
u08 nointerrupted = 0;
if (STATUS_REG & (1<<Interrupt_Flag)) // Проверка запрета прерывания, аналогично функции выше
{
Disable_Interrupt;
nointerrupted = 1;
}
for(index=0;index!=MainTimerQueueSize+1;++index) //Прочесываем очередь таймеров
{
if(MainTimer[index].GoToTask == TS) // Если уже есть запись с таким адресом
{
MainTimer[index].Time = NewTime; // Перезаписываем ей выдержку
if (nointerrupted) Enable_Interrupt; // Разрешаем прерывания если не были запрещены.
return; // Выходим. Раньше был код успешной операции. Пока убрал
}
}
for(index=0;index!=MainTimerQueueSize+1;++index) // Если не находим похожий таймер, то ищем любой пустой
{
if (MainTimer[index].GoToTask == Idle)
{
MainTimer[index].GoToTask = TS; // Заполняем поле перехода задачи
MainTimer[index].Time = NewTime; // И поле выдержки времени
if (nointerrupted) Enable_Interrupt; // Разрешаем прерывания
return; // Выход.
}
} // тут можно сделать return c кодом ошибки - нет свободных таймеров
}
/*=================================================================================
Диспетчер задач ОС. Выбирает из очереди задачи и отправляет на выполнение.
*/
inline void TaskManager(void)
{
u08 index=0;
TPTR GoToTask = Idle; // Инициализируем переменные
Disable_Interrupt; // Запрещаем прерывания!!!
GoToTask = TaskQueue[0]; // Хватаем первое значение из очереди
if (GoToTask==Idle) // Если там пусто
{
Enable_Interrupt; // Разрешаем прерывания
(Idle)(); // Переходим на обработку пустого цикла
}
else
{
for(index=0;index!=TaskQueueSize;index++) // В противном случае сдвигаем всю очередь
{
TaskQueue[index]=TaskQueue[index+1];
}
TaskQueue[TaskQueueSize]= Idle; // В последнюю запись пихаем затычку
Enable_Interrupt; // Разрешаем прерывания
(GoToTask)(); // Переходим к задаче
}
}
/*
Служба таймеров ядра. Должна вызываться из прерывания раз в 1 мс - это и есть минимальный период вызова задачи.
Хотя время можно варьировать в зависимости от задачи
To DO: Привести к возможности загружать произвольную очередь таймеров. Тогда можно будет создавать их целую прорву.
А также использовать эту функцию произвольным образом.
В этом случае не забыть добавить проверку прерывания.
*/
inline void TimerService(void)
{
u08 index;
TiksCount++; //Счетчик тиков службы таймера для всяких служебных нужд
for(index=0;index!=MainTimerQueueSize+1;index++) // Прочесываем очередь таймеров
{
if(MainTimer[index].GoToTask == Idle) continue; // Если нашли пустышку - щелкаем следующую итерацию
if(MainTimer[index].Time !=1) // Если таймер не выщелкал, то щелкаем еще раз.
{ // To Do: Вычислить по тактам, что лучше !=1 или !=0.
MainTimer[index].Time --; // Уменьшаем число в ячейке если не конец.
}
else
{
SetTask(MainTimer[index].GoToTask); // Дощелкали до нуля? Пихаем в очередь задачу
MainTimer[index].GoToTask = Idle; // А в ячейку пишем затычку
}
}
}