ОСРВ OSA первоначальное знакомство

Разведение ОС в домашних условиях


Во-первых по OSA есть хороший учебник на самом же сайте осы www.pic24.ru/doku.php/osa/ref/download/intro и отличный chm дается прямо с ней, во-вторых на сайте навалом хороших примеров. Приводимые простые примеры только дополняют примеры автора осы. Это чисто практический опыт первоначального знакомства, вообще же это дело серьезное и требует внимания и серьезного отношения. Пятьсот раз я был уверен что это глюк операционной системы и в конечном итоге оказывалось что я всегда ошибался.
Ну сразу в настройках AVR студии убираем оптимизацию, а то вообще работать не будет ничего, потом включаем в проект студии путь к файлам осы например C:/osa и путь к файлам проекта(еще раз никаких русских имен в путях!), туда же (в папку проекта ) помещаем конфиг осы — OSAcfg.h, который создается при помощи конфигурационной утилиты OSAcfg_Tool которая берется тоже с сайта осы. Еще небольшое замечание — корректное включение файла osa.c в проект из контекстного меню в левом окне проекта, в текст программы инклудится только osa.h см. комменты.

Так, ну самое простое — просто две задачи одна пихает в PORTB 1 вторая 0.Все примеры проверялись на 8 АТМЕГЕ с фузами на 8 МГц и в протеусе — эмуляция вполне адекватная.
#include <avr/io.h>
#include "C:/osa/osa.c"
#include "C:/osa/osa.h"
#include "OSAcfg.h"
void power (void);
void power1 (void);
int main(void)
{
DDRB = 0xFF;
OS_Init();
OS_Task_Create(3, power);
OS_Task_Create(3, power1);
OS_Run();
}
void power (void)
{
while (1)
{
PORTB=1;
OS_Yield();
}
}
void power1 (void)
{
while (1)
{
PORTB=0;	
OS_Yield();
}
}
/* v konfige  ustanovl --winavr; --zadach - 2; 
-- uroven prioriteta norm; v AVR studio optimiz — otkl.*/

В конце файла в коменте — что ставим в конфигурационной утилите. Собираем, прошиваем, запускаем — работает.
Приятно видеть скорость просто ломовая — меандр с длиной импульса около 50 мкс, ну понятно если в задачи чего-нибудь напихать будет медленнее. Так, чего можно еще интересного сделать. Ну вот можно попробовать осуществлять переключение порта выводом в одной задаче значения посланного в простом сообщении из другой задачи:

#include <avr/io.h>
#include "C:/osa/osa.c"
#include "C:/osa/osa.h"
#include "OSAcfg.h"
void power (void);
void power1 (void);
OST_SMSG  port;

int main(void)
{
DDRB = 0xFF;
OS_Init();
OS_Task_Create(3, power);
OS_Task_Create(3, power1);
OS_Run();

}
void power (void)
{
static unsigned char vyvod1 = 1;
while (1)
{
OS_Smsg_Create(port);OS_Smsg_Send(port, (OST_SMSG)vyvod1);
PORTB = 2;								
OS_Yield();
}
}
void power1 (void)
{
OST_SMSG mess1;

while (1)
{
OS_Smsg_Wait(port, mess1);
PORTB = mess1;
OS_Yield();
}
}
/* v konfige  ustanovl --winavr; --zadach - 2;
 -- uroven prioriteta norm; v AVR studio optimiz — otkl.*/

сообщение у нас носит название port, передающееся значение в первой задаче носит название vyvod1, во второй задаче то что передалось сообщением port из первой задачи носит название mess1. А интересное заключается в форме выходного импульса который у нас совсем нисколько не меандр, а наоборот, длительность на первом бите порта в три раза превосходит время когда на первом бите 1. Помню сам я вполне удивился потому, что мне казалось что вообще-то должен быть меандр. Но при ближайшем рассмотрении выяснилось, что сервис OS_Smsg_Wait(…, …); ведет себя в данном случае аналогично OS_Yield(); то есть он просто передает управление OS_Run(); а уже в следующий раз когда до него доходит очередь, управление передается на следующий за ним оператор, то есть одно срабатывание он пропускает, отсюда и такая скважность — 4. Все то же самое верно если мы к примеру будем пользоваться бинарными семафорами — тут разница одна, сейчас в конфигурационной утилите надо поставить в области Binary semaphores количество -1 и дать семафору название (набрали и enter), в данном случае front_.

#include <avr/io.h>
#include "C:/osa/osa.c"
#include "C:/osa/osa.h"
#include "OSAcfg.h"
void power (void);
void power1 (void);

