SCM-RTOS

SCM RTOS — жесткая реальность реальной оси.


В сообществе уже было несколько статей по SCM rtos, начиная с приделки к AVR студии и кончая межпроцессным взаимодействием, остался неосвещенным очень существенный вопрос — в чем же собственно ее реальтаймность и как это посмотреть. На нескольких примерах я попытаюсь это проиллюстрировать.
Во-первых про реальтаймность очень подробно написано в самом мануале на SCM — scmrtos.sourceforge.net/files/doc/ru/scmRTOS_v4.ru.pdf, еще например есть небольшая статья посвященная конкретно этому вопросу — chipenable.ru/index.php/rtos/item/61-nuzhna-li-vam-operatsionnaya-sistema-realnogo-vremeniss.html в общем вкратце разница между чисто кооперативной осрв и вытесняющей приоритетной, то что в вытесняющей после выхода из прерывания управление в течение определенного времени отдается самой приоритетной задаче, а в кооперативной управление возвращается той же задаче и она сама передает управление планировщику когда досчитается, соответственно досчитываться она может сколько угодно и такая реальтаймность в противоположность первой называется мягкой, а первая — жесткой.
Первый пример демонстрирует получение управления процессами при выходе из прерывания, а второй — запуск, остановку и сохранение контекста процессами. Примеры сделаны для ATMEGA8 (8 МГц) и проверены в протеусе.

Итак, в первом примере (в конфиге задач 3, тики и хуки отключены) три простые задачи меняют состояние вывода на противоположное при наступлении события _1_ev. Все три дожидаются одного события — _1_ev.wait(); и меняют состояние вывода когда дождутся, событие наступает в прерывании таймера T2 — _1_ev.signal_isr();, там же заодно меняется и состояние четвертого вывода. Передача управления процессам происходит по очереди в соответствии с приоритетом что и видно на осциллограмме(верхний — 1, второй — 2, третий — 3, нижний — таймер). Кстати тут можно приблизительно оценить и быстрость ос — время перехода от процесса к процессу такая же как в OSA — приблизительно 40 микросекунд.

#include <avr/io.h> 
#include <scmRTOS.h>

typedef OS::process<OS::pr0, 80> TProc1;
typedef OS::process<OS::pr1, 80> TProc2;
typedef OS::process<OS::pr2, 80> TProc3;
OS::TEventFlag _1_ev;
TProc1 Proc1;
TProc2 Proc2;
TProc3 Proc3;


int main()
{
    DDRD = 0xFF;
    TCCR2=0x03;           
    TIMSK |=  (1 << TOIE2);
    OS::run();
}


namespace OS 
{
    template<> OS_PROCESS void TProc1::exec()
    {
        for(;;)
        {
		_1_ev.wait();
		if(PORTD & 0b00000001)
			PORTD = PORTD & 0b11111110;
			else PORTD=PORTD | 0b00000001;
			 
                           
        }
   }
}

namespace OS 
{
   template<> OS_PROCESS void TProc2::exec()
   {
       for(;;)
       {
	       _1_ev.wait();
		if(PORTD & 0b00000010)
			PORTD = PORTD & 0b11111101;
			else PORTD=PORTD | 0b00000010;


       }
   }
}
namespace OS 
{
   template<> OS_PROCESS void TProc3::exec()
   {
       for(;;)
       {

		_1_ev.wait();
		if(PORTD & 0b00000100)
			PORTD = PORTD & 0b11111011;
			else PORTD=PORTD | 0b00000100;

       }
   }
}
OS_INTERRUPT void TIMER2_OVF_vect()
{
OS::TISRW ISRW;
TCCR2=0;
TCNT2 = 100;
		if(PORTD & 0b00001000)
			PORTD = PORTD & 0b11110111;
			else PORTD=PORTD | 0b00001000; 
_1_ev.signal_isr();
TCCR2=0x03;
}


