Вы её просто не умеете готовить. Как, видимо, и любую другую вытесняющую ОС, так как то же самое будет в любой другой независимо от языка реализации.
Если Вы «драйверные» по сути вещи будете запихивать в отдельные процессы с ожиданием посланного сообщения из тупого обработчика прерываний, то будет то же самое — большие задержки, большие расходы не переключение задач, на стеки процессов.
Если Вы «драйверные» вещи выделите в отдельные классы, как в обсуждениях по ссылкам в предыдущем моём сообщении, а в процесс будете отправлять уже «высокоуровневый» результат работы драйвера, то отрабатывать драйверные прерывания будут так же быстро, как и в программе без какой-либо ОС. Всю быструю работу будет делать драйвер, остальное — разбуженный результатом процесс. Это вполне реализуемо в рамках scmRTOS.
Не нравится отдельный драйверный класс — сделайте свой хитрый процесс. Раз он хитрый — Вам не удастся воспользоваться готовым шаблоном для стандарнтых процессов, но Вы тут так много говорили про С++, что у Вас не должно быть проблем сделать, например, такое (за основу взят пример 2 из пакета avr-gcc и проверено в железе):
CODE
//******************************************************************************
//* FULLNAME: Single-Chip Microcontroller Real-Time Operating System
//* NICKNAME: scmRTOS
//* PROCESSOR: AVR (Atmel)
//* TOOLKIT: avr-gcc (GNU)
//* PURPOSE: avr-gcc Port Test File
... порезано ...
//******************************************************************************
//---------------------------------------------------------------------------
#include <avr/io.h>
#include "pin_macros.h"
#include <scmRTOS.h>
#if scmRTOS_CONTEXT_SWITCH_SCHEME == 1
// for analog comparator initialisation in main()
#include <util/delay.h>
#endif
//---------------------------------------------------------------------------
// Sample target
// The sample is intended for following AVR microcontrollers:
// atmega48..atmega328
// atmega64, atmega128
// atmega640..atmega2561
// Some changes in register names may be needed for other AVRs.
#if defined(TIMSK1)
# define TIMER1_IE_REG TIMSK1
#elif defined(TIMSK)
# define TIMER1_IE_REG TIMSK
#else
# error "Timer1 interrupt mask register not defined"
#endif
//---------------------------------------------------------------------------
// "Hello, scope!" pins in pin_macros.h notation.
#define TIMER1_ISR D,5,H
#define TIMER1_TO_PROC1 B,0,H
#define PROC1 B,1,H
#define PROC2 B,2,H
#define PROC3 B,3,H
#define TIMER_HOOK B,4,H
#define IDLE_HOOK B,5,H
#define MAMONT_TRUNK C,5,H
//---------------------------------------------------------------------------
struct TMamont // data type for sanding by message
{
enum TSource { PROC_SRC, ISR_SRC } src;
int data;
};
//---------------------------------------------------------------------------
// Process types
// Два процесса стандартные
typedef OS::process<OS::pr1, 160> TProc2;
typedef OS::process<OS::pr2, 120> TProc3;
// Третий имеет методы для общения с себе подобными и метод, отрабатывающий
// «в ожидании НАСТОЯЩЕГО прерывания»
// avr-gcc не позволяет объявить статический член класса обработчиком прерывания,
// приходится пользоваться помощью друга
OS_INTERRUPT void TIMER1_COMPA_vect();
// Наследуем от базового типа процесса scmRTOS
class TProc1 : public OS::TBaseProcess
{
friend void TIMER1_COMPA_vect();
public:
// Раз не воспользовались шаблоном стандратного процесса — солнце закатываем вручную
TProc1()
: OS::TBaseProcess( &Stack[stack_size/sizeof(stack_item_t)],
OS::pr0, reinterpret_cast<void (*)()>(exec) )
{
TCCR1B = (1 << WGM12) | (1 << CS10); // CTC mode, clk/1
OCR1A = 40000U;
TIMER1_IE_REG = (1 << OCIE1A); // Timer1 OC interrupt enable
}
// Это для вызова из других процессов
static void send_message(TMamont::TSource source, int data);
private:
static const size_t stack_size = 120;
OS_PROCESS static void exec();
static TMamont Mamont;
static OS::message<TMamont> MamontMsg;
// А это НАСТОЯЩЕЕ прерывание
INLINE void compa_isr();
stack_item_t Stack[stack_size/sizeof(stack_item_t)];
};
TProc1 Proc1;
TMamont TProc1::Mamont;
OS::message<TMamont> TProc1::MamontMsg;
void TProc1::send_message(TMamont::TSource source, int data)
{
TMamont m;
m.src = source;
m.data = data;
MamontMsg = m;
MamontMsg.send();
}
// Этот метод будет вызываться из НАСТОЯЩЕГО прерывания до любого перепланирования и т.п.
// Отрабатывает максимально быстро и может накопить работу (например, принять весь пакет
// по каналу связи) и только потом послать результирующее сообщение.
void TProc1::compa_isr()
{
TMamont m;
m.src = TMamont::ISR_SRC;
m.data = 10;
MamontMsg = m;
ON(MAMONT_TRUNK);
MamontMsg.send_isr();
}
//---------------------------------------------------------------------------
// Process objects
//
TProc2 Proc2;
TProc3 Proc3;
//---------------------------------------------------------------------------
int main()
{
// Start System Timer
TIMER0_CS_REG = (1 << CS01) | (1 << CS00); // clk/64
TIMER0_IE_REG |= (1 << TOIE0);
#if scmRTOS_CONTEXT_SWITCH_SCHEME == 1
// Setup analog comparator as software interrupt source
#if PORT_TOGGLE_BY_PIN_WRITE // see pin_macros.h for PORT_TOGGLE_BY_PIN_WRITE definition and sing
ACSR = (1 << ACBG); // Ref ON, interrupt on both edges
#else
ACSR = (1 << ACBG) | (1 << ACIS1); // Ref ON, falling edge
#endif
DRIVER(RAISE_PIN,OUT); // AIN1 - output
// analog comparator propagation and synchronization delay
_delay_us(2);
ACSR |= (1 << ACI); // needed for chips with improved sbi/cbi behavior
ACSR |= (1 << ACIE);
#endif
DRIVER(TIMER1_ISR,OUT);
DRIVER(TIMER_HOOK,OUT);
DRIVER(IDLE_HOOK,OUT);
DRIVER(MAMONT_TRUNK,OUT);
//
OS::run();
}
//---------------------------------------------------------------------------
void TProc1::exec()
{
DRIVER(PROC1,OUT);
DRIVER(TIMER1_TO_PROC1,OUT);
for(;;) {
OFF(PROC1);
MamontMsg.wait();
ON(PROC1);
OFF(TIMER1_TO_PROC1);
MamontMsg.out(Mamont);
if(Mamont.src == TMamont::PROC_SRC) {
OFF(MAMONT_TRUNK);
} else {
OFF(MAMONT_TRUNK);
ON(MAMONT_TRUNK);
OFF(MAMONT_TRUNK);
}
}
} // TProc1::exec()
//---------------------------------------------------------------------------
namespace OS {
template<> OS_PROCESS void TProc2::exec()
{
DRIVER(PROC2,OUT);
for(;;) {
OFF(PROC2);
sleep(20);
ON(PROC2);
}
} // TProc2::exec()
} // namespace OS
//---------------------------------------------------------------------------
namespace OS {
template<> OS_PROCESS void TProc3::exec()
{
DRIVER(PROC3,OUT);
for(;;) {
OFF(PROC3);
sleep(1);
ON(PROC3);
ON(MAMONT_TRUNK);
Proc1.send_message(TMamont::PROC_SRC, 5); // обращаемся к процессу от другого процесса
}
} // TProc3::exec()
} // namespace OS
//---------------------------------------------------------------------------
OS_INTERRUPT void TIMER1_COMPA_vect()
{
ON(TIMER1_ISR);
ON(TIMER1_TO_PROC1);
OS::TISRW ISRW;
// Часть логики процесса работает непосредственно в прерывании без перепланирования
// и без переключения задач
Proc1.compa_isr();
OFF(TIMER1_ISR);
}
Тут имеем быструю реакцию (уже не класса драйвера, а непосредственно класса процесса) на прерывание. Но не в его методе exec(), предназначенном для работы в рамках
ненастоящего прерывания вытесняющего планирования ОС, а в его методе compa_isr().
Всё как Вы хотели «но не знали как и постеснялись спросить».
Если ядро имеет приоритетную систему прерываний, как в
современных "Электроника-60", 1801ВМ, MSP430,
i8051 (вычёркиваем, C++ для него нет и scmRTOS не спортится, но на С всё то же в виде модулей и инкапсуляцией static-об’ектами это работает), ARM, то этот подход, как и с классами драйверов, автоматически ею воспользуется. Нет — не судьба. Но страдать от необходимости «
идти длинным путем через OS, через диспетчер, через полинг, через арбитр приоритетов....» не приходится и на AVR.
Более того, в классе драйвера UART для работы в рамке SLIP в передатчике у меня два isr-метода. Метод udre_isr() вообще «внеосевой», оне не пользуется сервисами ОС и очень лёгкий, после него не производится перепланирование (оно и не нужно, данное прерывание ничего не поменяло в состояниях процессов). А вот метод txc_isr() уже сообщает наверх о том, что пакет передан полностью, вызывает сервисы ОС и после него происходит перепланирование.
Цитата(Aprox @ Apr 14 2012, 12:01)