int main(void)
{
DDRB = 0xFF;
OS_Init();
OS_Task_Create(3, power);
OS_Task_Create(3, power1);
OS_Run();

}
void power (void)
{


while (1)
{
OS_Bsem_Set(front_);
PORTB = 2;
OS_Yield();
}
}
void power1 (void)
{

while (1)
{
OS_Bsem_Wait(front_);
PORTB = 1;
OS_Yield();
}
}
/* v konfige  ustanovl --winavr; --zadach - 2;
 -- uroven prioriteta norm; --Binary semaphores -1,
 nazvanie front_; --v AVR studio optimiz – otkl.*/

Так добрались потихоньку до таймеров. Таймеры задач отличаются от статических в основном только тем что работают только внутри задачи т. е. обратится к ним из другой задачи нельзя. Генератор пачек импульсов на таймере задач:

#include <avr/io.h>
#include <avr/interrupt.h>
#include "C:/osa/osa.c"
#include "C:/osa/osa.h"
#include "OSAcfg.h"

void power1 (void);

ISR(SIG_OVERFLOW0)
{
OS_Timer ();
}

int main(void)
{
DDRB = 0xFF;
TIMSK = 1 <<  TOIE0  ;
sei();
OS_Init();
OS_Task_Create(3, power1);
OS_Run();
}

void power1 (void)
{
TCCR0=1;
OS_Ttimer_Run (250);
while (1)
{
if (OS_Ttimer_Check ()) {OS_Ttimer_Run (250) ;
			 } 
	else asm("nop"::) ;
TCCR0=0;
if (-OS_Ttimer_Get () > 100) {if (PORTB==1) PORTB=0;
                                 else {PORTB=1;}
			      }
	else asm("nop"::);
TCCR0=1;
OS_Yield();
}
}
/* v konfige  ustanovl --winavr; --zadach - 1;
 -- uroven prioriteta norm; -- Task timers  – enable , type char ;
--v AVR studio optimiz – otkl.*/

Тут создается задача, и в ней запускается таймер который перезапускается по установке флага таймаута, сервис OS_Ttimer_Get () дает значение таймера оставшееся до таймаута. Чем значение сравниваемое с выдаваемым сервисом больше, тем пачка импульсов короче. Тут все ясно тонкость только одна — хотя в учебнике это не указано, но сервис OS_Ttimer_Get () выдает отрицательное значение, разработчик советует использовать конструкцию (unsigned char)OS_Ttimer_Get () — так тоже пойдет или ставим минус.
Генератор качающейся частоты на статическом таймере:
#include <avr/io.h>
#include <avr/interrupt.h>
#include "C:/osa/osa.c"
#include "C:/osa/osa.h"
#include "OSAcfg.h"
void power1 (void);
void power (void);

ISR(SIG_OVERFLOW0)
{
OS_Timer ();
}

int main(void)
{
DDRB = 0xFF;
TIMSK = 1 <<  TOIE0  ;
sei();
OS_Init();
OS_Task_Create(3, power);
OS_Task_Create(3, power1);
OS_Run();
}

void power1 (void)
{
TCCR0=1;
static unsigned char t=20;
OS_Stimer_Run (st, 250) ;
while (1)
{
if ((OS_Stimer_Get(st) > t) && (OS_Stimer_Get(st) < (t+10)))
{OS_Stimer_Pause (st);t++;{if (t>220)t=20;
                            else asm("nop"::);
                          }
}        
    else asm("nop"::);
OS_Yield();
}
}

void power (void)
{
while (1)
{
if (OS_Stimer_Check (st))
{OS_Stimer_Break (st);OS_Stimer_Run (st, 250) ;if (PORTB==1) PORTB=0; 
                                                    else {PORTB=1;}
}
    else asm("nop"::);
OS_Yield();
}
}
/* v konfige  ustanovl --winavr; --zadach - 2;
 -- uroven prioriteta norm; -- Static timers  – 1 , type --system,
 v  pole ID name  -- st; --v AVR studio optimiz – otkl.*/
Тут мысль в том что таймер проверяется на соответствие условию в одной задаче и потом ставится на паузу, а в другой стирается и перезапускается, ну и еще осуществляется вывод. Ну и понятно условие в первой задаче по ходу ее выполнения модифицируется. Тут интересный момент как бы в процессе выполнения не проскочить (не просчитать ) условие постановки на паузу поэтому и коридор ((OS_Stimer_Get(st) > t) && (OS_Stimer_Get(st) < (t+10))). Понятно что примеры нарочитые и это все можно реализовать проще, но тут смысл чтобы попробовать как раз одеть штаны через голову и поиспользовать побольше сервисов.
  • +2
  • 13 июня 2012, 16:59
  • basil

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

