Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: scmRTOS холостой ход и системный таймер
Форум разработчиков электроники ELECTRONIX.ru > Cистемный уровень проектирования > Операционные системы > scmRTOS
Acvarif
"Продолжаем разговор" как говорил Карлсон.
Запустил ОСь на mega128a в WinAvr (в скрепке проект - сделан на базе http://real.kiev.ua/scmrtos/1-eventflag/)

В железе холостой ход явно просматривается, а прерываний системного таймера нет. Все, что зависит от него (это proc1, proc2 ..) естественнго не работает.
Поскольку нет отладчика то понять в чем дело сложно.

В IAR (v5501) ОСь не работает совсем (проект приложен в скрепке). В проекте сделана визуализация холостого хода и переполнения системного таймера (чего уж может быть проще). Поскольку в железе не видать не только системного таймера, но и холостого хода то получается, что зацикливание происходит в OS::Run(); Подсобите please разобраться ...

Спасибо.
Acvarif
ОСь таки запустилась. Проблема была таки в компиляторе. Он не умеет правильно отличать mega128a от 128, хотя они ничем не отличаются кроме некоторых электрических характеристик (пример slon 1-EventFlag для mega128a, в настройках компилятора IAR AVR 5501,5511 нужно ставить mega128 в скрепке ).

Просмотрев в железе прерывания системного таймера стало чуть грустно.
Прерывания системного таймера (период 1,2 ms) явно нестабильны, хотя вроде ничего на прерывания T0 не должно влиять.
Тоесть использовать системные тики для каких-либо более менее точных отсчетов нельзя.
Но посмотрев на взаимодействие между вторым и третьим процессом особой нестабильности не заметил. ОСь начинает нравиться.
Код
template<> void TProc2::Exec()
{
    for(;;)
    {
      ef.Wait();
      PORTC |= (1 << 3);

    }
}
//---------------------------------------------------------------------------
template<> void TProc3::Exec()
{
    for(;;)
    {

       Sleep(20);
       ef.Signal();
      PORTC &= ~(1 << 3);
    }
}


Так до сих пор и не понял зачем в примере нужен аналоговый компаратор?
Код
    ACSR |= (1 << ACBG) | (1 << ACIE); /* Ref ON, IE ON */  
    DDRB |= (1 << 4);                  /* AIN1*/

Если закоментировать этот код ничего не изменится.
В документацци сказано о переключении контекстов. Дергание ногой должно вызывать прерывания по компаратору и соответственно переключение контекстов.
Но где это дергание происходит? И какая все же разница между контекстом и процессом? Я так понимаю, что процесс это все вместе взятое - нить со своими переменными, регистрами стеком.



Сергей Борщ
QUOTE (Acvarif @ Jul 6 2011, 11:29) *
Так до сих пор и не понял зачем в примере нужен аналоговый компаратор?
Посмотрите внимательно в scmRTOS_config.h чему равно scmRTOS_CONTEXT_SWITCH_SCHEME. Если 0, то компаратор не нужен. Если 1, то таки да, его прерывание переключает контекст.
QUOTE (Acvarif @ Jul 6 2011, 11:29) *
Но где это дергание происходит?
Смотрите OS_Kernel.h, там есть строки
CODE
void OS::TKernel::SchedISR()
{
    TPriority NextPrty = GetHighPriority(ReadyProcessMap);
    if(NextPrty != CurProcPriority)
    {
        SchedProcPriority    = NextPrty;
        RaiseContextSwitch();
    }
}
Вот RaiseContextSwitch() и есть дерганье ногой. Ищите его определение в OS_Target.h
QUOTE (Acvarif @ Jul 6 2011, 11:29) *
Я так понимаю, что процесс это все вместе взятое - нить со своими переменными, регистрами стеком.
Контекст - содержимое регистров для процесса (плюс указатель стека, который в "нормальных" процессорах входит в регистры ядра).
Acvarif
Спасибо. Стало немного светлее.

Цитата(Сергей Борщ @ Jul 6 2011, 11:50) *
Посмотрите внимательно в scmRTOS_config.h чему равно scmRTOS_CONTEXT_SWITCH_SCHEME. Если 0, то компаратор не нужен. Если 1, то таки да, его прерывание переключает контекст.


Код
#define  scmRTOS_CONTEXT_SWITCH_SCHEME      1

Получается, что если scmRTOS_CONTEXT_SWITCH_SCHEME = 1
то функция RaiseContextSwitch() просто разрешает глобальные прерывания

Код
#if scmRTOS_CONTEXT_SWITCH_SCHEME == 1

    INLINE inline void RaiseContextSwitch() { SPM_CONTROL_REG |= (1 << SPMIE);  } // enable SPM interrupt
    INLINE inline void BlockContextSwitch() { SPM_CONTROL_REG &= ~(1 << SPMIE); } // disable SPM interrupt


Кто или что тогда всетаки переключает процессы? Или с какой частотой переключаются процессы? Кто ее формирует?
Я так понимаю, что переключатель контекста и есть переключатель процессов? Может глупость сморозил...
MrYuran
Цитата(Acvarif @ Jul 6 2011, 14:35) *
Кто или что тогда всетаки переключает процессы? Или с какой частотой переключаются процессы? Кто ее формирует?
Я так понимаю, что переключатель контекста и есть переключатель процессов? Может глупость сморозил...

Переключается по таймеру. Таймер дёргает прерывание (обычно самое низкоприоритетное), по которому вызывается диспетчер процессов.
По-моему, так. (давно за инструмент не садился)
Acvarif
Цитата(MrYuran @ Jul 6 2011, 13:40) *
Переключается по таймеру. Таймер дёргает прерывание (обычно самое низкоприоритетное), по которому вызывается диспетчер процессов.
По-моему, так. (давно за инструмент не садился)


Примерно так и думал. В данном случае получается, что переключателем процессов является Таймер 0 (он же системный таймер или формирователь тиков)?

Зачем тогда еще один вариант переключения процессов (в данном примере scmRTOS_CONTEXT_SWITCH_SCHEME = 1 не работает) внешнее дергание ноги -> вызов таким образом какого нибудь низкоуровневого прерывания для переключения между процессами? Что это дает? Освобождает как то системный таймер?
Сергей Борщ
QUOTE (Acvarif @ Jul 6 2011, 13:35) *
Получается, что если scmRTOS_CONTEXT_SWITCH_SCHEME = 1
то функция RaiseContextSwitch() просто разрешает глобальные прерывания
Вы, похоже, взяли исходник из другого примера или же настройка компаратора - рудимент от предыдущей версии.
CODE
#if scmRTOS_CONTEXT_SWITCH_SCHEME == 1

    INLINE inline void RaiseContextSwitch() { SPM_CONTROL_REG |= (1 << SPMIE);  } // enable SPM interrupt
    INLINE inline void BlockContextSwitch() { SPM_CONTROL_REG &= ~(1 << SPMIE); } // disable SPM interrupt

Тут разрешаются не глобальные прерывания, а прерывание по окончанию записи во флешь. Этот такой трюк - флаг этого прерывания при нормальной работе всегда взведен, и разрешение этого прерывания (естетсвенно, при разрешенных глобальных прерываниях) вызовет переход на его обработчик. А уже в обработчике произойдет, собственно, переключение контекстов. Следствием которого является переключение текущего процесса. Если же переключение контекстов потребовалось во время обработки какого-либо прерывания, то глобально прерывания в этот момент запрещены и будут разрешены по команде RETI. В этот-то момент и вызовется обработчик.
QUOTE (Acvarif @ Jul 6 2011, 13:35) *
Кто или что тогда всетаки переключает процессы? Или с какой частотой переключаются процессы? Кто ее формирует?
Это вытесняющая ОСь. Здесь переключение происходит в тот момент, когда процесс отдает управление в ожидании какого-либо сервиса либо уходя в спячку либо если произошло событие (вызов сервиса из прерывания или текушего процесса), требующее пробуждения более приоритетного процесса.
Acvarif
Цитата(Сергей Борщ @ Jul 6 2011, 14:47) *
Тут разрешаются не глобальные прерывания, а прерывание по окончанию записи во флешь. Этот такой трюк - флаг этого прерывания при нормальной работе всегда взведен, и разрешение этого прерывания (естетсвенно, при разрешенных глобальных прерываниях) вызовет переход на его обработчик. А уже в обработчике произойдет, собственно, переключение контекстов. Следствием которого является переключение текущего процесса. Если же переключение контекстов потребовалось во время обработки какого-либо прерывания, то глобально прерывания в этот момент запрещены и будут разрешены по команде RETI. В этот-то момент и вызовется обработчик.
Это вытесняющая ОСь. Здесь переключение происходит в тот момент, когда процесс отдает управление в ожидании какого-либо сервиса либо уходя в спячку либо если произошло событие (вызов сервиса из прерывания или текушего процесса), требующее пробуждения более приоритетного процесса.

Спасибо. Еще немного посветлело.

Код
//    scmRTOS Context Switch Scheme
//
//    The macro defines a context switch manner. Value 0 sets direct context
//    switch in the scheduler and in the OS ISRs. This is the primary method.
//    Value 1 sets the second way to switch context - by using of software
//    interrupt. See documentation fo details.
//
//
#define  scmRTOS_CONTEXT_SWITCH_SCHEME      1


У меня все работает одинаково (во всяком случае внешне) при 0 и при 1

Получается,что в случае когда scmRTOS_CONTEXT_SWITCH_SCHEME = 1 - выбрана передача управления на основе программного прерывания. Поскольку все при этом работает, не пойму какого прерывания?
Когда scmRTOS_CONTEXT_SWITCH_SCHEME = 0 - выбрана передача управления на основе прерывание по окончанию записи во флешь.
Или все наоборот?
ReAl
Цитата(Сергей Борщ @ Jul 6 2011, 14:47) *
Вы, похоже, взяли исходник из другого примера или же настройка компаратора - рудимент от предыдущей версии.
В AVR/IAR 3.10 -- рудимент после замены на прерывание SPM_READY. Когда я это обнаружил, то уже думал, что вот-вот 4.00 выйдт и не стал править. А потом забыл.
В AVR/GCC 3.10 всё нормально и в примере 2, в котором компаратор оставлен для примера, инициализация компаратора охвачена
#if scmRTOS_CONTEXT_SWITCH_SCHEME == 1

В pre-400 поправлено и для AVR/IAR.

Acvarif, кстати, в pre-400 и в AVR/IAR пример 1-EventFlag приведён в почти полное соответствие с упомянутой в первом сообщении статьёй. "Почти", так как в порте в репозитории в переключатель контекста в OS_Target_asm, естественно, не вставлено махание ножкой осциллографу.

Цитата(Acvarif @ Jul 6 2011, 16:10) *
Код
#define  scmRTOS_CONTEXT_SWITCH_SCHEME      1

У меня все работает одинаково (во всяком случае внешне) при 0 и при 1
Потому что в примерах реализованы оба способа.

Цитата(Acvarif @ Jul 6 2011, 16:10) *
Получается,что в случае когда scmRTOS_CONTEXT_SWITCH_SCHEME = 1 - выбрана передача управления на основе программного прерывания. Поскольку все при этом работает, не пойму какого прерывания?
Задаётся в scmRTOS_TARGET_CFG.h, например,
Код
#define CONTEXT_SWITCH_ISR_VECTOR  SPM_READY_vect
или
Код
#define CONTEXT_SWITCH_ISR_VECTOR  ANA_COMP_vect
Это дело передаётся в OS_Target_asm.S (.s90 для IAR), где и используется для организации входа в обработчик прерывания.
Acvarif
Спасибо.

Значит в примере от IAR 310 пропущено только дрыгание ногой по прерываниям компаратора при scmRTOS_CONTEXT_SWITCH_SCHEME 1?
Или я опять недопонял...

Для уточнения
если
Код
#define  scmRTOS_CONTEXT_SWITCH_SCHEME      0

переключение контекстов происходит по прерыванию записи во флешь (он - вектор прерывания все время взведен)
если
Код
#define  scmRTOS_CONTEXT_SWITCH_SCHEME      1

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

Посмотрел pre 400, там код под IAR очень похож на WinAvr:

Код
//---------------------------------------------------------------------------
//  "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


//---------------------------------------------------------------------------
//
//      Process types
//

// demonstrate process switching from Proc2 to Proc3 in sleep() or ef.signal() call
#if PROC2_HIGHER_THAN_PROC3
# define PROC2_PRIO OS::pr1
# define PROC3_PRIO OS::pr2
#else
# define PROC2_PRIO OS::pr2
# define PROC3_PRIO OS::pr1
#endif


typedef OS::process<OS::pr0, 120, 32> TProc1;
typedef OS::process<PROC2_PRIO, 160, 32> TProc2;
typedef OS::process<PROC3_PRIO, 120, 32> TProc3;

template<> void TProc1::exec();
template<> void TProc2::exec();
template<> void TProc3::exec();

//---------------------------------------------------------------------------
//
//      Process objects
//
TProc1 Proc1;
TProc2 Proc2;
TProc3 Proc3;

//---------------------------------------------------------------------------
tick_count_t tick_count;    // global variable for OS::GetTickCount testing

OS::TEventFlag Timer1_Ovf;  // set in TIMER1_COMPA_vect(), waited in Proc1
OS::TEventFlag ef;          // set in Proc3, waited in Proc2

//---------------------------------------------------------------------------
int main()
{
    TCCR1B = (1 << WGM12) | (1 << CS10);    // CTC mode, clk/1
    OCR1A  = 40000U;
    TIMSK = (1 << OCIE1A); // Timer1 OC interrupt enable

    // Start System Timer
    TCCR0  = (1 << CS01) | (1 << CS00); // clk/64
    TIMSK |= (1 << TOIE0);

    DRIVER(TIMER1_ISR,OUT);
    DRIVER(TIMER_HOOK,OUT);
    DRIVER(IDLE_HOOK,OUT);
    //
    OS::run();
}


Правда компилится без проблем
Я так понял, что там для идентичности с gcc добавлены функции типа DRIVER(TIMER1_ISR,OUT);
и др.
ReAl
Цитата(Acvarif @ Jul 7 2011, 10:37) *
Значит в примере от IAR 310 пропущено только дрыгание ногой по прерываниям компаратора при scmRTOS_CONTEXT_SWITCH_SCHEME 1?
Нет. В IAR310 вариант "1" переведен с аналогового компаратора на готовность записи во флеш, но из main недовычищено то, что касалось компаратора.

Цитата(Acvarif @ Jul 7 2011, 10:37) *
если
Код
#define  scmRTOS_CONTEXT_SWITCH_SCHEME      0
переключение контекстов происходит по прерыванию записи во флешь (он - вектор прерывания все время взведен)
если
Код
#define  scmRTOS_CONTEXT_SWITCH_SCHEME      1
по прерываниям от аналогового компаратора
В последнем случае немного непонятно. Получается, что прерывания по аналоговому компаратору тоже должны быть все время взведены?
Вобщем и целом тогда особой разницы в scmRTOS_CONTEXT_SWITCH_SCHEME нет?
В случае "0" переключение производится прямым вызовом os_context_switcher.
В случае "1" переключение производится обработчиком специального прерывания, которое возбуждается при помощи raise_context_switch. Какое именно прерывание будет задействовано (а хоть и от свободного канала output compare) -- зависит от настроек проекта в scmRTOS_TARGET_CFG.h
В AVR/IAR-овских примерах было всё на компараторе, потом всё перевелось на запись во флеш. В AVR/GCC-шніх во втором примере оставлен компаратор, в остальных -- флеш. Сравните файлы scmRTOS_TARGET_CFG.h от первого и второго примера AVR/GCC (не важно, 310 или pre-400).
Для компаратора raise делается дёрганьем ноги, а само прерывание всегда разрешено. Для вектора записи во флеш запрос всегда взведён, а raise делается разрешением.

Цитата(Acvarif @ Jul 7 2011, 10:37) *
Посмотрел pre 400, там код под IAR очень похож на WinAvr:
...
Я так понял, что там для идентичности с gcc добавлены функции типа DRIVER(TIMER1_ISR,OUT); и др.
"Волковские" макросы из pin_macros.h добавлены для простоты обеспечения идентичности.
Просто скопирован кусок из AVR/GCC-шных примеров для полного соответствия поведения, чтобы можно было пользоваться статьёй-описанием для обеих компиляторов.
Если (когда wink.gif ) доберусь до CM3-шного примера, то тогда перепишу под тамошний pin.h
Acvarif
Цитата
В случае "0" переключение производится прямым вызовом os_context_switcher.
В случае "1" переключение производится обработчиком специального прерывания, которое возбуждается при помощи raise_context_switch. Какое именно прерывание будет задействовано (а хоть и от свободного канала output compare) -- зависит от настроек проекта в scmRTOS_TARGET_CFG.h


Спасибо. Нашел.
Код
#if scmRTOS_CONTEXT_SWITCH_SCHEME == 0
     public  OS_ContextSwitcher
#else
     extern  OS_ContextSwitchHook
#endif


Тоесть при scmRTOS_CONTEXT_SWITCH_SCHEME == 1 переключать контексты можно будет только извне дергая ногой, например одного из входов компаратора?
Если это так то с какой частотой нужно ее дергать?
Хотя я сам сомневаюсь в том, что написал...
Скорее всего если просто сделать ACSR = (1 << ACBG) и (так сказать изнутри) установить одну из ног компаратора в еденицу то тогда он постоянно будет находиться в состоянии прерывания, а значит будет extern OS_ContextSwitchHook.
И в этом неуверен...
Как все же правильно?


Цитата(ReAl @ Jul 7 2011, 11:49) *
В AVR/IAR-овских примерах было всё на компараторе, потом всё перевелось на запись во флеш. В AVR/GCC-шніх во втором примере оставлен компаратор, в остальных -- флеш. Сравните файлы scmRTOS_TARGET_CFG.h от первого и второго примера AVR/GCC (не важно, 310 или pre-400).
Для компаратора raise делается дёрганьем ноги, а само прерывание всегда разрешено. Для вектора записи во флеш запрос всегда взведён, а raise делается разрешением.

Да, действительно так. Спасибо.
Код
#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 new chips with improved sbi/cbi behavior
    ACSR |= (1 << ACIE);
#endif


Acvarif
Всем спасибо.

Появилось кое-какое понимание.

Пытаюсь организовать простую передачу данных USART по прерыванию таймера 1.
Для этого попытался организовать ассемблерную инициализацию порта в отдельном файле
с надеждой, что там будет еще всяко разное
Код
USART_Init:
  out UBRRH, r17
  out UBRRL, r16
  ldi r16, (1<<RXEN)|(1<<TXEN)
  out UCSRB,r16
  ldi r16, (1<<USBS)|(3<<UCSZ0)
  out UCSRC,r16
  ret
end

Возникла проблема с подключением этого файла к main. Сплошные ошибки типа Error[Pe077]: this declaration has no storage class or type specifier
Читал доку на OCЬ. Не нашел как можно подключить к проекту отдельный файл (cpp или asm). Или все нужно прописывать в самой main? А если понадобится много asm функций?
ReAl
1. Подключение файлов к проекту смотрят не в доке на ось, а в доке на среду разработки.
2. А назачем для такого асм?
Код
void uart_init(uint16_t baud_div)
{
        UBRRH = baud_div >> 8;
        UBRRL = baud_div;
        UCSRB = (1<<RXEN)|(1<<TXEN);
        UCSRC = (1<<USBS)|(3<<UCSZ0);
}

avr-gcc -Os -S -mmcu=atmega8 uartinit.c
Код
uart_init:
/* prologue: function */
/* frame size = 0 */
    out 64-32,r25
    out 41-32,r24
    ldi r24,lo8(24)
    out 42-32,r24
    ldi r24,lo8(14)
    out 64-32,r24
/* epilogue start */
    ret
Acvarif
Да, понял. Спасибо.
С IAR плотно работал несколько лет тому назад. Забывается блин...
После запуска ОСи возникла другая проблема - объектное программирование.
Оно еще в PHP мне не нравилось. Наверное потому, что толком его не понимал.
Поскольку все же решил сделать задачу на scmRTOS придется почитать немного буквари...
Сделал так:
Код
void USART_Init( unsigned int baudrate, bool usart_number)
{
    if(!usart_number)
    {
        // установка частоты бод
        UBRR0H = (unsigned char) (baudrate>>8);                  
        UBRR0L = (unsigned char) baudrate;
        // Разрешить передачу
        UCSR0B = ( 1 << TXEN0 );
        // Установка формата фреймов: 8 data 1stop
        UCSR0C = (1<<UCSZ01)|(1<<UCSZ00);              
    }
    else
    {  
        // установка частоты бод
        UBRR1H = (unsigned char) (baudrate>>8);                  
        UBRR1L = (unsigned char) baudrate;
        // Разрешить прием и передачу
        UCSR1B = ( ( 1 << RXEN1 ) | ( 1 << TXEN1 ) );
        // Установка формата фреймов: 7 data 2stop
        UCSR1C = (1<<USBS1)|(1<<UCSZ11);              
    }        
}

Поставил перед main.
Задача - обмен по Modbus по USART0, приведение в нужный вид полученых данных и передача в PC по USART1.
Обмен по Modbus с периодом 400 мс. Передача в PC с периодом 100 мс (100мс выглядят глупо, но это для иденчности со старым модулем).
Наверное можно сделать так:
По прерываниям T1 переходить в поцесс1 делать полный обмен по Modbus и сохранять полученные данные в глобальн. массиве.
В процессе 2 проспав нужное количество тиков системного таймера преобразовать в нужный вид данные из гл. массива и передать все в PC
Приоритетным в этом случае сделать процесс1 - пока идет обмен по модбас в PC ничего не передавать.
Первое, что пришло в голову. Может глупость...
Прошу прокомментировать.
Acvarif
Пролем с IAR AVR OCью (310) пока нет.
По ходу возникают всякие вопросы.
1. Могут ли разные процессы без ущерба себе использоваться одни и те же глобальные константы, типа
Код
const char __flash cTrPr15[5] = {0x55,0x34,0x0a,0x41,0xd4};

2. Можно ли в разных процессах использовать одну и ту же глобальную функцию, например
Код
unsigned char USART_Receive( void )
{
  ....
}
ReAl
1. А почему нет? Даже не-константы можно, только во избежание гонок защищаться от записи во время других операций (других записей или других чтений).

2. Если функция реентрабельна. Не все функции стандартной библиотеки реентрабелны, например, strtok() нельзя звать из двух процессов веремешку.
Acvarif
Цитата(ReAl @ Jul 9 2011, 12:45) *
1. А почему нет? Даже не-константы можно, только во избежание гонок защищаться от записи во время других операций (других записей или других чтений).

Понял. Спасибо. Наверное имеется ввиду Мутекс?

Цитата
2. Если функция реентрабельна. Не все функции стандартной библиотеки реентрабелны, например, strtok() нельзя звать из двух процессов вперемешку.

Спасибо.

Пытаюсь до конца понять такую штуку:
Если один процесс совершает омен по USATR0 и полученные данные помещает в глобальный массив типа
A[25], то может ли другой процесс достать эти данные из этого же массива, выполнить с ними действия и дальше передать по USART1? Конечно имеется ввиду, что будет обеспечена блокировка совместного доступа через Мутекс.
Если да, то получается, что к глобалам (в том числе и к глобальным функциям если они реентрабельны) в принципе имеют доступ все процессы?
Тогда встает вопрос, зачем организовывать возможность передачи данных между процессами (например черех message) если все можно крутить через глобальные буфера? Например (могу шибаться) в QNX глобалы из процессов не доступны вообще.
ReAl
Конечно может.

Цитата(Acvarif @ Jul 9 2011, 14:08) *
Например (могу шибаться) в QNX глобалы из процессов не доступны вообще.
Ну так (глобальный) объект message и является таким буфером. Только с дополнительным сервисом, чобы закат солнца вручную не организовывать.

Цитата(Acvarif @ Jul 9 2011, 14:08) *
Например (могу шибаться) в QNX глобалы из процессов не доступны вообще.
Интересно, как они могут на уровне ОС запретить то, что компилятор разрешает :-)
Другое дело, что они могут «не рекомендовать» такое использование. но сделать невозможным -- никак.
Acvarif
Цитата(ReAl @ Jul 9 2011, 14:57) *
Интересно, как они могут на уровне ОС запретить то, что компилятор разрешает :-)
Другое дело, что они могут «не рекомендовать» такое использование. но сделать невозможным -- никак.


