Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Зависает низкоприритетный процесс
Форум разработчиков электроники ELECTRONIX.ru > Cистемный уровень проектирования > Операционные системы > scmRTOS
Nikkola
Контроллер МЕГА16, IAR EWAVR 4.20, scmRTOS v 3.00-beta

фрагмент кода

OS_PROCESS void TProcess::Exec()
{

while(true)
{

__watchdog_reset();
Sleep(100);

PORTA &= ~(1<<PA5);
PORTA &= ~(1<<PA7);//вниз 0

__delay_cycles(10); //t1 > 0.45 мкс

word hGray, vGray; //код грея от энкодера

__watchdog_reset();
for(int i = 0; i < 10; i++)
{
hGray <<= 1;
vGray <<= 1;

PORTA |= (1<<5)|(1<<7);//вверх 1
__delay_cycles(10);

if(PINA&0x40) hGray |=(1<<0);
if(PINA&0x10) vGray |=(1<<0);

PORTA &= ~(1<<PA5);
PORTA &= ~(1<<PA7);//вниз 0
__delay_cycles(10);
}

__delay_cycles(30);

PORTA |= (1<<5)|(1<<7);//вверх 1
__watchdog_reset();

hGray &= 0x3FF;
vGray &= 0x3FF;
__watchdog_reset();


*phA = GrayToBin(hGray);
*pvA = GrayToBin(vGray);


byte dir=0;
__watchdog_reset();
byte vvA = HIGHBYTE(vAngle<<6);
byte hhA = HIGHBYTE(hAngle<<6);
byte TvA = HIGHBYTE(vTargetAngle<<6);
byte ThA = HIGHBYTE(hTargetAngle<<6);

if ((vvA>TvA)&&enable_move) dir |=(1<<3);

if ((vvA<TvA)&&enable_move) dir |=(1<<2);

if (vvA == TvA) dir &= ~((1<<2)|(1<<3));


if ((hhA>ThA)&&enable_move) dir |=(1<<1);

if ((hhA<ThA)&&enable_move) dir |=(1<<0);

if (hhA == ThA) dir &= ~((1<<0)|(1<<1));


if ((vvA == TvA)&&(hhA == ThA))
{

enable_move = 0; //EFlag.Clear();


}

PORTA = 0xF0|dir;

//move = 0xFF;

//задание направления движения
//__watchdog_reset();




__watchdog_reset();
}
}


Виснет в момент совпадения (== по if) . Испол зую глобальные переменные, здесь vAngle - текущее значение угла, vTarget -заданное значение. Когда движок доезжает до заданного места (совпадает значение энкодера и заданное), происходит перезапуск по ватчдогу.
AHTOXA
В приведённом коде виснуть нечему. Видимо меняются глобальные переменные, которые вызывают активность более приоритетного процесса, и он надолго захватывает управление. Вот собака и сбрасывает проц.
Nikkola
Цитата(AHTOXA @ May 13 2010, 19:10) *
В приведённом коде виснуть нечему. Видимо меняются глобальные переменные, которые вызывают активность более приоритетного процесса, и он надолго захватывает управление. Вот собака и сбрасывает проц.


Заменил глобальные переменные на закрытые члены класса. Не помогло. Может дело в размере стеков, как их настраивать в ИАР и в csmRTOS?
AHTOXA
Суть не в том, что это были глобальные переменные, суть в том, что их изменение в низкоприоритетном процессе запускало какую-то деятельность в более приоритетном процессе. Ведь запускало же? Например, флаг enable_move - он зачем? А scmRTOS устроена так, что пока более приоритетный процесс не отдаст управление (при помощи Sleep() или, скажем, TEventFlag::Wait() ), менее приоритетный процесс не имеет шансов на выполнение. Оттого и сбрасывается собака.

Стеки задач задаются в специализации шаблона процесса:
Код
typedef OS::process<OS::pr1, 200> TProc1;

здесь 200 - размер стека процесса TProc1.
Nikkola
Цитата(AHTOXA @ May 18 2010, 11:52) *
Суть не в том, что это были глобальные переменные, суть в том, что их изменение в низкоприоритетном процессе запускало какую-то деятельность в более приоритетном процессе. Ведь запускало же? Например, флаг enable_move - он зачем? А scmRTOS устроена так, что пока более приоритетный процесс не отдаст управление (при помощи Sleep() или, скажем, TEventFlag::Wait() ), менее приоритетный процесс не имеет шансов на выполнение. Оттого и сбрасывается собака.

