Здравствуйте!
Поставил, скомпилировал, подредактировал проект примера, идущий в комплекте, под себя, все компилируется и работает. Пока что экспериментирую на кошках (встроенный в MPLAB симулятор), железо через неделю только будет. Но уже есть некоторые вопросы.
Я не знаю пока вызвано ли это некорректным симулированием, попробую проверить на железе.
Вопрос первый, по работе системного таймера.
Проблема: от прерывания до следующего прерывания проходит меньше машинных циклов (МЦ), чем задано. Было бы больше- я б слова не сказал, но меньше....
В качестве таймера TNKernel пользует Core timer ядра MIPS32. Этот таймер инкрементируется каждые два МЦ, то есть в bsp.c вижу логичную конструкцию (это я уже под свои 40МГЦ переделал, в оригинале было под 80):
#define CORE_TIMER_PERIOD 20000UL /* 1 ms @ 40 MHz */
ну и есть прерывание:
void Sys_Tmr_Int_Handler (void)
{
INTClearFlag(INT_CT); // clear the interrupt flag
UpdateCoreTimer(CORE_TIMER_PERIOD); // update the period
}
результат по симулятору: 39991 МЦ. Хотя согласно таймеру должно быть 40000.
Изменив величину инициализации таймера на
#define CORE_TIMER_PERIOD (20000L + 5) /* 1 ms @ 40 MHz */
получил ровно 40000 МЦ, причем никакой погрешности не набегает при любом количестве прерываний.
То же самое с выдержками больше чем 1мс, скажем 1 секунда:
#define CORE_TIMER_PERIOD (20000000UL + 5) /* 1 s @ 40 MHz */
получаю ровно 40 миллионов МЦ. То есть ошибка аддитивная. Но почему таймер считает быстрее чем машинные циклы идут- не понимаю. Или лыжи не едут (симулятор врет) или реализация функции UpdateCoreTimer() хромает.
Вопрос второй.
Ну добился я что системный таймер в TNKernel идет как мне хочется (то есть с периодом 1мс), а не быстрее указанного. дальше перешел к проверке пауз в задачах. такая простенькая задача, чтобы светодиод поморгал
#define LED_PERIOD 500 //ms
//task
void TN_TASK LED_CPU_Task (void *par)
{
for (;;)
{
LED_CPU_ON;
tn_task_sleep(LED_PERIOD/2);
LED_CPU_OFF;
tn_task_sleep(LED_PERIOD/2);
}
}
Результат удивил: на строку включения светодиода (LED_CPU_ON) я должен попадать каждые 500мс или реже, если другие задачи работают. Реально время меньше требуемого примерно на 20 МЦ. Почему меньше?????????? Причем дельта явно меньше одного системного тика.
Я хочу быть уверенным, что прошел период не меньше указанного мной, это очень часто используется при выпиливании времянок: больше пожалуйста, а меньше нельзя.
Вероятно, разработчики считают таймаут от текущего системного тика который уже начался, тогда это понятно и нужно просто увеличивать нужные юзерские зазоры на единицу при вызове tn_task_sleep() (проблема юзера, а не кернела), но это где-то отображено?
В документации вижу обратное:
tn_task_sleep() : Функция переводит текущую задачу в ожидание на время не меньше чем timeout системных тиков.
Я согласен с этим и это нормально, но реально вижу "меньше чем timeout системных тиков." На малую долю этого тика, но ведь меньше.... И кто мне гарантирует что эта доля не увеличится до почти целого тика при каких-то условиях.
Оговорюсь, это все на основе симулятора, попробую позже на железе посмотреть.