RSS свернуть / развернуть
С оптимизацией чтоль в принципе не работает?
0
Для STM8 все с оптимизацией работает: we.easyelectronics.ru/os-rtos/znakomstvo-s-rtos-osa-na-stm8.html

Думаю, имеется в виду, что с без оптимизации можно в эмуляторе покрутить адекватно.
0
С оптимизацией тоже можно. Собственно с оптимизацией и нужно отлаживать.
0
So surprise, но да собраться еще в принципе соберется но работать не будет, при максимальном ужатии точно по крайней мере, при немаксимальном вроде все степени не проверял)) но вот правда чего ниудь видимо можно придумать с volatile, но это уже видимо для содержимого задач.
0
Ну сразу в настройках AVR студии убираем оптимизацию, а то вообще работать не будет ничего
Так не интересно.
Приятно видеть скорость просто ломовая — меандр с длиной импульса около 50 мкс, ну понятно если в задачи чего-нибудь напихать будет медленнее.
Ой ли? Это порядка 400 тактов на переключение задач. Я бы не сказал, что так уж мало.

Алсо статья сумбурная и непонятная. Больше похоже на впечатления от знакомста, чем на статью, так что место ей ИМХО в личном блоге.
0
  • avatar
  • Vga
  • 13 июня 2012, 18:29
Так не интересно.
Такова се ля ви)
Ой ли? Это порядка 400 тактов на переключение задач. Я бы не сказал, что так уж мало.
-348 для нормального приоритетного режима для 2-х задач, для неприоритетного для 2-х задач — 216
Алсо статья сумбурная и непонятная
в принцпе расчитано на тех кто кто уже чуть-чуть в курсе и будет уже что-то пробовать-все примеры рабочие, для первоначального знакомства конечно нужен учебник.
0
Такова се ля ви)
Больше попахивает косяками.
0
>>348 для нормального приоритетного режима для 2-х задач, для неприоритетного для 2-х задач — 216
Такое время нормально для вытесняющей ОСи: как раз примерно соответсвует времени на сохранение/востановление 32 регистров АВР. Интересно что там такое делается целых 50 мкс?
0
Под авр юзал OSA. С оптимизацией там все ОК. Зачем ее вырубать?
0
  • avatar
  • a9d
  • 13 июня 2012, 19:37
При максимальном сжатии если и собиралось то работало некорректно, пробовал все режимы. С немаксимальным сжатием посмотрел — вроде то же но точно не скажу.
0
И что там конкретно не работает? И что такое «максимальное сжатие»? В студии дофига настроек по оптимизации кода. Ими нужно равельно пользоваться. По ним даже апнот есть.
Насколько я помню там разработчик русский, я ему вопросы задавал. Он комментировал эту ситуацию?
0
В данном случае речь идет стандартном пути — о ниспадающем меню optimizatom на вкладке projekt->configuration options->general, если выбрать например максимальное сжатие — которое в студии по умолчанию — 0s то при компилляции вылазит куча варнингов и проект не работает. Видимо это можно устранить если порыться в самой осе но это совершенно другое дело.
Насколько я помню там разработчик русский, я ему вопросы задавал. Он комментировал эту ситуацию?
-разработчик осы? я с ним связывался но по другому поводу — по поводу сервисов таймеров. Вероятно и тут есть смысл его поспрашивать.
0
Там кроме 0s нужно ставить и другие опции. Они много чего определяют, не только размер.

Одни словом OSA с оптимизацией я использовал и все там работало. Да и не пойму с чего это она не должна работать. Хотя может автор ее обновил и забыл где-то прописать volatile.
0
Добрый день!

Я автор OSA, проблему с оптимизацией подтверждаю.

Как раз неделю назад получил подобный вопрос по мейлу с прикрепленные примером. Я на эту проблему уже натыкался раньше, но тогда ее решил, как оказалось, не полностью. К сожалению, эта проблема связана с некорректной работой оптимизатора WinAVR начиная с версии 20081205, и обойти ее средствами OSA крайне сложно. Здесь я ее описал с примером без OSA: www.pic24.ru/doku.php/osa/articles/winavr_bug