Тоже так думал. Но оказывается так таки оно и есть. Потому, как в Linux (в том числе и Windows) и т. п. процессы это разные приложения у каждого из которых своя область видимости. Это по сути разные программы, типа PCAD и Word. В sсmRTOS процессы это потоки запущенные из одного места (не понимаю почему их назвали процессами). А у потоков область видимости на глобалы одна и та же. Поэтому все процессы (потоки) имеют достум ко всему, что объявлено перед main. Если что не так поправьте меня.
Ну да ладно... это все не главное. Главное, что потоки работают неплохо.
1. Один из них по прерываниям T1 передает в PC данные по USART1
2. Другой, асинхронно с первым, проспав нужне количество тиков T0 (0.5 sec) формирует запрос по Modbus (Usart0).
3. Третий по прерываниям принимает и обрабатывает данные от Modbus (формирует массив для передачи в первый процесс). Первый данные должен будет передать в PC.

Вот только пока не уяснил как лучше передать даные из 3 в 1 - через глобальный буфер или методом типа meccage? Как лучше?
dxp
Цитата(Acvarif @ Jul 12 2011, 00:25) *
В sсmRTOS процессы это потоки запущенные из одного места (не понимаю почему их назвали процессами).

А почему они потоки, а не процессы?
Acvarif
Цитата(dxp @ Jul 12 2011, 13:23) *
А почему они потоки, а не процессы?


