|
scmRTOS холостой ход и системный таймер |
|
|
|
Jul 4 2011, 11:56
|
Знающий
   
Группа: Участник
Сообщений: 998
Регистрация: 27-08-08
Пользователь №: 39 850

|
"Продолжаем разговор" как говорил Карлсон. Запустил ОСь на mega128a в WinAvr (в скрепке проект - сделан на базе http://real.kiev.ua/scmrtos/1-eventflag/)В железе холостой ход явно просматривается, а прерываний системного таймера нет. Все, что зависит от него (это proc1, proc2 ..) естественнго не работает. Поскольку нет отладчика то понять в чем дело сложно. В IAR (v5501) ОСь не работает совсем (проект приложен в скрепке). В проекте сделана визуализация холостого хода и переполнения системного таймера (чего уж может быть проще). Поскольку в железе не видать не только системного таймера, но и холостого хода то получается, что зацикливание происходит в OS::Run(); Подсобите please разобраться ... Спасибо.
Сообщение отредактировал Acvarif - Jul 4 2011, 12:25
|
|
|
|
|
Jul 6 2011, 08:29
|
Знающий
   
Группа: Участник
Сообщений: 998
Регистрация: 27-08-08
Пользователь №: 39 850

|
ОСь таки запустилась. Проблема была таки в компиляторе. Он не умеет правильно отличать 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*/ Если закоментировать этот код ничего не изменится. В документацци сказано о переключении контекстов. Дергание ногой должно вызывать прерывания по компаратору и соответственно переключение контекстов. Но где это дергание происходит? И какая все же разница между контекстом и процессом? Я так понимаю, что процесс это все вместе взятое - нить со своими переменными, регистрами стеком.
|
|
|
|
|
Jul 6 2011, 08:50
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
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)  Я так понимаю, что процесс это все вместе взятое - нить со своими переменными, регистрами стеком. Контекст - содержимое регистров для процесса (плюс указатель стека, который в "нормальных" процессорах входит в регистры ядра).
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jul 6 2011, 10:35
|
Знающий
   
Группа: Участник
Сообщений: 998
Регистрация: 27-08-08
Пользователь №: 39 850

|
Спасибо. Стало немного светлее. Цитата(Сергей Борщ @ 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 Кто или что тогда всетаки переключает процессы? Или с какой частотой переключаются процессы? Кто ее формирует? Я так понимаю, что переключатель контекста и есть переключатель процессов? Может глупость сморозил...
|
|
|
|
|
Jul 6 2011, 10:57
|
Знающий
   
Группа: Участник
Сообщений: 998
Регистрация: 27-08-08
Пользователь №: 39 850

|
Цитата(MrYuran @ Jul 6 2011, 13:40)  Переключается по таймеру. Таймер дёргает прерывание (обычно самое низкоприоритетное), по которому вызывается диспетчер процессов. По-моему, так. (давно за инструмент не садился) Примерно так и думал. В данном случае получается, что переключателем процессов является Таймер 0 (он же системный таймер или формирователь тиков)? Зачем тогда еще один вариант переключения процессов (в данном примере scmRTOS_CONTEXT_SWITCH_SCHEME = 1 не работает) внешнее дергание ноги -> вызов таким образом какого нибудь низкоуровневого прерывания для переключения между процессами? Что это дает? Освобождает как то системный таймер?
Сообщение отредактировал Acvarif - Jul 6 2011, 11:01
|
|
|
|
|
Jul 6 2011, 11:47
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
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)  Кто или что тогда всетаки переключает процессы? Или с какой частотой переключаются процессы? Кто ее формирует? Это вытесняющая ОСь. Здесь переключение происходит в тот момент, когда процесс отдает управление в ожидании какого-либо сервиса либо уходя в спячку либо если произошло событие (вызов сервиса из прерывания или текушего процесса), требующее пробуждения более приоритетного процесса.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jul 6 2011, 13:10
|
Знающий
   
Группа: Участник
Сообщений: 998
Регистрация: 27-08-08
Пользователь №: 39 850

|
Цитата(Сергей Борщ @ 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 - выбрана передача управления на основе прерывание по окончанию записи во флешь. Или все наоборот?
Сообщение отредактировал Acvarif - Jul 6 2011, 15:53
|
|
|
|
|
Jul 6 2011, 20:49
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(Сергей Борщ @ 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), где и используется для организации входа в обработчик прерывания.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Jul 7 2011, 07:37
|
Знающий
   
Группа: Участник
Сообщений: 998
Регистрация: 27-08-08
Пользователь №: 39 850

|
Спасибо. Значит в примере от 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); и др.
Сообщение отредактировал Acvarif - Jul 7 2011, 07:38
|
|
|
|
|
Jul 7 2011, 08:49
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(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-шных примеров для полного соответствия поведения, чтобы можно было пользоваться статьёй-описанием для обеих компиляторов. Если (когда  ) доберусь до CM3-шного примера, то тогда перепишу под тамошний pin.h
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Jul 7 2011, 11:00
|
Знающий
   
Группа: Участник
Сообщений: 998
Регистрация: 27-08-08
Пользователь №: 39 850

|
Цитата В случае "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
|
|
|
|
|
Jul 7 2011, 14:00
|
Знающий
   
Группа: Участник
Сообщений: 998
Регистрация: 27-08-08
Пользователь №: 39 850

|
Всем спасибо. Появилось кое-какое понимание. Пытаюсь организовать простую передачу данных 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 функций?
|
|
|
|
|
Jul 7 2011, 20:07
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
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
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Jul 8 2011, 07:12
|
Знающий
   
Группа: Участник
Сообщений: 998
Регистрация: 27-08-08
Пользователь №: 39 850

|
Да, понял. Спасибо. С 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 ничего не передавать. Первое, что пришло в голову. Может глупость... Прошу прокомментировать.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|