Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Вопросы по scmRTOS
Форум разработчиков электроники ELECTRONIX.ru > Cистемный уровень проектирования > Операционные системы > scmRTOS
Страницы: 1, 2, 3
koluna
Здравствуйте!

scmRTOS v3 AVR/GCC.
Компилятор - WinAVR 20080610.
IDE - Code::Blocks 8.02.
Простую тестовую программу буду пробовать на ATmega88.

Приступил к изучению.
Читаю scmRTOS_v2.pdf, смотрю исходники примеров релиза.

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

Первые два вопроса - функции main примеров.
1. В примерах T0 - системный таймер. Почему инициализация и запуск системного таймера производится не средствами ОС (допустим, в Run), а пользователем ОС вручную?
2. Почему при использовании передачи управления на основе программного прерывания инициализация компаратора производится не средствами ОС, а пользователем ОС вручную?
3. Один тик системного таймера - одно его переполнение?
4. Рекомендуемое значение системного тика 1-10 мс. Т. е., мы должны настраивать системный таймер, на переполнение его в пределах этого времени?
5. Каковы будут дополнительные опции компилятора для моей связки ОС + компилятор + IDE?

Благодарю заранее!
dxp
Цитата(n_bogoyavlensky @ May 15 2009, 19:59) *
1. В примерах T0 - системный таймер. Почему инициализация и запуск системного таймера производится не средствами ОС (допустим, в Run), а пользователем ОС вручную?


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

Цитата(n_bogoyavlensky @ May 15 2009, 19:59) *
2. Почему при использовании передачи управления на основе программного прерывания инициализация компаратора производится не средствами ОС, а пользователем ОС вручную?


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

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

Цитата(n_bogoyavlensky @ May 15 2009, 19:59) *
3. Один тик системного таймера - одно его переполнение?


Это одно его прерывание. smile.gif А уж по переполнению оно сделано или по Compare Match - это особенности конкретного проекта. Все в руках юзера. smile.gif

Цитата(n_bogoyavlensky @ May 15 2009, 19:59) *
4. Рекомендуемое значение системного тика 1-10 мс. Т. е., мы должны настраивать системный таймер, на переполнение его в пределах этого времени?


Да, вы можете выбрать таймер, настроить его так, чтобы получить нужное вам значение системного тика. Оно может быть любым - какое сделаете, такое и будет.

Цитата(n_bogoyavlensky @ May 15 2009, 19:59) *
5. Каковы будут дополнительные опции компилятора для моей связки ОС + компилятор + IDE?

Не понял вопроса. ОС требует только чтобы для компилятора была включена поддержка С++ и (если надо) расширения языка. Если для целей проекта надо еще что-то, ну добавьте.

Если ответ не удовлетворил, уточните, что конкретно нужно. Либо дождемся ответа от автора порта. smile.gif
koluna
По вопросам 1 и 2 понятно.
Т. е., для того, чтобы ОС работала, выбираем, настраиваем, запускаем системный таймер в main.
Если используем конфигурацию ОС с передачей управления по программному прерыванию, то "настраиваем" соответствующее прерывание в main.

По вопросу 3.
Compare Match - для более точного подбора длительности тика?
А нужно ли это? smile.gif

Цитата(dxp @ May 15 2009, 17:42) *
Не понял вопроса. ОС требует только чтобы для компилятора была включена поддержка С++ и (если надо) расширения языка. Если для целей проекта надо еще что-то, ну добавьте.

Если ответ не удовлетворил, уточните, что конкретно нужно. Либо дождемся ответа от автора порта. smile.gif


Понятно smile.gif

6. При описании типа процесса размер двух стеков указывать или одного?

7. Как "прикинуть" размер требуемых стеков таким образом, чтобы взять его с запасом?
ReAl
Там есть makefile с ключами компилятора.
Если Code::Blocks позволяет создать проект "на всём готовом" (у NetBeans это называется С/С++ project from existing code - он тогда только подхватывает исходники в среду, а для компиляции в свой makefile подставляет вызов make с готовым makefile из проекта), то можно воспользоваться этим управляющим файлом. Если нет - то просто придётся посмотреть опции в makefile проекта и перенести их в IDE.
Собственно, там каких-то специфических опций именно для scmRTOS действительно и не нужно.

Цитата(n_bogoyavlensky @ May 15 2009, 17:23) *
По вопросу 3.
Compare Match - для более точного подбора длительности тика? А нужно ли это? smile.gif
А это вопрос вкусовой. Если речь именно о точности. А так - частота тактирования процессора и прескалер могут дать, к примеру, переполнение в 2,2мс, а хочется иметь тик в 1мс.
Или таймер 0 занят чем-то другим, а есть свободный канал сравнения на таймере 3.

Цитата(n_bogoyavlensky @ May 15 2009, 17:23) *
6. При описании типа процесса размер двух стеков указывать или одного?
7. Как "прикинуть" размер требуемых стеков таким образом, чтобы взять его с запасом?
Для avr-gcc, как оно видно в примерах, стек один.
Размер стека зависит от того, в какую глубину идут вызовы функций (в том числе сервисов ОС) и могут ли накладываться прерывания.
Сколь-нибудь серьёзного исследования я не проводил, но так навскидку - висящему в
Код
for (;;) {
    Sleep(500);
    TOGGLE(LED_R);
}
достаточно 45-50 байт стека (без наложения прерываний)
Вызывающему пару-тройку функций (без использования стека для локальных переменных), которые где-то там обращаются к Mutex да Event - уже нужно, скажем, 75-80. Для спокойствия можно начать где-то со 120 плюс ожидаемые размеры локальных переменных на стеке (обычно бывает когда есть массивчики или переменные, адрес которых передаётся куда-то).
sergeeff
У нас на форуме уже рассказывалось, как можно ввести контроль за объемом стека в scmRTOS. Методика простая. Выделяем поболее, смотрим за реальной работой процессора, анализируем сколько было использовано. Есть возможность - ужимаем, оставив еще немного про запас.
koluna
Вот и ещё вопросы подоспели smile.gif

8. Для чего функция процесса Exec() - статическая?
9. Почему функции WakeUpProcess() и ForceWakeUpProcess() следует использовать с осторожностью? В каких случаях?
10. Какую оптимизацию задавать при компиляции?

Цитата(sergeeff @ May 15 2009, 22:29) *
У нас на форуме уже рассказывалось, как можно ввести контроль за объемом стека в scmRTOS. Методика простая. Выделяем поболее, смотрим за реальной работой процессора, анализируем сколько было использовано. Есть возможность - ужимаем, оставив еще немного про запас.


Я читал smile.gif
Но мне как новичку пока сложновато это...

Цитата(ReAl @ May 15 2009, 18:47) *
TOGGLE(LED_R);


Что это?
ReAl
Цитата(n_bogoyavlensky @ May 15 2009, 21:37) *
10. Какую оптимизацию задавать при компиляции?
По вкусу. Я ставлю -Os и выбрасывание неиспользуемого кода/данных (-ffunction-sections -fdata-sections для компилятора и --gc-sections для линкера) а также --relax линкеру для замен длинных вызовов/переходов на короткие там, где это возможно и замен комбинаций call+ret на jump.
В общем, те же, что и для С-шных проектов.

Цитата(n_bogoyavlensky @ May 15 2009, 21:37) *
Что это?
Макрос инверсии вывода (в данном случае - выхода светодиода), развитие "классики от Аскольда Волкова"
http://electronix.ru/forum/index.php?showt...mp;#entry199555
Включено в примеры к порту scmRTOS для avr-gcc - файл pin_macros.h
dxp
Цитата(n_bogoyavlensky @ May 16 2009, 01:37) *
8. Для чего функция процесса Exec() - статическая?


А как иначе? Эта функция должна быть в единственном экземпляре всегда. Кроме того, хотя эта функция и объявлена, как функция процесса, на самом деле к ресурсам процесса она отношения не имеет и служит исключительно для нужд пользовательского кода. Поэтому делать ее нестатической - это передача ненужного this, а учитывая, что эта фукнция нормально не вызывается, то и this нее передать невозможно. Вот такие логические и технические посылы.

Цитата(n_bogoyavlensky @ May 16 2009, 01:37) *
9. Почему функции WakeUpProcess() и ForceWakeUpProcess() следует использовать с осторожностью? В каких случаях?

Потому, что их использование нарушает обычную логику работы программы. Например, какой-то процесс ожидает события, а тут его в другом месте выдергивают - это как бы нештатная ситуация. Поэтому тут надо действовать внимательно. К слову сказать, функции эти сделаны там скорее на всякий случай, лично я уже и не помню, когда их применял (и применял ли вообще). При правильно организованной программе необходимость в их использовании стемится к нулю. Это как с оператором goto.
koluna
Цитата(dxp @ May 16 2009, 09:54) *
А как иначе? Эта функция должна быть в единственном экземпляре всегда.


Каждый процесс - объект типа полученного с помощью шаблона process, наследник TBaseProcess.
Каждый процесс существует в единственном экземпляре.
Значит функция будет и так в единственном экземпляре...
Или я не понимаю что такое статическая функция sad.gif

Цитата
Потому, что их использование нарушает обычную логику работы программы. Например, какой-то процесс ожидает события, а тут его в другом месте выдергивают - это как бы нештатная ситуация. Поэтому тут надо действовать внимательно. К слову сказать, функции эти сделаны там скорее на всякий случай, лично я уже и не помню, когда их применял (и применял ли вообще). При правильно организованной программе необходимость в их использовании стемится к нулю. Это как с оператором goto.


А что может произойти? Система "упадёт"?
dxp
Цитата(n_bogoyavlensky @ May 16 2009, 16:35) *
Каждый процесс - объект типа полученного с помощью шаблона process, наследник TBaseProcess.
Каждый процесс существует в единственном экземпляре.
Значит функция будет и так в единственном экземпляре...
Или я не понимаю что такое статическая функция sad.gif


Никто не мешает завести больше одного объекта-процесса. Хотя это, конечно, неправильно. Я же ясно, вроде, пояснил, что:
  1. хотя эта функция и объявлена, как функция процесса, на самом деле к ресурсам процесса она отношения не имеет и служит исключительно для нужд пользовательского кода. Это логический довод.
  2. делать ее нестатической - это передача ненужного this, а учитывая, что эта фукнция нормально не вызывается, то и this нее передать невозможно. Это технический довод.
Как бы вы передали в нее указатель this? А без этого она может работать некорректно, и там можно получить очень хорошие грабли.




Цитата(n_bogoyavlensky @ May 16 2009, 16:35) *
А что может произойти? Система "упадёт"?


Можно получить неожиданное поведение. И удивляться. 
sergeeff
Раз пошел процесс обсуждения scmRTOS, хочу воспользоваться активным присутствием DXP на форуме.

Очень хотелось бы сделать так, чтобы первый объявленный процесс получал высший приоритет, следующий процесс - приоритет на 1 ниже и т.д.
Тогда, объявив в самой ОС число возможных процессов по максимуму всю ОС оформить в виде отдельной библиотеки и пользователям в своей организации раздать, чтобы они "грязными ногами" в ее "чистом теле" не натоптали. Сколько не думал, пока ничего не придумалось. Может есть какие соображения на сей счет?
ReAl
Цитата(dxp @ May 16 2009, 13:57) *
Как бы вы передали в нее указатель this?
Если постараться - можно.
В конструкторе TBaseProcess после Kernel.RegisterProcess(this), там, где формируется начальный стековый кадр, затолкать этот же this в такое место, чтобы после восстановления контекста он оказался в нужных регистрах. Только, насколько я понимаю, тип параметра exec у конструктора для этого должен быть другой - указатель на функцию-член.

Топикстартеру:

Таким же образом можно было бы передать в функцию процесса указатель на некую структуру/класс, с которыми процесс должен работать, но для этого надо конструктору добавить соответствующий аргумент. Но это имело бы смысл при одновремённом переводе Exec() в нестатическую - чтобы создавать два экземпляра процесса (с разными приоритетами, но это в конечном счёте не важно), работающие одинаковым образом с разными однотипными сущностями и разделяющими код.

Но это же делается просто созданием двух процессов, из Exec() которых вызывается одна и та же функция с разными указателями на рабочий объект. Несколько накладнее, пожалуй. И не так красиво.
Но у меня пока такие желания не возникали - ну пусть два UART - ну всё равно у них разное назначение в системе и они обрабатываются по разному.
А ради просто красоты до/пере-делывать структуру ОС особого смысла не вижу.



Цитата(sergeeff @ May 16 2009, 14:39) *
Очень хотелось бы сделать так, чтобы первый объявленный процесс получал высший приоритет, следующий процесс - приоритет на 1 ниже и т.д.
Тогда, объявив в самой ОС число возможных процессов по максимуму всю ОС оформить в виде отдельной библиотеки и пользователям в своей организации раздать, чтобы они "грязными ногами" в ее "чистом теле" не натоптали. Сколько не думал, пока ничего не придумалось. Может есть какие соображения на сей счет?
Чтобы процессов было "по максимуму" их и задать бы надо. Ну там размер таблиц вырастет, это ладно, но между низшим по приоритету из созданных и Idle заполнено всё должно быть, она же их вызывать попытается.
Можно наоборот - с низшего начинать. Ну, если выйдет, так как я тоже чисто языковыми средствами не могу придумать как это сделать - в разных файлах, независимо. Но тогда начинаться непонятно с чего выполнение будет - до наивысшего таблицы пусты.

Главное - "а зачем"?
Удобство "объектных", а не "исходниковых" библиотек в embeded обсуждалось неоднократно и практически для всего, кроме стандартной библиотеки языка оно для меня сомнительно. А уж scmRTOS, в которой ещё некоторые вещи конфигурируются попроектно - не только число процессов, и компилируется потом с inline-подстановками оптимально под проект - так и подавно.

Так то, что должно решаться административными методами, ими и решайте.
Пусть проверка результата работы производится компиляцией со свежевыдернутыми из недоступного по правам записи хранилища, а кто в рабочей копии наменял что-то - сам себе враг. Или ещё что-то придумайте.
koluna
Вопросы далее smile.gif

11. Как лучше поступить с исходниками scmRTOS?
Отвести для них отдельную папку и использовать для всех проектов сразу, как-то прописал пути в каждом проекте, или копировать в папку с каждым проектом?
Скопировал исходники в отдельную папку, прописал пути.
Но компилятор жалуется на отсутствие файлов scmRTOS_CONFIG.h и scmRTOS_TARGET_CFG.h - лежат в папке с проектом (это ведь файлы конфигурации ОС для конкретного проекта и по идее должны храниться в папке проекта). Переместил эти файлы в папку AVR ОС - компилятор перестал ругаться...

12. Сейчас при компиляции имею 5 ошибок. Скриншоты ниже (выбрана каждая из ошибок).
http://file.qip.ru/file/87782953/9829dcad/e1_online.html
http://file.qip.ru/file/87782958/ffb0525/e2_online.html
http://file.qip.ru/file/87782964/2d601acd/e3_online.html
http://file.qip.ru/file/87782966/c36e7be1/e4_online.html
http://file.qip.ru/file/87782969/53d16670/e5_online.html

Код main.cpp:

Код
#include <avr/io.h>
#include "scmRTOS.h"

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

TProc1 Proc1;
TProc2 Proc2;

int main(void)
{
    TCCR0B = (1 << CS01) | (1 << CS00);
    TIMSK0 |=  (1 << TOIE0);

    OS::Run();

    return 0;
};

namespace OS {

template<> OS_PROCESS void TProc1::Exec()
{
    for(;;)
    {
    }
}

}

namespace OS {

template<> OS_PROCESS void TProc2::Exec()
{
    for(;;)
    {
    }
}

}
ReAl
Цитата(n_bogoyavlensky @ May 16 2009, 15:30) *
Скопировал исходники в отдельную папку, прописал пути.
Но компилятор жалуется на отсутствие файлов scmRTOS_CONFIG.h и scmRTOS_TARGET_CFG.h - лежат в папке с проектом (это ведь файлы конфигурации ОС для конкретного проекта и по идее должны храниться в папке проекта). Переместил эти файлы в папку AVR ОС - компилятор перестал ругаться...
Текущая папка проекта должна быть прописана в ключах компилятора в -I иначе файлы из другой папки (из ОС) не видят .h из текущей.
koluna
Вообще непонятны следующие конструкции в примерах, я запутался...

Код
namespace OS {

template<> OS_PROCESS void TProc1::Exec()
{
...


В руководстве этого нет...

Цитата(ReAl @ May 16 2009, 17:31) *
Текущая папка проекта должна быть прописана в ключах компилятора в -I иначе файлы из другой папки (из ОС) не видят .h из текущей.


Получилось. Спасибо smile.gif
sergeeff
Цитата(ReAl @ May 16 2009, 15:17) *
Если постараться - можно.
В конструкторе TBaseProcess после Kernel.RegisterProcess(this), там, где формируется начальный стековый кадр, затолкать этот же this в такое место, чтобы после восстановления контекста он оказался в нужных регистрах. Только, насколько я понимаю, тип параметра exec у конструктора для этого должен быть другой - указатель на функцию-член.


Вы понимаете, надеюсь, что на место параметра exec в дальнейшем при переключении процессов будет писаться адрес возврата в прерванный процесс? Соответственно, this->(адрес чего-то там) никак не укладывается в размерность "чего-то там". А exec за счет своего static - укладывается, да еще и существует в единственном виде.

Про автоматическое присвоение приоритетам по мере объявления. Это могло бы автоматически решить проблему "бездырности" приоритетов в переменной, где устанавливаются/сбрасываются единички активных процессов. Одна из видимых проблем - pridle - намертво зашитый в enum. Понятно, что можно все тексты scmRTOS таскать вместе с проектом, но вы же исходники Windows/Linus и прочего в таком виде не используете? Вот и мне также хотелось бы иметь только библиотеки от scmRTOS, ну за вычетом inline и template, которые ну просто никак по-другому (пока, по крайней мере).
ReAl
Цитата(sergeeff @ May 16 2009, 21:06) *
Вы понимаете, надеюсь, что на место параметра exec в дальнейшем при переключении процессов будет писаться адрес возврата в прерванный процесс?
На место параметра писаться не будет ничего. Писаться будет на то место в стеке процесса, куда конструктор значение параметра - начальное значение счётчика команд для процесса, как якобы он в этот момент был прерван - будет записано. При статическом exec происходит то же - при первом же вызове любой подпрограммы, первом же вхождении в любое прерывание - стековый кадр процесса будет перезаписан, от инициализирующих значений там ничего не останется.

Цитата(sergeeff @ May 16 2009, 21:06) *
Соответственно, this->(адрес чего-то там) никак не укладывается в размерность "чего-то там". А exec за счет своего static - укладывается, да еще и существует в единственном виде.
Это другое дело, тут я не прав
(::*)() имеет более сложную структуру, чем (*)(), там наворочено на случай наследования/виртуальных и эта гадость не приводится ни к void* и к чему другому и просто так вызвать не получится.
Так что если хочется сделать реальную функцию процесса нестатической, то нужно просто статический exec сделать принимающим указатель на объект класса (записывать в стековый кадр на нужное место this) и в самом exec() так
Код
bla_bla_bla::Exec(void *p)
{
    bla_bla_bla * myprocess = reinterpret_cast<bla_bla_bla*>(p);
    myprocess->execute();
}

Если сделать execute() ещё в TBaseProcess и сделать её виртуальной, то тогда можно прямо TBaseProcess* сделать аргументом Exec. Но это лишние расходы.
А вот сделать Exec принимающим void*, добавить аргумент void *pросdata=0 в конструктор TBaseProcess и в шаблон процесса - практически ничего не требует дополнительного и, пожалуй, будет совместимо с уже написанным кодом. И иногда может быть удобным, по крайней мере если захочется из TBaseProcess вывести свой тип процесса и создать два экземпляра процесса. Но то же самое и со столь же небольшими расходами (хотя по ОЗУ вопрос - надо смотреть) можно сделать, создав два разных процесса "как оно сейчас" и сделав
Код
bla_bla_bla_1::Exec()
{
    process1.execute();
}

bla_bla_bla_2::Exec()
{
    process2.execute();
}

Так что при желании сделать реальную функцию процесса нестатической можно разными способами, хоть и не выйдет через указатель на функцию-член.

Цитата(sergeeff @ May 16 2009, 21:06) *
вы же исходники Windows/Linus и прочего в таком виде не используете?
Со сравнением с тасканием исходников "больших" ОС не согласен - эти ОС запускают отдельно скомпилированные процессы, долинковывая их к себе при запуске. И такая универсальность тянет за собой дополнительные расходы.
От scmRTOS пока такого (к примеру, загрузки процесса по каналу связи или из воткнутой флешки) никто не требует, а если потребует, то она станет гораздо менее "scm-ной".
Она в существенной мере инлайнится в пользовательское приложений - ну положите Вы объектные модули, по .cpp и .S от scmRTOS уже "никто не потопчется" ценой роста размера таблиц. Но существенная часть кода ОС всё равно находистя в .h-файлах и с "нетоптанием" по ним всё равно придётся работать "административно" а не "языково".
"За что боролись?"

Конечно, любая автоматизация даёт удобства. И можно даже что-то попробовать наворотить. Все ключевые места, где используется число процессов - или разогнать по максимуму (таблицы), или считывать из внешних по отношению к коду ОС переменных (начальные/конечные значения счётчиков/масок при переборе процессов), так как пустые места в таблицах надо будет обходить. Стоят ли эти расходы полученного частичного удобства, отличающегося не качественно, а только количественно (ограничен доступ грязных ножек и шаловливых ручек к половине файлов)? Ну не знаю.
koluna
Помогите, пожалуйста, побороть ошибки (на первой странице)!
У вас тут такие разговоры пошли... я ничего не понимаю... crying.gif
sergeeff
Цитата(ReAl @ May 17 2009, 14:04) *
На место параметра писаться не будет ничего. Писаться будет на то место в стеке процесса, куда конструктор значение параметра - начальное значение счётчика команд для процесса, как якобы он в этот момент был прерван - будет записано.


Про счетчик команд процесса. Может вы просто неудачно это называете. Это ведь просто значение регистра адреса команд. Правильнее было бы говорить про стартовый адрес процесса в начале, и текущий (прерванный) адрес процесса.
ReAl
Цитата(n_bogoyavlensky @ May 17 2009, 13:31) *
Помогите, пожалуйста, побороть ошибки (на первой странице)!
У вас тут такие разговоры пошли... я ничего не понимаю... crying.gif
Что-то мне казалось, что с включением текущей папки проекта в пути поиска все эти undefined reference должны были уйти.
koluna
Цитата(ReAl @ May 17 2009, 15:13) *
Что-то мне казалось, что с включением текущей папки проекта в пути поиска все эти undefined reference должны были уйти.


Но не ушли...
А чтобы ушли, надо было в мой проект Code::Blocks добавить файлы ОС OS_Target_cpp.cpp, OS_Target_asm.S, OS_Kernel.cpp, OS_Services.cpp, usrlib.cpp.

Я их не включил в проект, наивно полагая, что C::B или компилятор их сами включат...
sergeeff
Цитата(n_bogoyavlensky @ May 17 2009, 15:17) *
Но не ушли...

Я их не включил в проект, наивно полагая, что C::B или компилятор их сами включат...


Вы должны раз и навсегда запомнить. Вы пишете программу, а не IDE и всякие там С::B и прочие. Что вы в проект сами включите, то и получите.
koluna
Вот по поводу этого объясните, ещё пожалуйста:

Код
namespace OS {

template<> OS_PROCESS void TProc1::Exec()
{
...


Зачем namespace, template?
На страницах 21, 27, 103-104 руководства процесс оформлен более просто... почему?
sergeeff
На 21 стр. - "скелет" функции. Собственно вызов (имя) и иллюстрация того, что процесс, как минимум, бесконечный цикл.

На 103-104 стр. - реальный пример.
koluna
Цитата(sergeeff @ May 17 2009, 15:53) *
На 21 стр. - "скелет" функции. Собственно вызов (имя) и иллюстрация того, что процесс, как минимум, бесконечный цикл.

На 103-104 стр. - реальный пример.


Да я это-то понял давно!
Я не понял почему в этом примере (стр. 103-104) "namespace OS" и "template<>" перед функциями процессов не поставлены, а в примерах из дистрибутива ОС - поставлены.
Почему? smile.gif
sergeeff
Текущая верия scmRTOS? - 3.05

А документация писалась под 2.хх. C тех пор много воды утекло.
ReAl
Цитата(n_bogoyavlensky @ May 17 2009, 15:10) *
Я не понял почему в этом примере (стр. 103-104) "namespace OS" и "template<>" перед функциями процессов не поставлены, а в примерах из дистрибутива ОС - поставлены.
Почему? smile.gif
Потому что gcc 4.x несколько строже к этому всему относится и требует, чтобы Exec() определялся в том же namespace, в котором он был объявлен (в файлах ОС). С template<> аналогичная петрушка - все параметры шаблона уже "специализированы", свободных не осталось, но Exec() - часть шаблона, поэтому gcc просит template<>
IAR обходится без этого, а документация писалась автором оси по итогам IAR-вского варианта.

Не вникал дотошно в стандарт - толи IAR даёт тут некоторое послабление относительно стандарта, толи gcc относится несколько прямолинейнее, чем нужно, но это в конечном итоге и неважно.
А в стандарте в примерах такие же template<> с пустыми уголками.


По поводу включения осевых .cpp в проект - ни среда ни компилятор действительно от себя ничего не включают.
Так или иначе это нужно указать, в примерах к варианту avr-gcc просто в makefile сделаны правила "включать всё, что есть в указанных каталогах - проекта (текущий) и scmRTOS/Common scmRTOS/AVR". И make находит нужное и включает в команды для компилятора.
koluna
ReAl

Понятно.
Вот спасибо smile.gif
И за avreal32.exe спасибо (если я не ошибаюсь) biggrin.gif

А ссылочку на стандарт можно?
Сергей Борщ
Цитата(n_bogoyavlensky @ May 17 2009, 18:14) *
А ссылочку на стандарт можно?
Google-> "c++ standard". Первая же ссылка.
dxp
Цитата(sergeeff @ May 16 2009, 18:39) *
Очень хотелось бы сделать так, чтобы первый объявленный процесс получал высший приоритет, следующий процесс - приоритет на 1 ниже и т.д.
Тогда, объявив в самой ОС число возможных процессов по максимуму всю ОС оформить в виде отдельной библиотеки и пользователям в своей организации раздать, чтобы они "грязными ногами" в ее "чистом теле" не натоптали. Сколько не думал, пока ничего не придумалось. Может есть какие соображения на сей счет?


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


Ну, а про автоматическое присваивание приоритетов - а если процессы объявлены в разных файлах? Тут зависимость от порядка объявления возникнет. 

А для борьбы с ошибками конфигурации штатные средства (компилятор, линкер, препроцессор) не подходят (из-за раздельной компиляции), и лучше использовать утилитку, которую пускать в процессе сборки (до или после линкера). Я так и делаю. И проблем нет. Всем рекомендую.
sergeeff
Ну и лады.
dxp
Цитата(ReAl @ May 16 2009, 19:17) *
Если постараться - можно.
В конструкторе TBaseProcess после Kernel.RegisterProcess(this), там, где формируется начальный стековый кадр, затолкать этот же this в такое место, чтобы после восстановления контекста он оказался в нужных регистрах. Только, насколько я понимаю, тип параметра exec у конструктора для этого должен быть другой - указатель на функцию-член.

Да, согласен, если постараться, то можно. Раз уж готовим сами стековый кадр, то и внедрить туда this тоже можно. Только зачем? Я ни одной приличной причины не знаю. По своей сути функция exec - это функция пользователя. Ей от самого объекта-процесса ничего не надо. Т.е. это отдельная фукнция, просто помещенная в пространство имен процесса. С таким же успехом можно было бы создавать произвольные глобальные функции и подсовывать их в конструктор процесса. Ну, как сделано, так сделано. smile.gif В духе ++. 
koluna
13. Что такое системный процесс Idle и для чего он нужен?

14. Как "сообщить" scmRTOS о том, что я в качестве системного таймера выбрал таймер Т0?

15. По поводу scmRTOS_SYSTIMER_NEST_INTS_ENABLE. Зачем разрешать вложенные прерывания в обработчике прерывания от системного таймера?
Для какой-нибудь очень важной и срочной задачи (если она есть)?
Сергей Борщ
Цитата(n_bogoyavlensky @ May 18 2009, 12:31) *
13. Что такое системный процесс Idle и для чего он нужен?
Процессор выполняет его, когда все пользовательские процессы находятся в состоянии ожидания. В нем может быть, например, команда перевода процессора в спячку.
Цитата(n_bogoyavlensky @ May 18 2009, 12:31) *
14. Как "сообщить" scmRTOS о том, что я в качестве системного таймера выбрал таймер Т0?
Хороший. вопрос. Учитывая, что в примерах именно T0 уже выбран в качестве системного таймера.
Цитата(n_bogoyavlensky @ May 18 2009, 12:31) *
Зачем разрешать вложенные прерывания в обработчике прерывания от системного таймера?
Для какой-нибудь очень важной и срочной задачи (если она есть)?
Да. Для других прерываний, которые могут не использовать сервисы ОС.
koluna
Ну вот, запустил smile.gif
Только вот код много места занимает.
С опцией компилятора -Os, rtos.elf.hex - 8 кб, бинарный - около 3 кб.
Это нормально? Или для сокращения размера надо ещё что-нибудь в опции компилятора добавить?

Код
#include <avr/io.h>
#include <scmRTOS.h>

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

TProc1 Proc1;
TProc2 Proc2;

int main(void)
{
    DDRB |= _BV(PB0);
    DDRC |= _BV(PC5);

    TCCR0B = (1 << CS01) | (1 << CS00);    // clk/64
    TIMSK0 |=  (1 << TOIE0);

    OS::Run();

    return 0;
};

namespace OS
{
    template<> OS_PROCESS void TProc1::Exec()
    {
        for(;;)
        {
            if ((PORTB & _BV(PB0))) {PORTB &= ~_BV(PB0);} else {PORTB |= _BV(PB0);};
            Sleep(10);
        };
    };
};

namespace OS
{
    template<> OS_PROCESS void TProc2::Exec()
    {
        for(;;)
        {
            if ((PORTC & _BV(PC5))) {PORTC &= ~_BV(PC5);} else {PORTC |= _BV(PC5);};
            Sleep(10);
        };
    };
};


Цитата(Сергей Борщ @ May 18 2009, 15:37) *
Процессор выполняет его, когда все пользовательские процессы находятся в состоянии ожидания. В нем может быть, например, команда перевода процессора в спячку.


А ещё что там может быть? Что угодно с учётом того, что этот процесс самый низкоприоритетный?

Цитата
Хороший. вопрос. Учитывая, что в примерах именно T0 уже выбран в качестве системного таймера.


Примеры смотрел. Но не так подробно все исходники. Времени пока нет.
Пока нигде не "сообщал" и всё работает с Т0.
Но ответ хотелось бы знать smile.gif



Как я понял, если следовать логике авторов ОС, то для Idle код надо вставлять в IdleProcessUserHook()? smile.gif
А где её определять?
В своём модуле или в OS_Target_cpp.cpp?
Наверное, в своём лучше...
ReAl
Цитата(n_bogoyavlensky @ May 18 2009, 15:12) *
Ну вот, запустил smile.gif
Только вот код много места занимает.
С опцией компилятора -Os, rtos.elf.hex - 8 кб, бинарный - около 3 кб.
Это нормально? Или для сокращения размера надо ещё что-нибудь в опции компилятора добавить?


http://electronix.ru/forum/index.php?s=&am...st&p=593569

Цитата(n_bogoyavlensky @ May 18 2009, 15:12) *
А ещё что там может быть? Что угодно с учётом того, что этот процесс самый низкоприоритетный?
И что он не может пользоваться "ожидающими" сервисами. Т.е. послать сигнал может, ждать его - нет.
Код
start = OS::GetTickCount();
while( (OS::GetTickCount() - start) < 10 );
может
Код
Sleep(10);
не может.

Хук, естественно, лучше в своём.

Цитата(n_bogoyavlensky @ May 18 2009, 15:12) *
Примеры смотрел. Но не так подробно все исходники. Времени пока нет.
А у нас, значит, валом...
koluna
Нашёл:

В OS_Target_cpp.cpp определена функция:

Код
//    System timer ISR
//
OS_INTERRUPT void SYSTEM_TIMER_VECTOR(void)
{
    scmRTOS_ISRW_TYPE ISR;
    Kernel.SystemTimer();

  #if scmRTOS_SYSTIMER_HOOK_ENABLE == 1

    // enable nested interrupts ONLY if user hook enabled
  #if scmRTOS_SYSTIMER_NEST_INTS_ENABLE == 1
    ENABLE_NESTED_INTERRUPTS();
  #endif

    SystemTimerUserHook();
  #endif
}


А выбор вектора прерывания системного таймера осуществлён в scmRTOS_TARGET_CFG.h.
Здесь и выбираем нужный системный таймер.
А в main его инициализируем...

Код
//       System Timer stuff
//
//
#if defined(TIMER0_OVF0_vect)
#  define SYSTEM_TIMER_VECTOR TIMER0_OVF0_vect
#elif defined(TIMER0_OVF_vect)
#  define SYSTEM_TIMER_VECTOR TIMER0_OVF_vect
#else
#  error "Timer0 overflow vector not defined"
#endif

#if defined(TIMSK0)
#  define TIMSK0_REG TIMSK0
#elif defined(TIMSK)
#  define TIMSK0_REG TIMSK
#else
#  error "Timer0 interrupt mask register not defined"
#endif

#define LOCK_SYSTEM_TIMER()    ( TIMSK0_REG &= ~(1 << TOIE0) )
#define UNLOCK_SYSTEM_TIMER()  ( TIMSK0_REG |=  (1 << TOIE0) )


Цитата(ReAl @ May 18 2009, 16:27) *


Пробовал, разницы нет...
ReAl
Цитата(n_bogoyavlensky @ May 18 2009, 15:59) *
Пробовал, разницы нет...

Странно.
Пример 1-EventFlag из порта - явно сложнее Вашего кода.
CFLAGS = -Os -ffunction-sections -fdata-sections
LDFLAGS = -Wl,--gc-sections -Wl,--relax

Код
======== Beginning of project event_flag processing
avr-gcc.exe (GCC) 4.2.2 (WinAVR 20071221)
...
==== Compiling ./src/main.cpp
==== Compiling ../scmRTOS/Common/OS_Kernel.cpp
==== Compiling ../scmRTOS/Common/OS_Services.cpp
==== Compiling ../scmRTOS/Common/usrlib.cpp
==== Compiling ../scmRTOS/AVR/OS_Target_cpp.cpp
==== Compiling ../scmRTOS/AVR/OS_Target_asm.S
==== Link to event_flag.elf
==== extract event_flag.hex
======== All OK, project size:
AVR Memory Usage
----------------
Device: atmega168
Program:    1792 bytes (10.9% Full)
(.text + .data + .bootloader)
Data:        444 bytes (43.4% Full)
(.data + .bss + .noinit)

Код
======== Beginning of project event_flag processing
avr-gcc.exe (GCC) 3.4.6
...
======== All OK, project size:
AVR Memory Usage
----------------
Device: atmega168
Program:    2084 bytes (12.7% Full)
(.text + .data + .bootloader)
Data:        444 bytes (43.4% Full)
(.data + .bss + .noinit)

Код
======== Beginning of project event_flag processing
avr-gcc.exe (WinAVR 20081205) 4.3.2
...
======== All OK, project size:
AVR Memory Usage
----------------
Device: atmega168
Program:    1686 bytes (10.3% Full)
(.text + .data + .bootloader)
Data:        444 bytes (43.4% Full)
(.data + .bss + .noinit)

Код
======== Beginning of project event_flag processing
avr-gcc.exe (WinAVR 20090313) 4.3.2
...
======== All OK, project size:
AVR Memory Usage
----------------
Device: atmega168
Program:    1664 bytes (10.2% Full)
(.text + .data + .bootloader)
Data:        444 bytes (43.4% Full)
(.data + .bss + .noinit)


-funsigned-bitfields -fshort-enums компилятору ещё немного уменьшает код, байт на тридцать в зависимости от версии компилятора (собственно, в примерах в makefile эти опции стоят, но я не упоминал их в том посте и сейчас для соответствия ему убрал)
koluna
Не могу понять... почему у меня тогда код почти в два раза больше? sad.gif
Что тут можно предпринять?
ReAl
Цитата(n_bogoyavlensky @ May 18 2009, 17:58) *
Не могу понять... почему у меня тогда код почти в два раза больше? sad.gif
Что тут можно предпринять?
Попробуйте разобраться - какие опции реально получает компилятор. Я-то всем управляю руками через самописній makefile, а сто там среда куда подставляет...

p.s. если у меня на уровне makefile отключить линкеру --gc-sections --relax, то віходит 3400-3500 байт в зависимости от версии компилятора
koluna
Цитата(ReAl @ May 18 2009, 20:42) *
Попробуйте разобраться - какие опции реально получает компилятор. Я-то всем управляю руками через самописній makefile, а сто там среда куда подставляет...


Я пока не знаю как это сделать sad.gif
Вроде, прописал всё куда нужно...
Надо как-то попробовать включить полный вывод того, что делает среда...

Цитата
p.s. если у меня на уровне makefile отключить линкеру --gc-sections --relax, то віходит 3400-3500 байт в зависимости от версии компилятора


Кстати, вот ещё что...
Добавил в проект старый модуль на Си (xxx.c).
Получил на все функции в нём сообщения о том, что они не определены...
Переименовал файл в "xxx.cpp" - всё сразу нашлось.
Почему?
Добавлял-то я файл с расширением...
ReAl
Цитата(n_bogoyavlensky @ May 18 2009, 20:14) *
Добавил в проект старый модуль на Си (xxx.c).
Получил на все функции в нём сообщения о том, что они не определены...
Переименовал файл в "xxx.cpp" - всё сразу нашлось.
Почему?
Добавлял-то я файл с расширением...
В .h они были объявлены "как обычно" и при компиляции С++ файлов (других в проекте) компилятор, грубо говоря, пытался на них сослаться как на С++ - функции.
Надо внутренности этого h-файла охватить таким
Код
#ifdef __cplusplus
extern "C" {
#endif

// тут объявления всех функций из С-файла

#ifdef __cplusplus
}
#endif
sergeeff
Уважаемый коллега!

Неужели вам в google трудно поискать ответы на тысячу раз расписанные вопросы совместной работы .с и .сpp модулей?

Вы своим пытливым взглядом не разглядивали устройство .h файлов в библиотеках? Так вот там есть такая кострукция:

Код
#ifdef __cplusplus

extern "C" {
#endif /* __cplusplus */

int            ааа(int j);
int            bbb(const char *s);

.....

#ifdef __cplusplus
}
#endif /* __cplusplus */


Это заставляет С++ -ный компилятор генерить С-совместимые (nonmangled) имена. Что и вам надо сделать с вашими .h файлами (если вы ими в своими проектами пользуетесь, надеюсь).
koluna
Спасибо Вам всем большое smile.gif
Обязательно посмотрю подробнее.
sergeeff
Цитата(n_bogoyavlensky @ May 18 2009, 22:05) *
Спасибо Вам всем большое smile.gif
Обязательно посмотрю подробнее.


Может надо взять за правило сначала посмотреть все по-подробнее, а уже потом...
koluna
Цитата(sergeeff @ May 18 2009, 22:08) *
Может надо взять за правило сначала посмотреть все по-подробнее, а уже потом...


Согласен. Но не всегда получается. Вы уж извините...
Очень всем благодарен за помощь! smile.gif
koluna
Здравствуйте!

Ещё один вопрос smile.gif

Корректным ли с точки зрения ОС будет использование объекта TEventFlag как поля данных внутри динамически создаваемого экземпляра класса (экземпляр класса, точнее указатель на него, при этом глобальный)?
Или объект TEventFlag должен быть обязательно статическим?
Сергей Борщ
Цитата(n_bogoyavlensky @ May 25 2009, 09:06) *
Корректным ли с точки зрения ОС будет использование объекта TEventFlag как поля данных внутри динамически создаваемого экземпляра класса
Вполне корректно.
koluna
Цитата(Сергей Борщ @ May 25 2009, 11:50) *
Вполне корректно.


Слово "вполне" немного смущает smile.gif
Какие подводные камни?
Сергей Борщ
Цитата(n_bogoyavlensky @ May 25 2009, 11:28) *
Какие подводные камни?
Да никаких, кроме обычных - обращение через указатель к уже уничтоженному объекту.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.