Думаю потому, что у потока область видимости, например на глобалы одна и та же. Потоки могут работать с глобалами без особых проблем.
В ОСях процессы это обычно отдельные приложения (в каждом из них можно запускать сколько угодно, в разумных пределах, потоков).
Могу ошибаться...
MrYuran
Цитата(Acvarif @ Jul 12 2011, 17:46) *
Думаю потому, что у потока область видимости, например на глобалы одна и та же. Потоки могут работать с глобалами без особых проблем.
В ОСях процессы это обычно отдельные приложения (в каждом из них можно запускать сколько угодно, в разумных пределах, потоков).
Могу ошибаться...

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

В данном случае таски - это именно процессы, т.к. реализуются средствами оси.
А вот если внутри процесса сделать хотя бы простецкую карусельку - это уже будут потоки.
Acvarif
Имеется три процесса.
1. Первый передача запросов Модбас (USART0) после спячки Sleep(900);

Код
// Передача команд по MODBUS
template<> void TProc1::Exec()
{

    for(;;)
    {
        Sleep(900);
        // Запретить прием
        UCSR0B &= ~( 1 << RXEN0 );
        // Запретить прерывания на прием USART0
        UCSR0B &= ~(1<<RXCIE0);
//---------------------------------------------------------------------------
        ...... передача по USART0 типа
      // Ждять пока будет пуст буфер передачи
      while ( !(UCSR0A & (1<<UDRE0)) );                             
      // Передача байта
      UDR0 = data;                     

//---------------------------------------------------------------------------
        // Разрешить прием  
        UCSR0B |= (1 << RXEN0);
        // Разрешить прерывания на прием USART0
        UCSR0B |= (1<<RXCIE0);
    }
}