Точнее сказать, без привычной из прошлого OS.
Из какого прошлого? Кому привычной? Привычной нам ОС или
неправильного её использования Вами из-за привычной работы без ОС?
В RT11 (FB) было то же самое — драйвера отрабатывали быстро, при необходимости было более медленное переключение на ожидающую задачу. Без С++ и
современных чипов.
А то, что Вы описали — это таки не вытесняющая ОС вообще. Это расталкивание всей работы по обработчикам прерываний с оставшейся программой без каких-либо признаков ОС либо с зачатками кооперативной ОС, пользующейся результатом работы выполненной в прерываниях обработки. Вполне себе решение, пользовался раньше и пользуюсь сейчас. Без ОС или с кооперативной ОС часто иначе невозможно.
Если некоторые поселенные в прерывания задачи довольно длительны, то такой подход просит приоритетной системы вложенных прерываний. да. Но никаких
современных чипов для этого не нужно, это есть в MSP430. Это было в 1801ВМ1, ВМ2 30+ лет назад. Там, кстати, в RT11 для драйверов готовые макросы были для регулирования приоритета обработчика, самое важное он делал на большом приоритете, потом снижал приоритет ядра до более низкого и его могли прервать даже те прерывания, которых он победил при первоначальном арбитраже. То же самое я делал на i8051 — после критической по времени части обработчика очищал уровень приоритета и данный обработчик уже могли прервать не только более приоритетные прерывания, но и вобще все, т.е. я снижал уровень приоритета обработчика прерываний до приоритета основного кода. Иногда при этом даже то же самое прерывание прерывало как бы само себя, но шло при этом по другой ветке (по бедности — таймеров не хватало, вот и было на один таймер навешано несколько задач разной периодичности и длительности). Не совсем то, что было в 1801ВМ или что есть у MSP430 или
современных чипов, но это именно эта идеология.