Встает совершенно логичный вопрос а что делать, если надо передать управление после выхода из прерывания не самой приоритетной задаче, а какой-нибудь другой. В третьей версии SCM для этого ничего не было, в четвертой появилась возможность процессы прекращать и запускать. За это отвечают функции terminate() и start(). В конфиге эта возможность включается установкой параметра, scmRTOS_PROCESS_RESTART_ENABLE в 1.
Во втором примере (в конфиге задач 2, включены систем тик и систаймер юзер хук), два простых процесса просто изменяют состояния выводов в зависимости от значения параметров. В первом процессе длительность импульса задается значением до которого производится счет, во втором таймером. В пользовательской части обработчика прерываний (юзер хуке) таймера T0 ( OS::system_timer_user_hook() ), первый процесс останавливается и потом практически сразу снова запускается из второго процесса к которому передается управление. Без выключения функцией Proc1.terminate(); первый процесс никогда не передает управления как самый приоритетный. Причем интересно прерывать его именно в процессе счета, чтобы выяснить сохраняется ли значение параметра (контекст) при его дальнейшем запуске( Proc1.start(); ) вторым процессом. Тут есть один тонкий момент, если в первом процессе до цикла задавать значение параметра ( в данном случае int schet_= 0; ) то все нормально, на осциллограмме видно что процесс начинается заново т. е. на выводе уровень высокий что соответствует значению параметра меньше 5000, а если конкретное значение не задавать (int schet_;) то он берет старое значение (то до которого досчитал в прошлый раз) и процесс счета продолжается с того места с которого прервался, т. е. не видно, что он на самом деле перезапустился (третья осциллограмма). А второй процесс (второй луч) сохраняет свой контекст (и значение параметра которое меняется от срабатывания к срабатыванию) так как не перезапускается, что тоже видно по осциллограмме. Если бы был перезапуск то был бы только один уровень, в данном конкретном случае 0 так как процесс все время бы начинался с schet = 5;.

#include <avr/io.h> 
#include <scmRTOS.h>

typedef OS::process<OS::pr0, 80> TProc1;
typedef OS::process<OS::pr1, 80> TProc2;

TProc1 Proc1;
TProc2 Proc2;

int main()
{
    DDRD = 0xFF;
    TCCR0=0x05;           
    TIMSK |=  (1 << TOIE0);
    OS::run(); 
}


namespace OS 
{
    template<> OS_PROCESS void TProc1::exec()
    {
	int schet_= 0;
        for(;;)
        {

		if(schet_ > 5000)
			{if(schet_ > 10000)schet_=0; 
				else {}schet_++;PORTD = PORTD & 0b11111110;
			}
			else {schet_++;PORTD=PORTD | 0b00000001;
			}

         }
   }
}

namespace OS 
{
   template<> OS_PROCESS void TProc2::exec()
   {	
   	char schet = 5;
       	for(;;)
       	{
		if(schet)
			{PORTD = PORTD & 0b11111101;schet=0;
			}
			else {PORTD=PORTD | 0b00000010;schet=5;
			      }

			Proc1.start();

       	}
   }
}



void OS::system_timer_user_hook()
{
			TCNT0 = 185;
			Proc1.terminate();
}



Теперь о реализации, при компилляции почему-то все время вылазят варнинги типа
… scmRTOS\Common/OS_Services.h:261:18: warning: ignoring packed attribute because of unpacked non-POD field 'OS::TMutex& OS::TMutexLocker::Mutex', разработчики уверяют, что это ни на что не влияет. И еще один момент, при просто включении таймера T0, даже если в конфиге не включены тики и хуки все равно система уходит на прерывание, чего нет при просто включении других таймеров. Возможно эти моменты относятся только к портам под AVR. Остается надеятся что в дальнейших релизах это будет устранено, мешать это конечно не мешает но и не способствует)).
P.S. Относительно таймера T0 — явление присутствует, но не во всех портах — спасибо ReAl-)
P.P.S.Так как народ наминусил, статья вылетела в персональный блог-), щас руки дошли перенес в коллективный (а пусть), но куда-то делись все комменты, попробую связаться с Ди Хальтом что бы попытался восстановить, а то восприятие не то…
  • -3
  • 09 октября 2012, 16:07
  • basil

Комментарии (29)

RSS свернуть / развернуть
И еще один момент, при просто включении таймера T0, даже если в конфиге не включены тики и хуки все равно система уходит на прерывание, чего нет при просто включении других таймеров. Возможно эти моменты относятся только к портам под AVR.

Перед тем как включать прерывание сбрасывай флаги прерывания.

Встает совершенно логичный вопрос а что делать, если надо передать управление после выхода из прерывания не самой приоритетной задаче, а какой-нибудь другой. В третьей версии SCM для этого ничего не было, в четвертой появилась возможность процессы прекращать и запускать.

Это не корректно. Суть РТОС в том, что самая приоритетная всегда получает управление первой.
В scmRTOS приоритеты динамически менять нельзя. Но если все-же это потребуется, то разработчики оставили на этот случай функции для изменения логики работы диспетчера. Сразу предупредив, что ими лучше не пользоваться а лучше правильно спроектировать систему.

то он берет старое значение (то до которого досчитал в прошлый раз) и процесс счета продолжается с того места с которого прервался, т. е. не видно, что он на самом деле перезапустился (третья осциллограмма).