2. Второй передача данных в PC (USART1) по прерыв. таймера 1 проспав Sleep(150);

Код
template<> void TProc2::Exec()
{
    __watchdog_reset();

    unsigned char i;
    
    for(;;)
    {
        // Ожидание Timer1_CompA через 90 мс  
        Sleep(150);
        Timer1_CompA.Wait();
        .... пердача типа
        while ( !(UCSR1A & (1<<UDRE1)) );                             
        UDR1 = data;         
     }
}


3. Третий прием данных USART0 по прерываниям приема (заполнения приемного буфера)

Код
// Прием по Modbus
template<> void TProc3::Exec()
{
    for(;;)
    {
//        Sleep(1);
        // Сброс флага приема
        Usart0_rxc.Wait();
        cRxBuf[cRxBufCount] = UDR0;
        cRxBufCount++;
    }
}


Сами прерывания

Код
//---------------------------------------------------------------------------
#pragma vector=TIMER1_COMPA_vect
OS_INTERRUPT void Timer1_period_ISR()
{
    OS::TISRW_SS ISRW;

    ENABLE_NESTED_INTERRUPTS();

    Timer1_CompA.SignalISR();
}
//---------------------------------------------------------------------------
#pragma vector=USART0_RXC_vect
OS_INTERRUPT void Usart0_rxc_ISR()
{
    OS::TISRW_SS ISRW;

    ENABLE_NESTED_INTERRUPTS();

    Usart0_rxc.SignalISR();
}


