Ruslan1 14 27 января, 2011 Опубликовано 27 января, 2011 · Жалоба Здравствуйте! Поставил, скомпилировал, подредактировал проект примера, идущий в комплекте, под себя, все компилируется и работает. Пока что экспериментирую на кошках (встроенный в 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 системных тиков." На малую долю этого тика, но ведь меньше.... И кто мне гарантирует что эта доля не увеличится до почти целого тика при каких-то условиях. Оговорюсь, это все на основе симулятора, попробую позже на железе посмотреть. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
yuri_t 0 27 января, 2011 Опубликовано 27 января, 2011 · Жалоба В любой RTOS время Sleep() будет генерироваться с точностью 0..-1 системный тик. Например, в TNKernel для ф-ции tn_task_sleep (100) с временем одного тика 1 ms, реальная задержка может колебаться от 99 ms (+ несколько микросекунд) до 100 ms (минус несколько микросекунд ). Это связано с тем, что "фазовое соотношение" между вызовом ф-ции Sleep() и прерыванием от системного таймера всегда случайно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Ruslan1 14 27 января, 2011 Опубликовано 27 января, 2011 · Жалоба В любой 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 и индивидуальные условия для каждой ожидающей задачи это вообще праздник какой-то! Я не припомню ничего подобного в юкосе. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
denim 0 27 января, 2011 Опубликовано 27 января, 2011 · Жалоба А я вот на 24FJ64 запускаю светодиодиками моргаю и как я раньше без этого жил Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Rusoil 0 14 февраля, 2011 Опубликовано 14 февраля, 2011 · Жалоба Тоже есть вопрос по TN. Будет ли происходить раскрутка стека при вызове tn_task_exit(0)? Я использую c++ обертку для мьютекса, там происходит автоосвобождение в деструкторе. Будет там автоматом деструктор выполняться как при выходе из функции? Или лучше так не делать? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
yuri_t 0 14 февраля, 2011 Опубликовано 14 февраля, 2011 · Жалоба Будет ли происходить раскрутка стека при вызове tn_task_exit(0)? Я использую c++ обертку для мьютекса, там происходит автоосвобождение в деструкторе. Будет там автоматом деструктор выполняться как при выходе из функции? Или лучше так не делать? Правильность работы "внутрених" механизмов С++ можно проверить в embedded по-настоящему только под отладчиком. Рекомендую использовать симулятор и debugger Keil ( для АРМ/Cortex). Кстати, наличие в С++ кода, написанного не напрямую (как в С) программистом, а добавляемого компилятором самостоятельно, является основной причиной, по которой я лично не использую С++ в embedded системах. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Rusoil 0 14 февраля, 2011 Опубликовано 14 февраля, 2011 · Жалоба Спасибо, учту. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dxp 32 15 февраля, 2011 Опубликовано 15 февраля, 2011 · Жалоба Будет там автоматом деструктор выполняться как при выходе из функции? Или лучше так не делать? А деструктор объекта вообще когда вызывается? Upd. Перечитал свой вопрос и понял, что нужно уточнение. У вас этот мутекс - это глобальный объект или локальный по отношению к этой фукнции? Кстати, наличие в С++ кода, написанного не напрямую (как в С) программистом, а добавляемого компилятором самостоятельно, является основной причиной, по которой я лично не использую С++ в embedded системах. Какой именно код тут имеется в виду? Конкретно? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
yuri_t 0 15 февраля, 2011 Опубликовано 15 февраля, 2011 · Жалоба Какой именно код тут имеется в виду? Конкретно? Например, default constructor/destructor в случае declaration типа MyClass x; Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Rusoil 0 15 февраля, 2011 Опубликовано 15 февраля, 2011 · Жалоба Локальный для функций. Обявляется локальный объект, мютекс захватывается и дальше о нем забываем. Если есть десяток проверок после которых нужен выход из функции, то это сильно упрощает код. В иаре это работает. Но нужно помнить о специфике ртос. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dxp 32 15 февраля, 2011 Опубликовано 15 февраля, 2011 · Жалоба Например, 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. Где этот левый код? Кстати. Вы считаете, что использовать неинициализированные данные - это хорошо? Локальный для функций. Обявляется локальный объект, мютекс захватывается и дальше о нем забываем. Если есть десяток проверок после которых нужен выход из функции, то это сильно упрощает код. Я, простите, не очень понимаю. Мутекс (пусть в плюсовой обёртке) - это сущность от RTOS? Она является средством межзадачного взаимодействия? Если так, то как она может быть локальной? Точнее, как к ней получает доступ код из других задач? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Rusoil 0 15 февраля, 2011 Опубликовано 15 февраля, 2011 (изменено) · Жалоба Сам мьютекс конечно обявлен как static и является сущностью ртос. В конструктор даем указатель на мьютекс. Потом вызываем захват мьютекса. При выходе из функции все локальные объекты уничтожаются - автоматом вызывается деструктор. 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); }; } Из других задач получить доступ к мьютексу не является проблемой. Изменено 15 февраля, 2011 пользователем Rusoil Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dxp 32 16 февраля, 2011 Опубликовано 16 февраля, 2011 · Жалоба Rusoil Понятно. Ответ на ваш исходный вопрос: если функция tn_task_exit возвращает управление в вызывающую функцию, то деструктор будет вызван. Если нет, то не будет. Какое именно у tn_task_exit поведение, надо смотреть в документации. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться