scmRTOS 4.0 release

4 квітня (2012.04.04) нарешті вийшла «офіційна» версія 4.0 операційної системи scmRTOS.

Попередню версію по виправленні відомих помилок збережено в гілці scmrtos/tags/3.11.

Нова версія зафіксована в scmrtos/tags/4.00 та продовжує розвиватися в scmrtos/trunk.

»»» Дізнатися, що нового в з’явилося в scmRTOS 4.0

scmRTOS for STM8, IAR port

Влітку зовсім не було часу на продовження розробки scmRTOS, лише зараз до цього повернувся.

Порт STM8/IAR додано в репозиторій, в гілку scmRTOS pre-v4.00. Звідти можна витягти архів прикладів scmRTOS для порта STM8/IAR. Каталоги scmRTOS/Common, scmRTOS/Extensions та scmRTOS/STM8 в архіві прикладів порожні, необхідно завантажити архіви ядра scmRTOS pre-v4.00, розширень ядра та порта STM8/IAR і розпакувати їх у відповідні каталоги.

»»» Детальніше про порт scmRTOS для мікроконтролерів STM8

scmRTOS for STM8

Викладаю першу чорнову версію порта scmRTOS для мікроконтролерів STM8 та компілятора IAR.
Порт основано на scmRTOS гілки pre-v400.

Обмеження цієї версії порта:

  • Не підтримується LARGE модель даних.
  • Не реалізовано перемикання контексту програмно ініційованим прериванням.
  • Не реалізовано перемикання преривань на окремий стек.

В комплекті йдуть приклади 1-EventFlag та 4-Debug.
Приклади збиралися компілятором IAR версії 1.30, перевірялися на платі STM8S-DISCOVERY (STM8S105C6).

Файли iostm*.h від IAR конфліктують з файлом stm8s.h від STMicroelectronics. Зараз приклади зроблено під IAR-івські include-файли.
Порт scmRTOS (вміст каталогу scmRTOS/STM8) не залежить від цих файлів, все необхідне йому передається у вигляді макросів у файлі scmRTOS_TARGET_CFG.h.
Схоже, пізніше в окремому #include-файлі буде дописано те, чого не вистачає для використання stm8s.h, приклади буде переписано під стандартну бібліотеку від STMicro.

Приклад 1-EventFlag зроблено на основі прикладу для AVR/GCC порта, можна користуватися описом цього прикладу використання scmRTOS.
При оптимізації максимального рівня на швидкість приклад 4-Debug працює неправильно. Тобто все наче працює, на терміналку стан стеків процесів та завантаженість системи видається, але величини завантаженості не відповідають дійсності. При максимальній оптимізації на розмір або збалансованій приклад працює. В чому причина неправильної роботи — ще не розбирався.

В офіційний репозиторій scmRTOS порт поки-що не включено — щоб не затримувати вихід релізу scmRTOS v4.00.


Доповнення від 8 листопада 2011 року: порт STM8/IAR додано в репозиторій scmRTOS.

Attached Files:

Нарешті!

Нарешті я знайшов час для перекладу опису прикладу «1-EventFlag» scmRTOS російською та англійською мовами. Пояснення базується на avr-gcc (WinAVR) порті системи для мікроконтролерів AVR, але може бути корисним для розуміння будь-якого порта системи.

Заразом трохи почистив сам текст, додав врізки з призначенням виводів, позначки на осцилограми та розфарбовку синтаксису. Не знаю, чи не надто пістряве воно від всього цього вийшло, та сподіваюся, що стало краще.

Пояснення прикладу 1-EventFlag

Як працює цей приклад scmRTOS і що взагалі там відбувається?
Ілюстроване пояснення.

Пояснення базується на avr-gcc (WinAVR) порті системи для мікроконтролерів AVR, але може бути корисним для розуміння будь-якого порта системи.

Для детальної демонстрації процесів, що відбуваються в системі, приклад 1-EventFlag дещо розширено. В функції Exec() процесів, IdleProcessUserHook(), SystemTimerUserHook(), TIMER1_COMPA_vect() (файл main.cpp) а також в код перемикання контекстів (файл OS_Target_asm.S) додано команди зміни стану виводів мікроконтролера.

Виводи, що керуються з коду користувача scmRTOS, призначаються у файлі main.cpp:

55
56
57
58
59
60
61
62
63
64
65
//-------------------------------------------------------------------
//  "Hello, scope!" pins (pin numbers for ATmega168 in DIP28 package)
// Define pins in form   PORT_LETTER,PORT_PIN,ACTIVE_LEVEL
// (Ascold Volkov - type "pin_macro.h" notation)
#define TIMER1_ISR_PIN     C,4,H    // pin 27
#define T1PROC1_PIN        B,0,H    // pin 14
#define PROC1_PIN          B,1,H    // pin 15
#define PROC2_PIN          B,2,H    // pin 16
#define PROC3_PIN          B,3,H    // pin 17
#define TIMERHOOK_PIN      B,4,H    // pin 18
#define IDLEHOOK_PIN       B,5,H    // pin 19

Вивід контролера для керування з перемикача контекстів визначається в makefile:

11
12
13
# Define contect switch "Hello, scope!" pin in form PORT_LETTER,PORT_PIN
#    C,5 for pin5 of PORTC
SWITCH_PIN=C,5

Виводи підключено до логічного аналізатора. Контролер тактується від внутрішнього RC-генератора на 8 МГц, один тік системного таймера відповідає приблизно двом мілісекундам.

Приклади в репозиторії scmRTOS та її код можуть змінюватися. Крім того, перемикач контекстів в робочому коді не може містити команд керування виводами мікроконтролера, їх прибрано з коду в репозиторії. Звідси можна завантажити архів 1-EventFlag-explanation.zip з модифікованою scmRTOS та прикладом, які відповідають пропонованому тексту.
Приклад розраховано на компілятор avr-gcc (WinAVR) та на мікросхему з лінійки ATmega48/ATmega88/ATmega168/ATmega328, для інших мікроконтролерів може знадобитися внести зміни відповідно до використовуваних таймерів та виводів.


Розподіл входів аналізатора

D5 IDLEHOOK
Перекидається у протилежний стан в IdleProcessUserHook().
D4 TIMERHOOK
Перекидається у протилежний стан в SystemTimerUserHook()
D3 PROC3
Піднімається та опускається в TProc3::Exec().
D2 PROC2
Піднімається та опускається в TProc2::Exec().
D1 SWITCH
Піднімається першою командою перемикача контексту, опускається перед виконанням команди виходу з перемикача (безпосередньо перед reti).
D0 T1PROC1
Піднімається в прериванні TIMER1_COMPA_vect(), опускається в функції TProc1::Exec(), яка чекає сигналу від цього переривання.

Взаємна робота Proc2 та Proc3 — з пташиного польоту

Параметри компіляції прикладу:

main.cpp

86
#define PROC2_LONG_PULSE 1

Proc2 генерує імпульс довжиною в один тік системного таймера. Всі інші параметри компіляції при вивченні системи в такому масштабі неважливі.


Proc2 and Proc3 live oscillogram

  1. Сигнал IDLEHOOK, який є меандром з періодом в декілька мікросекунд з короткими перервами на роботу процесів, в цьому масштабі відображається суцільною смугою.
  2. Оскільки значення сигналу TIMERHOOK інвертується в функції OS::SystemTimerUserHook(), на відповідній лінії спостерігається меандр з періодом в два тіки системного таймера, близько чотирьох мілісекунд. Події на лініях PROC2 та PROC3 відбуваються синхронно зі зіміною стану на лінії TIMERHOOK.
  3. В функції TProc2::Exec() є два виклики функції засинання просесу: Sleep(1) визначає довжину імпульса на лінії PROC2, Sleep(9) визначає час між імпульсами. Таким чином, Proc2 є мультивібратором з періодом імпульсів 10 тіків системного таймера (20 мс) та довжиною імпульсу 1 тік (2 мс).
  4. Перед опусканням лінії PROC2 та засинанням на десять тіків Proc2 викликом ef.Signal(); пробуджує Proc3. Отримавши керування, TProc3::Exec() піднімає рівень на лінії PROC3 та знову засинає, тепер по виклику Sleep(). Час сну вибирається виходячи з стану біту 9 лічильника системних тіків, отриманого викликом OS::GetTickCount();. Протягом 512 тіків таймера (близько секунди) процес спить два тіки таймера, протягом іншої секунди сон триває три тіки таймера.
  5. Прокидаючись після сну по системному таймеру Proc3 опускає сигнал на лінії PROC3 та викликом ef.Wait(); знову засинає в очікуванні сигналу від Proc2. Фактично Proc3 є одновібратором, що запускається по спаду імпульса на лінії PROC2.
  6. Імпульси на лінії T1PROC1 не синхронізовані з системним таймером, бо вони породжуються в прериванні TIMER1_COMPA_vect(), яке активується з частотою, не кратною системному таймеру. Детальніше робота таймера 1 та Proc1 розглянута нижче.
  7. На лінії SWITCH бачимо маркери перемикання процесів. Частина з них відповідає перепадам на лініях PROC2 та PROC3, частина — на лінії T1PROC1.

Перемикання з Proc2 на Proc3 — під мікроскопом

Параметри компіляції OC та прикладу (спільна частина для обох варантів розвитку подій):

scmRTOS_CONFIG.h

124
#define scmRTOS_CONTEXT_SWITCH_SCHEME  1

Перемикання контекстів виконується за допомогою переривання найнижчого рівня пріоритету, запит якого формується програмно. Перемикання, заплановане в результаті обробки інших преривань, починає працювати після виходу з цих преривань.

main.cpp

86
#define PROC2_LONG_PULSE               0

Для детального розгляду з коду Proc2 видалено затримку в один тік системного таймера при генерації імпульсу на лінії PROC2. Довжина імпульсу тепер визначається часом роботи функції ef.Signal() та, у варіанті 2, часом перемикання задач та роботи Proc3.

Варіант 1

Додаткові параметри компіляції:

main.cpp

85
#define PROC2_HIGHER_THAN_PROC3        1

Пріоритет Proc2 вищий, ніж Proc3.


Proc2 to Proc3 variant 1

  1. При переході на підпрограму переривання від системного таймера припиняється генерація меандру на лінії IDLEHOOK в функції IdleProcessUserHook().
  2. Після закінчення роботи системної частини підпрограми переривання викликається функція користувача SystemTimerUserHook(), в якій інвертується стан лінії TIMERHOOK.
  3. Відбувається вихід з підпрограми переривання системного таймеру та вхід в переривання перемикання контексту. Між двома перериваннями може виконатися одна команда з коду перерваного процесу. На цій осцилограмі трапилося так, що цією командою було інвертування стану лінії IDLEHOOK.
  4. Перемикання контексту, яке передає керування Proc2 в точку виходу з виклику Sleep(9). На початку перемикання піднімаєтьcя рівень на лінії SWITCH, по закінченні перемикання лінія SWITCH повертається до низького рівня. Довжина імпульсу показує час, необхідний власне для перемиканя контексту, без врахування витрат часу на диспетчеризацію.
  5. В функції TProc2::Exec() піднімається лінія PROC2, викликається ef.Signal() і опускається лінія PROC2. По довжині імпульсу можна визначити час, необхідний для виконання функції Signal(). Тепер TProc2::Exec() робить виклик Sleep(10) і засинає, планувальник scmRTOS шукає готовий до виконання процес. Таким процесом є TProc3, який щойно отримав сигнал.
  6. Відбувається чергове перемикання процесів (другий імпульс на лінії SWITCH), керування отримує TProc3::Exec().
  7. Proc3 піднімає лінію PROC3, зчитує значення системного лічильника тіків і засинає на відповідний час, як це описано в розділі «Взаємна робота Proc2 та Proc3 — з пташиного польоту».
  8. Знову перепланування процесів і, оскільки інших готових до виконання процесів немає, керування передається на IdleProcess (третій імпульс на лінії SWITCH).
  9. Керування отримала функція TIdleProcess::Exec(), відновлюється перекидання лінії IDLEHOOK. Довжина паузи в меандрі показує повний час на обробку апаратного переривання, перепланування процесів, перемикання контекстів та виконання процесами своєї роботи, перемикання назад на процес IdleProcess.

Перемикання процесів відбувається по шляху IdleProcess → Proc2 → Proc3 → IdleProcess, разом три перемикання процесів.

Варіант 2

Додаткові параметри компіляції:

main.cpp

85
#define PROC2_HIGHER_THAN_PROC3        0

Пріоритет Procп2 нижчий, ніж у Proc3. Події розгортаються схожим на «Варіант 1» чином, але є відмінності після виклику ef.Signal() в TProc2::Exec().
Осцилограми змінюються наступним чином:


Proc2 to Proc3 variant 2

  1. При переході на підпрограму переривання від системного таймера припиняється генерація меандру на лінії IDLEHOOK в функції IdleProcessUserHook().
  2. Після закінчення роботи системної частини підпрограми переривання викликається SystemTimerUserHook(), в якій інвертується значення лінії TIMERHOOK.
  3. Перше переривання перемикання контексту передає керування Proc2 в точку виходу з виклику Sleep(9).
  4. В функції TProc2::Exec() піднімається лінія PROC2, викликається ef.Signal(). І тут, на відміну від першого варіанту, повернення з викликаної системної функції дещо затримується. В даному варіанті пріоритет Proc3 вищий, ніж Proc2, тому перепланування в кінці ef.Signal() активує перемикання на Proc3.
  5. Перемикання процесів (другий імпульс на лінії SWITCH), керування отримує TProc3::Exec().
  6. Proc3 піднімає лінію PROC3, зчитує значення системного лічильника тіків і засинає.
  7. Залишається ще один активний процес — Proc2, контекст перемикається назад на TProc2::Exec() (третій імпульс на лінії SWITCH).
  8. І от лише тепер відбувається «повернення» в TProc2::Exec() з функції ef.Signal(). Нарешті опускається лінія PROC2. На цій осцилограмі довжина імпульсу на лінії PROC2 набагато більша, ніж для попереднього варіанту, в нього ввійшли робота Proc3 та два перемикання процесів.
    Тепер TProc2::Exec() знову робить виклик Sleep(9), scmRTOS шукає готовий до виконання процес. Але для даного варіанту ним є не Proc3, він вже свою роботу зробив, а фоновий процес IdleProcess.
  9. Останнє перемикання контекстів, керування передається на TIdleProcess::Exec().
  10. Керування отримала функція TIdleProcess::Exec(), відновлюється перекидання лінії IDLEHOOK.

При такому співвідношенні пріоритетів виконання іде по шляху
IdleProcess → Proc2 → Proc3→ Proc2 → IdleProcess
Маємо чотири перемикання процесів.

З одного боку, роботу IdleProcess було перервано на довший час. В реальній системі перерваним міг би бути процес, який виконував би кориснішу роботу, ніж перекидання стану IO-ніжки у високому темпі.
З іншого боку, Proc3 отримав керування дещо раніше. Знову ж таки, в реальній системі, де між відправкою сигналу за допомогою ef.Signal() та засинанням Proc2 робив би більше роботи, в першому варіанті затримка до початку роботи Proc3 була б ще більша.
Який варіант кращий, залежить від конкретних умов, від логіки роботи системи. Цей приклад лише показує, що від вибору пріоритетів процесів залежатимуть затримки від подій до передачі керування потрібному процесові та час роботи процесів.


Передача сигналу від переривання таймера 1 до процесу 1

Ця частина прикладу відрізняється від попередніх лише тим, що передача сигналу через OS::TEventFlag Timer1_Ovf; відбувається не від одного процесу до іншого, а від підпрограми обробки переривання до процесу.


Timer1 to Proc1

  1. Як і на попередніх осцилограмах, меандр на лінії IDLEHOOK припиняється при виникненні переривання.
  2. На вході в підрограму обробки переривання TIMER1_COMPA_vect() піднімається лінія T1PROC1, після чого викликом Timer1_Ovf.SignalISR(); посилається сигнал Proc1. Планувальник бачить необхідність перемикання процесів і активує запит переривання перемикання контекстів.
  3. Після виходу з переривання TIMER1_COMPA_vect() відпрацьовує переривання перемикання контекстів, керування отримує TProc1::Exec().
  4. Proc1 опускає рівень на лінії T1PROC1 і знову засинає викликом Timer1_Ovf.Wait(); до приходу сигналу. Довжина імпульсу на лінії T1PROC1 дає уявлення про мінімальний час затримки від апаратної події до того моменту, коли почне працювати код високопріоритетного процесу, що чекав на цю подію.
  5. В даному випадку інших готових до виконання процесів нема і другим перемиканням контекстів керування повертається до IdleProcess.
  6. TIdleProcess::Exec() відновлює роботу і на лінії IDLEHOOK знову з’являється меандр.

Запитання по цьому прикладу та порту scmRTOS для AVR та компілятора avr-gcc (WinAVR) можна задавати тут, в коментарях до сторінки.
Запитання по «scmRTOS взагалі» краще задавати у відповідному розділі на форумі electronix.ru.


© 2008-2010, Oleksandr Redchuk aka ReAl

scmRTOS

scmRTOS – це компактна проста ОСРЧ для мікроконтроллерів, створена Гарі Журовим (Harry Zhurov). Поточна версія — 4.00.
Існують порти scmRTOS для наступних серій мікроконтролерів:

  • ARM7 — GCC;
  • AVR (Atmel) — GCC, IAR;
  • Blackfin (Analog Devices) — VDSP;
  • Cortex-M3 — GCC, IAR;
  • Cortex-M0 — GCC (на даний момент розміщено в гілці pre-v400);
  • MSP430 (Texas Instruments) — GCC, IAR;
  • STM8 (ST Microelectronics) — IAR.

Використовуйте лінк Download GNU tarball в нижній частині сторінки для вибраного мікроконтролера або завантажуйте архів зі сторінки scmRTOS на sourceforge
Використовуйте сторінку trunk для отримання найсвіжіших версій.

З мікроконтролерів AVR підтримуютьcя «звичайні» megaAVR включно з ATmega256x.

Опис scmRTOS v4.00 російською та англійською мовами.
Сторінка проекту на sourceforge.net.
scmRTOS Wiki (англійською)
Група google для обговорння проекту (російською, краще підписатися на розсилку поштою, бо через web-інтерфейс половина листів не читається).
Розділ, присвячений scmRTOS, на форумі electronix.

scmRTOS може бути використано з Arduino, дивіться тему на форумі Arduino, сховище git та статтю про це російською мовою.

Тут я пропоную увазі детальне пояснення одного з поширюваних з системою прикладів 1-EventFlag.

Пояснення призначене для тих, хто ще не надто знайомий з роботою ОС з витісненням і «на ніжках» показує, що відбувається в системі. Для демонстрації процесів в приклад було внесено деякі зміни, в основному, додано індикацію стану системи на виводах мікроконтроллера для спостереження осцилографом/логічним аналізатором. Команди для індикації стану було додано також в процедуру перемикання контекстів (встановлення виводу першою командою макросу save_context та скидання останньою командою макросу restore_context в файлі OS_Target_asm.S). З розміщеного в репозиторії коду ці команди видалено.

[flagcounter image]