|
|
  |
Вопросы по TNKernel, порт для PIC32 |
|
|
|
Jan 27 2011, 11:55
|
Гуру
     
Группа: Свой
Сообщений: 2 360
Регистрация: 6-03-06
Из: Кишинев
Пользователь №: 15 025

|
Здравствуйте!
Поставил, скомпилировал, подредактировал проект примера, идущий в комплекте, под себя, все компилируется и работает. Пока что экспериментирую на кошках (встроенный в 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 системных тиков." На малую долю этого тика, но ведь меньше.... И кто мне гарантирует что эта доля не увеличится до почти целого тика при каких-то условиях.
Оговорюсь, это все на основе симулятора, попробую позже на железе посмотреть.
|
|
|
|
|
Jan 27 2011, 17:08
|
Гуру
     
Группа: Свой
Сообщений: 2 360
Регистрация: 6-03-06
Из: Кишинев
Пользователь №: 15 025

|
Цитата(yuri_t @ Jan 27 2011, 18:33)  В любой RTOS время Sleep() будет генерироваться с точностью 0..-1 системный тик.
Например, в TNKernel для ф-ции tn_task_sleep (100) с временем одного тика 1 ms, реальная задержка может колебаться от 99 ms (+ несколько микросекунд) до 100 ms (минус несколько микросекунд ).
Это связано с тем, что "фазовое соотношение" между вызовом ф-ции Sleep() и прерыванием от системного таймера всегда случайно. Ясно, спасибо! Просто я ориентировался на рускоязычную документацию: "Функция переводит текущую задачу в ожидание на время не меньше чем timeout системных тиков.". А нужно было оригинал смотреть: "This function puts the currently running task to the sleep for at most timeout system ticks"  PS. Eventflags и индивидуальные условия для каждой ожидающей задачи это вообще праздник какой-то! Я не припомню ничего подобного в юкосе.
|
|
|
|
|
Feb 14 2011, 10:52
|
Участник

Группа: Участник
Сообщений: 47
Регистрация: 21-01-09
Пользователь №: 43 695

|
Тоже есть вопрос по TN.
Будет ли происходить раскрутка стека при вызове tn_task_exit(0)?
Я использую c++ обертку для мьютекса, там происходит автоосвобождение в деструкторе. Будет там автоматом деструктор выполняться как при выходе из функции? Или лучше так не делать?
|
|
|
|
|
Feb 14 2011, 17:55
|
Частый гость
 
Группа: Свой
Сообщений: 163
Регистрация: 24-08-05
Пользователь №: 7 937

|
Цитата(Rusoil @ Feb 14 2011, 14:52)  Будет ли происходить раскрутка стека при вызове tn_task_exit(0)?
Я использую c++ обертку для мьютекса, там происходит автоосвобождение в деструкторе. Будет там автоматом деструктор выполняться как при выходе из функции? Или лучше так не делать? Правильность работы "внутрених" механизмов С++ можно проверить в embedded по-настоящему только под отладчиком. Рекомендую использовать симулятор и debugger Keil ( для АРМ/Cortex). Кстати, наличие в С++ кода, написанного не напрямую (как в С) программистом, а добавляемого компилятором самостоятельно, является основной причиной, по которой я лично не использую С++ в embedded системах.
|
|
|
|
|
Feb 14 2011, 20:23
|
Участник

Группа: Участник
Сообщений: 47
Регистрация: 21-01-09
Пользователь №: 43 695

|
Спасибо, учту.
|
|
|
|
|
Feb 15 2011, 04:18
|

Adept
     
Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343

|
Цитата(Rusoil @ Feb 14 2011, 16:52)  Будет там автоматом деструктор выполняться как при выходе из функции? Или лучше так не делать? А деструктор объекта вообще когда вызывается? Upd. Перечитал свой вопрос и понял, что нужно уточнение. У вас этот мутекс - это глобальный объект или локальный по отношению к этой фукнции? Цитата(yuri_t @ Feb 14 2011, 23:55)  Кстати, наличие в С++ кода, написанного не напрямую (как в С) программистом, а добавляемого компилятором самостоятельно, является основной причиной, по которой я лично не использую С++ в embedded системах. Какой именно код тут имеется в виду? Конкретно?
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
Feb 15 2011, 08:43
|
Частый гость
 
Группа: Свой
Сообщений: 163
Регистрация: 24-08-05
Пользователь №: 7 937

|
Цитата(dxp @ Feb 15 2011, 08:18)  Какой именно код тут имеется в виду? Конкретно? Например, default constructor/destructor в случае declaration типа MyClass x;
|
|
|
|
|
Feb 15 2011, 09:07
|
Участник

Группа: Участник
Сообщений: 47
Регистрация: 21-01-09
Пользователь №: 43 695

|
Локальный для функций.
Обявляется локальный объект, мютекс захватывается и дальше о нем забываем. Если есть десяток проверок после которых нужен выход из функции, то это сильно упрощает код.
В иаре это работает. Но нужно помнить о специфике ртос.
|
|
|
|
|
Feb 15 2011, 09:21
|

Adept
     
Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343

|
Цитата(yuri_t @ Feb 15 2011, 14:43)  Например, default constructor/destructor в случае declaration типа MyClass x; Код class TSlon { public: int get_a() { return a; }
private: int a; };
int main() { TSlon Slon; return Slon.get_a(); } Код int main() main: { TSlon Slon; return Slon.get_a(); 0C43 MOV.W #0x0, R12 3041 RET } Это для MSP430. Где этот левый код? Кстати. Вы считаете, что использовать неинициализированные данные - это хорошо? Цитата(Rusoil @ Feb 15 2011, 15:07)  Локальный для функций.
Обявляется локальный объект, мютекс захватывается и дальше о нем забываем. Если есть десяток проверок после которых нужен выход из функции, то это сильно упрощает код. Я, простите, не очень понимаю. Мутекс (пусть в плюсовой обёртке) - это сущность от RTOS? Она является средством межзадачного взаимодействия? Если так, то как она может быть локальной? Точнее, как к ней получает доступ код из других задач?
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
Feb 15 2011, 10:39
|
Участник

Группа: Участник
Сообщений: 47
Регистрация: 21-01-09
Пользователь №: 43 695

|
Сам мьютекс конечно обявлен как static и является сущностью ртос. В конструктор даем указатель на мьютекс. Потом вызываем захват мьютекса. При выходе из функции все локальные объекты уничтожаются - автоматом вызывается деструктор. CODE AUTOMUTEX::AUTOMUTEX(void * const _mutex) : m_isMutexLock(-1), m_mutex(_mutex) {}
sint32_t AUTOMUTEX::Lock() { if (m_isMutexLock != TERR_NO_ERR) { m_isMutexLock = tn_mutex_lock_polling((TN_MUTEX *)m_mutex); };
return m_isMutexLock; }
AUTOMUTEX::~AUTOMUTEX() { if (m_isMutexLock == TERR_NO_ERR) { tn_mutex_unlock((TN_MUTEX *)m_mutex); }; }
Из других задач получить доступ к мьютексу не является проблемой.
Сообщение отредактировал Rusoil - Feb 15 2011, 10:43
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|