Перейти к содержанию
    

scmRTOS холостой ход и системный таймер

"Продолжаем разговор" как говорил Карлсон.

Запустил ОСь на mega128a в WinAvr (в скрепке проект - сделан на базе http://real.kiev.ua/scmrtos/1-eventflag/)

 

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

Поскольку нет отладчика то понять в чем дело сложно.

 

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

 

Спасибо.

WinAvrPrj.rar

TestScmRtosV310.rar

Изменено пользователем 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*/

Если закоментировать этот код ничего не изменится.

В документацци сказано о переключении контекстов. Дергание ногой должно вызывать прерывания по компаратору и соответственно переключение контекстов.

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

 

 

 

scmrtos_avr_iar_snapshot.rar

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Так до сих пор и не понял зачем в примере нужен аналоговый компаратор?
Посмотрите внимательно в scmRTOS_config.h чему равно scmRTOS_CONTEXT_SWITCH_SCHEME. Если 0, то компаратор не нужен. Если 1, то таки да, его прерывание переключает контекст.

Но где это дергание происходит?
Смотрите OS_Kernel.h, там есть строки
void OS::TKernel::SchedISR()
{
    TPriority NextPrty = GetHighPriority(ReadyProcessMap);
    if(NextPrty != CurProcPriority)
    {
        SchedProcPriority    = NextPrty;
        RaiseContextSwitch();
    }
}

Вот RaiseContextSwitch() и есть дерганье ногой. Ищите его определение в OS_Target.h

Я так понимаю, что процесс это все вместе взятое - нить со своими переменными, регистрами стеком.
Контекст - содержимое регистров для процесса (плюс указатель стека, который в "нормальных" процессорах входит в регистры ядра).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

Посмотрите внимательно в 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

 

Кто или что тогда всетаки переключает процессы? Или с какой частотой переключаются процессы? Кто ее формирует?

Я так понимаю, что переключатель контекста и есть переключатель процессов? Может глупость сморозил...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Кто или что тогда всетаки переключает процессы? Или с какой частотой переключаются процессы? Кто ее формирует?

Я так понимаю, что переключатель контекста и есть переключатель процессов? Может глупость сморозил...

Переключается по таймеру. Таймер дёргает прерывание (обычно самое низкоприоритетное), по которому вызывается диспетчер процессов.

По-моему, так. (давно за инструмент не садился)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Переключается по таймеру. Таймер дёргает прерывание (обычно самое низкоприоритетное), по которому вызывается диспетчер процессов.

По-моему, так. (давно за инструмент не садился)

 

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

 

Зачем тогда еще один вариант переключения процессов (в данном примере scmRTOS_CONTEXT_SWITCH_SCHEME = 1 не работает) внешнее дергание ноги -> вызов таким образом какого нибудь низкоуровневого прерывания для переключения между процессами? Что это дает? Освобождает как то системный таймер?

Изменено пользователем Acvarif

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Получается, что если 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

Тут разрешаются не глобальные прерывания, а прерывание по окончанию записи во флешь. Этот такой трюк - флаг этого прерывания при нормальной работе всегда взведен, и разрешение этого прерывания (естетсвенно, при разрешенных глобальных прерываниях) вызовет переход на его обработчик. А уже в обработчике произойдет, собственно, переключение контекстов. Следствием которого является переключение текущего процесса. Если же переключение контекстов потребовалось во время обработки какого-либо прерывания, то глобально прерывания в этот момент запрещены и будут разрешены по команде RETI. В этот-то момент и вызовется обработчик.

Кто или что тогда всетаки переключает процессы? Или с какой частотой переключаются процессы? Кто ее формирует?
Это вытесняющая ОСь. Здесь переключение происходит в тот момент, когда процесс отдает управление в ожидании какого-либо сервиса либо уходя в спячку либо если произошло событие (вызов сервиса из прерывания или текушего процесса), требующее пробуждения более приоритетного процесса.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Тут разрешаются не глобальные прерывания, а прерывание по окончанию записи во флешь. Этот такой трюк - флаг этого прерывания при нормальной работе всегда взведен, и разрешение этого прерывания (естетсвенно, при разрешенных глобальных прерываниях) вызовет переход на его обработчик. А уже в обработчике произойдет, собственно, переключение контекстов. Следствием которого является переключение текущего процесса. Если же переключение контекстов потребовалось во время обработки какого-либо прерывания, то глобально прерывания в этот момент запрещены и будут разрешены по команде 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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вы, похоже, взяли исходник из другого примера или же настройка компаратора - рудимент от предыдущей версии.
В 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, естественно, не вставлено махание ножкой осциллографу.

 

#define  scmRTOS_CONTEXT_SWITCH_SCHEME      1

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

Потому что в примерах реализованы оба способа.

 

Получается,что в случае когда 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), где и используется для организации входа в обработчик прерывания.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Спасибо.

 

Значит в примере от 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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Значит в примере от IAR 310 пропущено только дрыгание ногой по прерываниям компаратора при scmRTOS_CONTEXT_SWITCH_SCHEME 1?
Нет. В IAR310 вариант "1" переведен с аналогового компаратора на готовность записи во флеш, но из main недовычищено то, что касалось компаратора.

 

если

#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 делается разрешением.

 

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

...

Я так понял, что там для идентичности с gcc добавлены функции типа DRIVER(TIMER1_ISR,OUT); и др.

"Волковские" макросы из pin_macros.h добавлены для простоты обеспечения идентичности.

Просто скопирован кусок из AVR/GCC-шных примеров для полного соответствия поведения, чтобы можно было пользоваться статьёй-описанием для обеих компиляторов.

Если (когда ;) ) доберусь до CM3-шного примера, то тогда перепишу под тамошний pin.h

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В случае "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.

И в этом неуверен...

Как все же правильно?

 

 

В 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

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

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

 

Пытаюсь организовать простую передачу данных 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 функций?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Да, понял. Спасибо.

С 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 ничего не передавать.

Первое, что пришло в голову. Может глупость...

Прошу прокомментировать.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...