Одно время решение было найдено (та часть стека, которая могла попортиться, сохранялась вместе с контекстом задачи), однако уже неделю ковыряюсь с присланным мне кодом и вижу, что проблема намного глубже. Для ее обхода сейчас дописал кучу ассемблерного кода для управления стеком, но решение, на мой взгляд, слишком сложное: во-первых, громоздкое; во-вторых, значительно снижает скорость работы; в-третьих, это все равно костыль. Поэтому скорее всего придется откатиться на старую версию OSA, не поддерживающую оптимизацию.

С уважением, Виктор.
+1
Без оптимизации эта система практически не применима, особенно на маленьких контроллерах, о которых речь. Там где не помещается вытесняющая ОС, с успехом работает подход, используемый в Protothreads. Там поведение автоматических переменных полностью определено и не зависит от оптимизации кода.
+1
Дело не в авто-переменных. Вы текст по ссылке читали?
Согласен, что без оптимизации хуже, но с ней в данном случае работать не получится.
0
А зачем изобретать велосипед? Есть куча кооперативных ОС, почему бы не посмотреть ответ у них?

Также уже писали, «микроконтроллеры с малым объемом памяти» и «без оптимизации» это взаимоисключающие параграфы.
0
Ни одна кооперативка не будет работать с WinAVR > 20071221, увы
0
Откуда такая уверенность?
Пробежался по кооперативкам. Там о таком баге ни слова.
0
Значит они еще просто не напоролись. Баг не в ОС, а в компиляторе. Вы описание ошибки по ссылке выше читали? Понимаю, что многа букаф, но там рассмотрен пример вообще без ОС.
0
Нет, баг-таки именно в ОС. Вы про memory barrier слышали?
0
Не совсем понял, причем тут барьеры. Поясните, плз.
0
Барьер тут при том, что после него гарантированно не будут использованы никакие промежуточные значения полученные до него. Так-же через барьер не «перетекают» никакие перестановки кода, которые компилятор может выполнять при оптимизации. А статические и глобальные переменные после барьера будут точно записаны в память.
0
Разве в WinAVR этот механизм есть? Это действительно могло бы быть решением.
0
compiler.h
0
/**
* \def barrier
* \brief Memory barrier
*/
#ifdef __GNUC__
# define barrier() asm volatile("" ::: «memory»)
#else
# define barrier() asm ("")
#endif
0
Облом. Ничего не меняется. Добавил barrier в программу — все равно проблема не исчезла.
0
На всякий случай вставь asm volatile("" ::: «memory»).

Может у тебя каким-то макаром использовалась asm ("").
0
Прямым текстом вставлял.
0
Есть.
asm volatile ("" : : : "memory");

Это чисто програмный барьер. Универсально для всех компиляторов семейства GCC. Есть еще полный барьер
__sync_synchronize ();
, он еще генерирует специальную инструкцию, препятствующую перестановкам данных в процессоре, если таковая имеется. Для AVR это не актально и в указанном компиляторе его вроде и нет __sync_synchronize. А вообще при создании ОС такие вещи нужно иметь ввиду.
0
и «мемори» и __sync_synchronize дают тот же результат.

>>А вообще при создании ОС такие вещи нужно иметь ввиду.
Не спорю. Я и полагался изначально на атрибут return_twice.
0
Я прочитал полностью. О подобном во FreeRTOS да и вообще в какой либо другой ОС не слышал(volatile не в счет, но там были баги в сервисах а не в ОС).
0
FreeRTOS — вытесняющая, в ней эта ошибка проявляться не будет. Собственно, для решения этой проблемы я и добавил в OSA механизм распределения памяти, схожий с вытесняющей (у каждой задачи свой стек), но сами понимаете, что ОС, расходующая память как вытесняющая, а по скорости работающая как кооперативная — далеко не самое лучшее решение.
0
FreeRTOS это не только РТОС. Там три планировщика: кооперативный, ртос, смешанный.
0
Там механизм ручного переключения только добавлен. Стек все равно у каждой задачи свой.
0
Простите Вы случайно не в курсе, разработчики компиллятора знают о ситуации с кооперативками?
0
Это скорей всего проблема в данной конкретной ОС а не в компиляторе.
0
а как с этим обстоят дела в Atmel Studio 6? так же?
0
Кстати вроде есть еще и IAR, так что есть что у автора оси спросить) кстати в 4.19 студии не знаю не новая ли версия компилятора.
0
у меня в AVR Studio 4.18 — GCC 4.4.3, и в Atmel Studio 6 — GCC 4.6.2
0
Смотреть нужно на версию WinAVR, а не студии
0
там написано
AVR Toolchain 8-bit
Version: 3.4.0.663 — GCC 4.6.2
Вы имеете в виду это?
0
Примерно. WinAVR, AFAIK, уже не разрабатывается — оно перешло под крылышко атмел и теперь называется AVR Toolchain.
0
Хорошая реализация отделения контента статьи от рекламу (пробить пару пустыс строк). Спасибо за идею, надо будет свои статейки подрихтовать подобным образом.
0
#include «C:/osa/osa.c»
#include «C:/osa/osa.h»
Кстати, за захардкоденные пути к инклюдам руки надо отрывать. Для этого есть настройки компилятора (директории поиска инклюдов).
+1
  • avatar
  • Vga
  • 14 июня 2012, 11:09