В таком виде все глохнет при попадании первых байт в приемный буфер USART0
Приоритеты процессов выставлены по очереди 1,2,3.

Подскажите пожалуйста где я ошибаюсь?

AHTOXA
В прерывании Usart0_rxc_ISR() надо вычитывать UDR0, иначе не сбрасывается флаг прерывания:
Цитата
When interrupt-driven data reception is used, the receive complete routine
must read the received data from UDR in order to clear the RXC Flag, otherwise a new interrupt
will occur once the interrupt routine terminates.

Может всё же почитаете документацию на процессор, или вы собираетесь весь проект делать методом тыка с помощью конфы?
Acvarif
Цитата(AHTOXA @ Jul 13 2011, 15:15) *
В прерывании Usart0_rxc_ISR() надо вычитывать UDR0, иначе не сбрасывается флаг прерывания:

Может всё же почитаете документацию на процессор, или вы собираетесь весь проект делать методом тыка с помощью конфы?


Спасибо.
Читал когда-то. Видно порядком подзабыл.
Помогло, только без вложенных прерываний.
Код
#pragma vector=USART0_RXC_vect
OS_INTERRUPT void Usart0_rxc_ISR()
{
    OS::TISRW_SS ISRW;

    cRxBuf[cRxBufCount] = UDR0;
    cRxBufCount++;

    Usart0_rxc.SignalISR();
}


Разве вычитывание UDR0 в процессе TProc3::Exec() это не то же самое?
Процесс ждет прерывания (точнее Usart0_rxc.SignalISR())-> при его возникновении вычитывает UDR0, сбрасывается RXC0 -> процесс опять готов обработать прерывание.
Разве не так? Или после обработки прерывания нужно обеспечить выход из процесса, переключиться куда нибудь? Здесь не врубаюсь...
Сергей Борщ
QUOTE (Acvarif @ Jul 13 2011, 16:00) *
Процесс ждет прерывания (точнее Usart0_rxc.SignalISR())-> при его возникновении вычитывает UDR0, сбрасывается RXC0 -> процесс опять готов обработать прерывание.
А как процесс получит управление, если вы в прерывании не сбросили RXC0? После выхода из обработчика процессор снова будет вызывать этот же обработчик.
Acvarif
Цитата(Сергей Борщ @ Jul 13 2011, 16:42) *
А как процесс получит управление, если вы в прерывании не сбросили RXC0? После выхода из обработчика процессор снова будет вызывать этот же обработчик.


Спасибо Сергей. Уяснил. RXC0 нужно сбросить имено в прерывании чтением UDR0 (действительно мне нужно вспомнить матчасть).
Это #pragma vector=TIMER1_COMPA_vect сам очищает свой флаг после выхода из обработчика. Там и переход в процесс (Timer1_CompA.Wait()wink.gif мягкий, без проблем.

