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

Зависает низкоприритетный процесс

Контроллер МЕГА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 -заданное значение. Когда движок доезжает до заданного места (совпадает значение энкодера и заданное), происходит перезапуск по ватчдогу.

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


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

В приведённом коде виснуть нечему. Видимо меняются глобальные переменные, которые вызывают активность более приоритетного процесса, и он надолго захватывает управление. Вот собака и сбрасывает проц.

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


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

В приведённом коде виснуть нечему. Видимо меняются глобальные переменные, которые вызывают активность более приоритетного процесса, и он надолго захватывает управление. Вот собака и сбрасывает проц.

 

Заменил глобальные переменные на закрытые члены класса. Не помогло. Может дело в размере стеков, как их настраивать в ИАР и в csmRTOS?

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


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

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

 

Стеки задач задаются в специализации шаблона процесса:

typedef OS::process<OS::pr1, 200> TProc1;

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

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


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

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

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


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

Основная идея такая - чем больше требования к времени реакции - тем больше приоритет.

У вас это скорее всего терморегулятор (поскольку инерционность системы малая).

Но если он будет работать как сейчас, в глухом цикле, то остальные процессы не получат шанса на выполнение. Поэтому сделаем так: в таймерном прерывании (или в OS::SystemTimerUserHook()) взводим TEventFlag. А в процессе термостата ждём этого флага и, дождавшись - делаем очередную итерацию регулирования (например, PID).

Теперь что касается управления по UART...

В прерывании по приёму принятый символ складывается в OS::channel<char> RxChannel. Процесс UART (менее приоритетный) постоянно висит в ожидании прибытия символа (RxChannel.pop()). Получив символ, анализирует его, и если получилась команда, выполняет. Запись новой температуры регулирования нужно проводить в критической секции, потому что иначе она может быть прервана посередине и температура будет некорректной. Чтение - необязательно.

Как-то так.

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


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

Спасибо большое за участие!

Пожалуйста:)

 

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

 

Не, немного не так. Event flag -- это одностороннее средство коммуникации. Один процесс устанавливает флаг, другой - ждёт. Нельзя пользоваться им как шариком для пинг-понга, для передачи управления между процессами. Для этого придётся завести два флага. Более приоритетный процесс делает так:

    StartLowPriorityProcessFlag.Signal(); // даём отмашку менее приоритетному процессу
    LowPriorityWorkDone.Wait();   // ждём когда отработает низкоприоритетный процесс.

А низкоприоритетный делает соответственно так:

    StartLowPriorityProcessFlag.Wait(); // ждём команды от высокоприритетного процесса
    Work(); // делаем работу
    LowPriorityWorkDone.Signal(); // сигнализируем об окончании работы.

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


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

Основная идея такая - чем больше требования к времени реакции - тем больше приоритет.

У вас это скорее всего терморегулятор (поскольку инерционность системы малая).

Но если он будет работать как сейчас, в глухом цикле, то остальные процессы не получат шанса на выполнение. Поэтому сделаем так: в таймерном прерывании (или в OS::SystemTimerUserHook()) взводим TEventFlag. А в процессе термостата ждём этого флага и, дождавшись - делаем очередную итерацию регулирования (например, PID).

Теперь что касается управления по UART...

В прерывании по приёму принятый символ складывается в OS::channel<char> RxChannel. Процесс UART (менее приоритетный) постоянно висит в ожидании прибытия символа (RxChannel.pop()). Получив символ, анализирует его, и если получилась команда, выполняет. Запись новой температуры регулирования нужно проводить в критической секции, потому что иначе она может быть прервана посередине и температура будет некорректной. Чтение - необязательно.

Как-то так.

 

Спасибо большущее! Значит чтение глобальной переменной можно не опасаясь, а модификацию -в критической секции.

Я привел пример в общем виде, на самом деле у меня крутятся два асинхронных двигателя (~тока) в двух направляниях, у каждого на валу по энкодеру.

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

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


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

Спасибо большущее! Значит чтение глобальной переменной можно не опасаясь, а модификацию -в критической секции.

Нет:) Чтение можно выполнять не опасаясь только из потока (процесса), который производит запись (модификацию переменной), при непременном условии, что он приоритетнее читателей, и к тому же единственный, кто выполняет модификацию.

То есть, если модификация переменной производится из двух потоков, то и чтение (любое) надо обрамлять критической секцией. Или если модификация производится в менее приоритетном процессе.

Я бы для начала рекомендовал не ломать голову, а обрамлять критическими секциями любые переменные, используемые в нескольких потоках. Оптимизация подождёт:)

 

Видимо для считывания угла мне надо устроить внепроцессную функцию типа 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. И по прибытии команд рулил бы этими объектами.

 

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

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


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

Нет:) Чтение можно выполнять не опасаясь только из потока (процесса), который производит запись (модификацию переменной), при непременном условии, что он приоритетнее читателей, и к тому же единственный, кто выполняет модификацию.

То есть, если модификация переменной производится из двух потоков, то и чтение (любое) надо обрамлять критической секцией. Или если модификация производится в менее приоритетном процессе.

Я бы для начала рекомендовал не ломать голову, а обрамлять критическими секциями любые переменные, используемые в нескольких потоках. Оптимизация подождёт:)

 

 

 

Функцию можно использовать любую, причём по значению как раз правильней. Такое чтение можно защитить критической секцией, в отличие от функции, возвращающей ссылку. Я бы сказал, что вариант со ссылкой вообще нонсенс.

Как оформить - дело вкуса. Я бы организовал класс 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);

} и соответственно вызывается в первом процессе? Буду пробовать!

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


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

Самый приоритетный процесс- это уарт- так требуют программисты верхнего уровня (связь с компом), да и чтоб на команду стоп мгновенно реагировал
Вот меньше всего программистам связи с компом надо знать о приоритете процесса. Пусть оговаривают время отклика, время реакции, но приритет их никак беспокоить не должен. Если UART у вас будет самым высокоприоритетным процессом, то copy /b pagefile.sys com1 может парализовать вашу систему напрочь.

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


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

Еще раз спасибо. Я так понимаю, что функция void process() отвечает за получение новых целей

 

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

 

Вот меньше всего программистам связи с компом надо знать о приоритете процесса.

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

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


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

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

 

 

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

 

 

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

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

 

process(){

if ( where()!= target) {go(target); }

}

а в сетевом (uart) использовать where() для ответ на запрос текущего угла?

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


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

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

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

 

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

 

process(){

if ( where()!= target) {go(target); }

}

а в сетевом (uart) использовать where() для ответ на запрос текущего угла?

 

Да.

 

ЗЫ. Здесь есть маленький подвох - если go() будет длиться долго, то до её завершения нельзя будет снова изменить target, вернее, изменение не подействует. Поэтому желательно сделать go() достаточно короткой. Но это уже детали.

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


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

Получилось, что неправильно распределены ресурсы Мк. Есть ли инструкция как расчитывать RSTACK CSTACK?

Дебаггер пишет, что указатели стэков OUT of range. Что именно значат настройки проекта в GENERAL->System? Какая там арифметика в ИАР АВР? Заранее благодарен.

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


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

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

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

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

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

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

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

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

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

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