Естественно, ты после сброса не инициализируешь параметры. Это не правильно.

Производить испытание в протеусе тоже глуповато.

Да и непонятно о чем статья.
0
  • avatar
  • a9d
  • 09 октября 2012, 16:49
Гы;_) Тож чет к такому выводу пришел! Типа надо проверить насколько окружность круглая=)
0
>>В scmRTOS приоритеты динамически менять нельзя. Но если все-же это потребуется, то разработчики оставили на этот случай функции для изменения логики работы диспетчера.
Что там насчёт динамических приоритетов? Не поясните?
0
Динамически приоритет менять нельзя. Но можно прямо передать управление нужному процессу.
0
ЭЭ… Каким образом?
Пример(ссылку) где можно посмотреть не дадите?
0
LockSystemTimer(), UnlockSystemTimer(), WakeUpProcess(), ForceWakeUpProcess, IsProcessSleeping(), IsProcessSuspended()… С помощью этих функций процессами можно рулить как угодно.

Это написано в документации.
0
Тогда понятно, спасибо.
0
Перед тем как включать прерывание сбрасывай флаги прерывания.
Прерывание не включается. Единственно с чем могу согласиться недостаточно ясно написал — речь идет о реализации самого порта безотносительно к приведенным примерам.
Это не корректно. Суть РТОС в том, что самая приоритетная всегда получает управление первой.
В scmRTOS приоритеты динамически менять нельзя. Но если все-же это потребуется, то разработчики оставили на этот случай функции для изменения логики работы диспетчера. Сразу предупредив, что ими лучше не пользоваться а лучше правильно спроектировать систему.
Прерываний может быть несколько и они могут готовить данные каждое для своей задачи, естественно будет быстрее если после соответствующего прерывания управление будет получать соответствующий процесс. Вообще-то это разработчики и придумали перезапуск процесса и рекомендовали его применение см. мануал.
Естественно, ты после сброса не инициализируешь параметры. Это не правильно.
После сброса параметры инициализируются см. статью.
Производить испытание в протеусе тоже глуповато.
Я думаю что создатели протеуса достаточно квалифицированные люди. И никто не говорит о том что он заменяет реальность.
0
Если прерывание не включено, то ты никаким образом туда попасть не можешь. Так, что сбрасывай флаг а уже потом включай.

Прерываний может быть несколько и они могут готовить данные каждое для своей задачи, естественно будет быстрее если после соответствующего прерывания управление будет получать соответствующий процесс. Вообще-то это разработчики и придумали перезапуск процесса и рекомендовали его применение см. мануал.

Прерываний может быть сколько угодно. Но в РТОС системе всегда наиболее важный процесс получает управление первым. Нужно правильно проектировать систему или выбрать РТОС в которой можно динамически менять приоритет.

Вообще-то это разработчики и придумали перезапуск процесса и рекомендовали его применение см. мануал.
Ничего подобного. Это просто перезапуск процесса. Собственно это написано в документации.

Тут есть один тонкий момент, если в первом процессе до цикла задавать значение параметра ( в данном случае int schet_= 0; ) то все нормально, на осциллограмме видно что процесс начинается заново т. е. на выводе уровень высокий что соответствует значению параметра меньше 5000, а если конкретное значение не задавать (int schet_;) то он берет старое значение (то до которого досчитал в прошлый раз) и процесс счета продолжается с того места с которого прервался,

Тыж сам написал, что не инициализируешь данные.

Я думаю что создатели протеуса достаточно квалифицированные люди. И никто не говорит о том что он заменяет реальность.

В протеусе очень много глюком. Многие прерывания работают неправильно либо вообще не работают.
0
Если прерывание не включено, то ты никаким образом туда попасть не можешь.
Вот именно, видимо ос его сама всегда и включает оно может не использоватся если не включен делитель в TCCR0B но в TIMSK0 галка видимо ставится всегда.
Но в РТОС системе всегда наиболее важный процесс получает управление первым.
Безусловно, вот и если остановить самый приоритетный то выполнятся будет следующий, потому что самым приоритетным будет уже он.
Тыж сам написал, что не инициализируешь данные.
))) Вот и написано что если инициализировать то все будет нормально))
В протеусе очень много глюком. Многие прерывания работают неправильно либо вообще не работают.

Да, поэтому железо это критерий истины)
0
Вот именно, видимо ос его сама всегда и включает оно может не использоватся если не включен делитель в TCCR0B но в TIMSK0 галка видимо ставится всегда.