Если можно, еще один нюанс.
Процесс 3 вызывается только если там имеется Sleep(>=1); Почему процесс не запускается просто по Usart0_rxc.SignalISR();
Usart0_rxc.Wait();




dxp
Цитата(Acvarif @ Jul 12 2011, 20:46) *
Думаю потому, что у потока область видимости, например на глобалы одна и та же. Потоки могут работать с глобалами без особых проблем.
В ОСях процессы это обычно отдельные приложения (в каждом из них можно запускать сколько угодно, в разумных пределах, потоков).
Могу ошибаться...

Вы имеете в виду POSIX процессы? Ну, а причём тут они? У нас не POSIX система, а крохотная RTOS. Слово "процесс" обозначает некое продолжительное действие и употребляется в самых разных областях. По поводу терминологии в документации на v4 есть пара абзацев с аргументацией, почему выбран термин "процесс", а не "тред" и не "задача".
Acvarif
Цитата(dxp @ Jul 14 2011, 06:34) *
Вы имеете в виду POSIX процессы? Ну, а причём тут они? У нас не POSIX система, а крохотная RTOS. Слово "процесс" обозначает некое продолжительное действие и употребляется в самых разных областях. По поводу терминологии в документации на v4 есть пара абзацев с аргументацией, почему выбран термин "процесс", а не "тред" и не "задача".


Да, нашел.

Цитата
О принятой терминологии. В scmRTOS используется термин «процесс»
(process) для обозначения части программы, выполняемой циклически, самостоя-
тельно и асинхронно по отношению к остальным частям программы. В литерату-
ре и в терминологии, принятой в других ОСРВ для обозначения этого, часто ис-
пользуются термины «задача» (task) и «тред» (thread – «нить», поток). Термин
«процесс» был выбран сознательно, т.к. представляется, что он более удачно под-
чёркивает смысл обозначаемого.
Действительно, «задача» — понятие весьма широкое и может обозначать
широкий спектр от школьной задачки по алгебре до боевой задачи роте спецназа.
«Тред» — это дословно «нить», т.е. как видно из названия, это нечто такое, что
имеет характеристику линейности, а не цикличности. Учитывая вышеприведён-
ные доводы, термин «процесс» представляется более удачным вариантом — дей-
ствительно, смысл этого слова в явном виде отражает действие1, протяжённое во
времени, с возможностью цикличности2 как отдельных составных частей процес-
са, так и всего процесса в целом.
Спасибо. Вопрос снят.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.