Стеки задач задаются в специализации шаблона процесса:
Код
typedef OS::process<OS::pr1, 200> TProc1;

здесь 200 - размер стека процесса TProc1.


Значит , я не могу выставить флаг в высокоприоритетном процессе (у меня это enable_move в Usart-овском процессе при получении команды движения в заданный сектор), а сбросить в низкоприоритетном (когда текущее значение энкодера совпало с заданным сектором). Именно при совпадении происходит завис. Тогда можно вопрос? Какой тогда механизм задействовать для обмена данными между процессами? EVENT_Flag ксожалению сразу сбрасывает значение. Как бы вы , например, разбили по процессам и сервисам , скажем терморегулятор, опрашиваемый по УСАРту, причем значение задаваемой температуры должно изменяться по команде с УСАРта в любой момент, а инерционность системы малая. Получается есть заданная температура, кот надо обеспечить (пусть там нагреть-охладить ) текущая- по измерению, с кажем с термопары. И еще надо давать ответ на запрос с УСАРТа о текущей температуре?

Спасибо большое за участие!
Вот теперь флагом управляю в самом приоритетном процессе. Выставляю при получении команды с УСАРТа, а сбрасываю при помощи EVENT FLAG WAIT(10). А в менее приоритетном делаю Signal(). Вроде правильно должно отрабатывать?
AHTOXA
Основная идея такая - чем больше требования к времени реакции - тем больше приоритет.
У вас это скорее всего терморегулятор (поскольку инерционность системы малая).
Но если он будет работать как сейчас, в глухом цикле, то остальные процессы не получат шанса на выполнение. Поэтому сделаем так: в таймерном прерывании (или в OS::SystemTimerUserHook()) взводим TEventFlag. А в процессе термостата ждём этого флага и, дождавшись - делаем очередную итерацию регулирования (например, PID).
Теперь что касается управления по UART...
В прерывании по приёму принятый символ складывается в OS::channel<char> RxChannel. Процесс UART (менее приоритетный) постоянно висит в ожидании прибытия символа (RxChannel.pop()). Получив символ, анализирует его, и если получилась команда, выполняет. Запись новой температуры регулирования нужно проводить в критической секции, потому что иначе она может быть прервана посередине и температура будет некорректной. Чтение - необязательно.
Как-то так.
AHTOXA
Цитата(Nikkola @ May 18 2010, 18:31) *
Спасибо большое за участие!

Пожалуйстаsmile.gif

Цитата
Вот теперь флагом управляю в самом приоритетном процессе. Выставляю при получении команды с УСАРТа, а сбрасываю при помощи EVENT FLAG WAIT(10). А в менее приоритетном делаю Signal(). Вроде правильно должно отрабатывать?


Не, немного не так. Event flag -- это одностороннее средство коммуникации. Один процесс устанавливает флаг, другой - ждёт. Нельзя пользоваться им как шариком для пинг-понга, для передачи управления между процессами. Для этого придётся завести два флага. Более приоритетный процесс делает так:
Код
    StartLowPriorityProcessFlag.Signal(); // даём отмашку менее приоритетному процессу
    LowPriorityWorkDone.Wait();   // ждём когда отработает низкоприоритетный процесс.

А низкоприоритетный делает соответственно так:
Код
    StartLowPriorityProcessFlag.Wait(); // ждём команды от высокоприритетного процесса
    Work(); // делаем работу
    LowPriorityWorkDone.Signal(); // сигнализируем об окончании работы.
Nikkola
Цитата(AHTOXA @ May 18 2010, 16:36) *
Основная идея такая - чем больше требования к времени реакции - тем больше приоритет.
У вас это скорее всего терморегулятор (поскольку инерционность системы малая).
Но если он будет работать как сейчас, в глухом цикле, то остальные процессы не получат шанса на выполнение. Поэтому сделаем так: в таймерном прерывании (или в OS::SystemTimerUserHook()) взводим TEventFlag. А в процессе термостата ждём этого флага и, дождавшись - делаем очередную итерацию регулирования (например, PID).
Теперь что касается управления по UART...
В прерывании по приёму принятый символ складывается в OS::channel<char> RxChannel. Процесс UART (менее приоритетный) постоянно висит в ожидании прибытия символа (RxChannel.pop()). Получив символ, анализирует его, и если получилась команда, выполняет. Запись новой температуры регулирования нужно проводить в критической секции, потому что иначе она может быть прервана посередине и температура будет некорректной. Чтение - необязательно.
Как-то так.


Спасибо большущее! Значит чтение глобальной переменной можно не опасаясь, а модификацию -в критической секции.
Я привел пример в общем виде, на самом деле у меня крутятся два асинхронных двигателя (~тока) в двух направляниях, у каждого на валу по энкодеру.
Самый приоритетный процесс- это уарт- так требуют программисты верхнего уровня (связь с компом), да и чтоб на команду стоп мгновенно реагировал, хотя приоритеты можно пересмотреть. Видимо для считывания угла мне надо устроить внепроцессную функцию типа void с критической секцией , а значение считанного c энкодера угла передавать по ссылке (в параметре ф_ции) типа Get_Angle(word&). функции с возвращаемым значением вроде как то не советовали в процессе использовать. Тогда эту функцию мог бы я в обоих процессах использовать?
AHTOXA
Цитата(Nikkola @ May 18 2010, 20:10) *
Спасибо большущее! Значит чтение глобальной переменной можно не опасаясь, а модификацию -в критической секции.

Нетsmile.gif Чтение можно выполнять не опасаясь только из потока (процесса), который производит запись (модификацию переменной), при непременном условии, что он приоритетнее читателей, и к тому же единственный, кто выполняет модификацию.
То есть, если модификация переменной производится из двух потоков, то и чтение (любое) надо обрамлять критической секцией. Или если модификация производится в менее приоритетном процессе.
Я бы для начала рекомендовал не ломать голову, а обрамлять критическими секциями любые переменные, используемые в нескольких потоках. Оптимизация подождётsmile.gif

Цитата
Видимо для считывания угла мне надо устроить внепроцессную функцию типа void с критической секцией , а значение считанного c энкодера угла передавать по ссылке (в параметре ф_ции) типа Get_Angle(word&). функции с возвращаемым значением вроде как то не советовали в процессе использовать. Тогда эту функцию мог бы я в обоих процессах использовать?


Функцию можно использовать любую, причём по значению как раз правильней. Такое чтение можно защитить критической секцией, в отличие от функции, возвращающей ссылку. Я бы сказал, что вариант со ссылкой вообще нонсенс.
Как оформить - дело вкуса. Я бы организовал класс TEncoder, типа:
Код
class TEncoder
{
private:
  int target; // куда едем
  int current_point; // где находимся
public:
  void process(); // эта функция выполняется в потоке (из Exec)
  void go(int point); // команда на перемещение (вызывается из другого процесса)
  int where() {TCritSect cs; return current_point; } // команда чтения текущего положения
};

, потом создал два экземпляра этого класса - enc1 и enc2. И по прибытии команд рулил бы этими объектами.

Тут главное понять сразу, что одна и та же функция может быть вызвана из разных процессов. Это как бы другая плоскость программы - объект (функция) и процесс.
Nikkola
Цитата(AHTOXA @ May 18 2010, 20:33) *
Нетsmile.gif Чтение можно выполнять не опасаясь только из потока (процесса), который производит запись (модификацию переменной), при непременном условии, что он приоритетнее читателей, и к тому же единственный, кто выполняет модификацию.
То есть, если модификация переменной производится из двух потоков, то и чтение (любое) надо обрамлять критической секцией. Или если модификация производится в менее приоритетном процессе.
Я бы для начала рекомендовал не ломать голову, а обрамлять критическими секциями любые переменные, используемые в нескольких потоках. Оптимизация подождётsmile.gif



Функцию можно использовать любую, причём по значению как раз правильней. Такое чтение можно защитить критической секцией, в отличие от функции, возвращающей ссылку. Я бы сказал, что вариант со ссылкой вообще нонсенс.
Как оформить - дело вкуса. Я бы организовал класс TEncoder, типа:
Код
class TEncoder
{
private:
  int target; // куда едем
  int current_point; // где находимся
public:
  void process(); // эта функция выполняется в потоке (из Exec)
  void go(int point); // команда на перемещение (вызывается из другого процесса)
  int where() {TCritSect cs; return current_point; } // команда чтения текущего положения
};

, потом создал два экземпляра этого класса - enc1 и enc2. И по прибытии команд рулил бы этими объектами.

Тут главное понять сразу, что одна и та же функция может быть вызвана из разных процессов. Это как бы другая плоскость программы - объект (функция) и процесс.


Еще раз спасибо. Я так понимаю, что функция void process() отвечает за получение новых целей , что -то вроде
{
TCrit Cect cs1;
if(....)
Target = (// полученные данные с uart);
} и соответственно вызывается в первом процессе? Буду пробовать!
Сергей Борщ
Цитата(Nikkola @ May 18 2010, 17:10) *
Самый приоритетный процесс- это уарт- так требуют программисты верхнего уровня (связь с компом), да и чтоб на команду стоп мгновенно реагировал
Вот меньше всего программистам связи с компом надо знать о приоритете процесса. Пусть оговаривают время отклика, время реакции, но приритет их никак беспокоить не должен. Если UART у вас будет самым высокоприоритетным процессом, то copy /b pagefile.sys com1 может парализовать вашу систему напрочь.
AHTOXA
Цитата(Nikkola @ May 19 2010, 12:51) *
Еще раз спасибо. Я так понимаю, что функция void process() отвечает за получение новых целей


В void process() засуньте весь код из первого поста. Новые цели обновляются сами по себе, из другого процесса (который UART).

Цитата(Сергей Борщ @ May 19 2010, 13:19) *
Вот меньше всего программистам связи с компом надо знать о приоритете процесса.

+1:) Но можно им сказать, что UART самый приоритетный, зачем расстраивать людей? smile.gif
Nikkola
Цитата(AHTOXA @ May 19 2010, 11:18) *
В void process() засуньте весь код из первого поста. Новые цели обновляются сами по себе, из другого процесса (который UART).


+1:) Но можно им сказать, что UART самый приоритетный, зачем расстраивать людей? smile.gif



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

process(){
if ( where()!= target) {go(target); }
}
а в сетевом (uart) использовать where() для ответ на запрос текущего угла?
AHTOXA
Цитата(Nikkola @ May 19 2010, 17:23) *
А что, можно одну функцию класса использовать другую функцию?

Конечно! (если она public )

Цитата
В самом простом случае мой процесс будеть выглядеть просто

process(){
if ( where()!= target) {go(target); }
}
а в сетевом (uart) использовать where() для ответ на запрос текущего угла?


Да.

ЗЫ. Здесь есть маленький подвох - если go() будет длиться долго, то до её завершения нельзя будет снова изменить target, вернее, изменение не подействует. Поэтому желательно сделать go() достаточно короткой. Но это уже детали.
Nikkola
Получилось, что неправильно распределены ресурсы Мк. Есть ли инструкция как расчитывать RSTACK CSTACK?
Дебаггер пишет, что указатели стэков OUT of range. Что именно значат настройки проекта в GENERAL->System? Какая там арифметика в ИАР АВР? Заранее благодарен.
Сергей Борщ
Цитата(Nikkola @ May 24 2010, 15:11) *
Дебаггер пишет, что указатели стэков OUT of range.
Придется с этим смириться. Он не имеет понятния об ОС и о нескольких стеках. Или покупать у IAR sdk и писать свой плугин для c-spy. Вы понаблюдайте за данными в начале массивов стеков для каждого процесса - если там нули, значит стека еще хватает.
Nikkola
Цитата(Сергей Борщ @ May 24 2010, 18:48) *
Придется с этим смириться. Он не имеет понятния об ОС и о нескольких стеках. Или покупать у IAR sdk и писать свой плугин для c-spy. Вы понаблюдайте за данными в начале массивов стеков для каждого процесса - если там нули, значит стека еще хватает.


Как же быть? Сколько выделить в SYSTEM под CSTACK RSTACK? Сколько выделить в IDLE и в пользовательских процессах, чтоб все работало, а так две мои глобальные переменные типа word забиваются единицами. Есть ли общие рекомендации, какие - нибудь итерации к расчету оптимальных стеков, методы научного тыка и т.п. А диагностические сообщения я и прежде на рабочих проектах видел, а вот теперь попал.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.