Вообще в начале о включении путей в проект я написал, а тут-то это больше для наглядности, вообще тут можно обойтись #include «osa.c» и этого будет достаточно, и все будет работать).
0
Эээ, кстати, .c файлы не включают — это чревато. Включают только .h. Возможно потому оно у тебя и не работает с оптимизацией — она вытаскивает на свет скрытые баги.
0
А насчет оптимизации см выше)
0
Включать нужно только h-файл
0
Really sorry, если только хедер — орда ошибок, если только си
#include «osa.c»
то все корректно, ну понятно при вкюченных путях.
0
Не должно быть ошибок. Файл osa.c включен в проект?
0
Если впрямую включить оба файла (как выше в примерах) — все нормально. Если оставить один osa.c — тоже, если один osa.h — 100 ошибок, все это с безусловно включенными путями в проект.
0
Вы не поняли: файл osa. должен быть включен в проект, чтобы он бул в списке компилируемых файлов (в AvrStudio он должен присутствовать в списке Source в левом окне). То, как делаете Вы, приведет к проблемам, как только к программе будет подключен еще один модуль, использующий OSA
0
А-а дошло, спасибо все работает), то есть корректно надо было включать файлы из контекстного меню — грубо говоря, а не тупо задавать include directories из configuration options? Разница будет только в том что Вы сказали?
0
По моей ссылке как раз на эту тему написано.
0
Да.
Да.
0
0
Виктор, а требование отключать в ИАРе праметр оптимизации Cross Call с чем связано?
0
Извиняюсь, не сразу заметил вопрос.
Опция Cross Call позволяет компилятору повторяющиеся участки кода объединять в подпрограммы. И если компилятор решит таким образом оптимизировать часть кода планировщика OSA, которая использует данные из стека, может произойти путаница с восстановлением адресов возврата.
0
А разве это Cross Call, а не Common Subroutine Elimination?
0
В ИАРе нет такой опции. Там есть Common Subexpression Elimination, но она относится к повторному использованию промежуточных результатов вычислений.
0
Тьфу, Subexpression, да — спутал название. Но судя по названию — она как раз и должна выделять однотипные куски кода и выделять их в функции.
Хотя гайд от IAR'а на эту тему говорит только «eliminates redundant subexpression evaluation». Похоже и правда сохраняет результаты, а не выделяет в функции.
А вот Cross Call не нашел. Возможно потому, что смотрел доки на EWARM 6.30.
0
Они различаются не только в принципе работы, но и в эффекте оптимизации. Cross-call, в отличии от CSE, приводит не только к ужатию кода, но и к замедлению его работы (т.к. добавляются коллы и ретурны). CC не выделяет мелкие фрагменты, где объединение соизмеримо с объемом добавляемых call'ов, а CSE это делает. Кроме того, CC работает по всему исходнику (в случае IAR, кажись, в рамках одного си-файла), а CSE — только в пределах одной функции.
0
А можно выдержку из гайда IAR'а на тему Cross Call? У меня нету EWAVR, а в EWARM нету Cross Call.
0
Из CompilerReference.pdf:

Cross call
Common code sequences are extracted to local subroutines. This optimization, which is performed at optimization level High, can reduce code size, sometimes dramatically, on behalf of execution time and stack size. The resulting code might however be difficult to debug. This optimization cannot be disabled using the #pragma optimize directive.

Note: This option has no effect at optimization levels None, Low, and Medium, unless the option --do_cross_call is used.
0
Простите Виктор, Вы не связывались с разработчиками компилятора WinAVR?
0
WinAvr уже давно не разрабатывается. Он перерос в тулчейн.
Связываться с ними очень легко, они на электрониксе обитают. Если вопрос умный то ответят.
0
Нет, не связывался.
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.