ОС сама включает системный таймер. Пользователю нужно его настроить и сбросить флаг. И вообще всегда нужно сбрасывать флаг прерывания перед включением прерывания.

))) Вот и написано что если инициализировать то все будет нормально))

Кхкх.

Вывод статьи.

1) Очередность выполнения задач зависит от приоритета.
2) Если инициализировать переменные, то они будут инициализированы.
3) Если сбросить задачу, то она сбросится.

Кэп не дремлет.
0
В свете новой информации

4) Если задачу выключить, то она выключится. Т.е. не будет работать.
0
))))))))))))))
слов нет…
0
5)Чтобы получить представление о чем статья ее лучше прочесть.
0
я ее прочел. Даже два раза.

Жду статью на темы:
— Взаимосвязь между логическим состоянием ножки reset и работой микроконтроллера.
— scmRTOS. Выключаем низко приоритетную задачу.
— scmRTOS. Что будет если выключить все задачи.
0
Если нечего сказать по делу то можешь уже успокоится.
0
ты и с жестким реалтаймом ошибся. Это я промолчал.

В жестком реалтайме при не соблюдении заданного уровня сервиса вся система крашиться. В scmRTOS мягкий реалтайм. А в кооперативке реалтайма нет, но можно построить реалтайм систему.
+1
>>вся система крашиться
В чём «краш» выражается? Проц выгорает что ли?
0
Синий экран смерти не видел? Одна системная ошибка и виндовс выключается. Тоже самое и в жестком реалтайме происходит.
0
>>Синий экран смерти не видел?
Видел, но при чём тут windows со своими экранами?
>> Тоже самое и в жестком реалтайме происходит
У вас какое-то новое определение real-time сформировалось?
0
??? В жестком реалтайме не соблюдение заданного уровня сервиса считается системной ошибкой. Реакция будет аналогичной.
0
А может систему заново перезапустить (автоматически) будет правильнее?
0
>>разработчики и придумали перезапуск процесса и рекомендовали его применение
Только к приоритетам перезапуск процесса отношения не имеет.
0
Перезапуск процесса состоит из двух частей, необязательно сразу после остановки процесса его запускать, пока процесс остановлен самым приоритетным будет другой процесс именно это в частности и иллюстрируют приведенные примеры. Собственно пример с terminate() и start().
0
>>чего нет при просто включении других таймеров.
А какой компилятор вы использовали? И прерывание просто так не может возникнуть — его разрешить надо ведь…
0
AVR Studio 4.19 gcc, сейчас хотел перепроверить но не нашел где это у меня, суть дела следующая: если специально не включаешь прерывание таймера 0 но просто его запускаешь на осциллограмме видны паузы скважность очень близка к единице импульсы длинные и заметить это трудно. Видимо в системе это прерывание всегда включено, но чтобы оно заработало надо включить сам таймер и разрешить тики с хуками, но как минимум включить таймер. Ну и соответственно тики работать не будут но на прерывание она уходить будет.
0
Естественно речь идет не о ситуации вообще, а о конкретно SCM оси. И на осциллограмме какого-нибудь процесса к примеру вообще одного процесса, видно что он периодически прерывается что пропадает при выключении T0. Попробую все-таки найти, где-то что-то такое у меня было.
0
>>Видимо в системе это прерывание всегда включено
Прерывание таймера 0 включается так
TIMER0_IE_REG |= (1 << TOIE0);

Если строчку убрать, то прерывание не возникнет.
чтобы оно заработало надо включить сам таймер и разрешить тики с хуками, но как минимум включить таймер.
Смысла нет включать таймер, если тики и хук запрещены.
ЗЫ как-то странно смотрится (scmRTOS_SYSTEM_TICKS_ENABLE равен 0).
Логично было бы так:

OS_INTERRUPT void SYSTEM_TIMER_VECTOR(void)
{
#if (scmRTOS_SYSTEM_TICKS_ENABLE!=0)
    scmRTOS_ISRW_TYPE ISR;
    Kernel.system_timer();
#endif
// и так далее
0
Смысла нет включать таймер, если тики и хук запрещены.
ЗЫ как-то странно смотрится (scmRTOS_SYSTEM_TICKS_ENABLE равен 0).
Логично было бы так:…

basil,

аффтар, если статья про жесткость/не-жесткость реалтаймовой оси, надо бы дать понятие определяющего критерия, и в статье рассказывать о реалтаймовости по отношению к внешним событиям а не трещать на тему платформенной привязки.

Вообще если по теме — то дохера многл о чем рассказывать: контексте — вне контекста, без запрещения или с запретом, с локами или без… а не мять сиськи без нужды, словоблудить рассуждать о кодинге без предложения принципов решения.
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.