|
Зависает низкоприритетный процесс |
|
|
|
May 13 2010, 13:42
|
Группа: Участник
Сообщений: 11
Регистрация: 13-05-10
Пользователь №: 57 239

|
Контроллер МЕГА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 -заданное значение. Когда движок доезжает до заданного места (совпадает значение энкодера и заданное), происходит перезапуск по ватчдогу.
|
|
|
|
|
May 18 2010, 07:24
|
Группа: Участник
Сообщений: 11
Регистрация: 13-05-10
Пользователь №: 57 239

|
Цитата(AHTOXA @ May 13 2010, 19:10)  В приведённом коде виснуть нечему. Видимо меняются глобальные переменные, которые вызывают активность более приоритетного процесса, и он надолго захватывает управление. Вот собака и сбрасывает проц. Заменил глобальные переменные на закрытые члены класса. Не помогло. Может дело в размере стеков, как их настраивать в ИАР и в csmRTOS?
|
|
|
|
|
May 18 2010, 07:52
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Суть не в том, что это были глобальные переменные, суть в том, что их изменение в низкоприоритетном процессе запускало какую-то деятельность в более приоритетном процессе. Ведь запускало же? Например, флаг enable_move - он зачем? А scmRTOS устроена так, что пока более приоритетный процесс не отдаст управление (при помощи Sleep() или, скажем, TEventFlag::Wait() ), менее приоритетный процесс не имеет шансов на выполнение. Оттого и сбрасывается собака. Стеки задач задаются в специализации шаблона процесса: Код typedef OS::process<OS::pr1, 200> TProc1; здесь 200 - размер стека процесса TProc1.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
May 18 2010, 12:31
|
Группа: Участник
Сообщений: 11
Регистрация: 13-05-10
Пользователь №: 57 239

|
Цитата(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(). Вроде правильно должно отрабатывать?
|
|
|
|
|
May 18 2010, 12:36
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Основная идея такая - чем больше требования к времени реакции - тем больше приоритет. У вас это скорее всего терморегулятор (поскольку инерционность системы малая). Но если он будет работать как сейчас, в глухом цикле, то остальные процессы не получат шанса на выполнение. Поэтому сделаем так: в таймерном прерывании (или в OS::SystemTimerUserHook()) взводим TEventFlag. А в процессе термостата ждём этого флага и, дождавшись - делаем очередную итерацию регулирования (например, PID). Теперь что касается управления по UART... В прерывании по приёму принятый символ складывается в OS::channel<char> RxChannel. Процесс UART (менее приоритетный) постоянно висит в ожидании прибытия символа (RxChannel.pop()). Получив символ, анализирует его, и если получилась команда, выполняет. Запись новой температуры регулирования нужно проводить в критической секции, потому что иначе она может быть прервана посередине и температура будет некорректной. Чтение - необязательно. Как-то так.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
May 18 2010, 14:04
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(Nikkola @ May 18 2010, 18:31)  Спасибо большое за участие! Пожалуйста  Цитата Вот теперь флагом управляю в самом приоритетном процессе. Выставляю при получении команды с УСАРТа, а сбрасываю при помощи EVENT FLAG WAIT(10). А в менее приоритетном делаю Signal(). Вроде правильно должно отрабатывать? Не, немного не так. Event flag -- это одностороннее средство коммуникации. Один процесс устанавливает флаг, другой - ждёт. Нельзя пользоваться им как шариком для пинг-понга, для передачи управления между процессами. Для этого придётся завести два флага. Более приоритетный процесс делает так: Код StartLowPriorityProcessFlag.Signal(); // даём отмашку менее приоритетному процессу LowPriorityWorkDone.Wait(); // ждём когда отработает низкоприоритетный процесс. А низкоприоритетный делает соответственно так: Код StartLowPriorityProcessFlag.Wait(); // ждём команды от высокоприритетного процесса Work(); // делаем работу LowPriorityWorkDone.Signal(); // сигнализируем об окончании работы.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
May 18 2010, 14:10
|
Группа: Участник
Сообщений: 11
Регистрация: 13-05-10
Пользователь №: 57 239

|
Цитата(AHTOXA @ May 18 2010, 16:36)  Основная идея такая - чем больше требования к времени реакции - тем больше приоритет. У вас это скорее всего терморегулятор (поскольку инерционность системы малая). Но если он будет работать как сейчас, в глухом цикле, то остальные процессы не получат шанса на выполнение. Поэтому сделаем так: в таймерном прерывании (или в OS::SystemTimerUserHook()) взводим TEventFlag. А в процессе термостата ждём этого флага и, дождавшись - делаем очередную итерацию регулирования (например, PID). Теперь что касается управления по UART... В прерывании по приёму принятый символ складывается в OS::channel<char> RxChannel. Процесс UART (менее приоритетный) постоянно висит в ожидании прибытия символа (RxChannel.pop()). Получив символ, анализирует его, и если получилась команда, выполняет. Запись новой температуры регулирования нужно проводить в критической секции, потому что иначе она может быть прервана посередине и температура будет некорректной. Чтение - необязательно. Как-то так. Спасибо большущее! Значит чтение глобальной переменной можно не опасаясь, а модификацию -в критической секции. Я привел пример в общем виде, на самом деле у меня крутятся два асинхронных двигателя (~тока) в двух направляниях, у каждого на валу по энкодеру. Самый приоритетный процесс- это уарт- так требуют программисты верхнего уровня (связь с компом), да и чтоб на команду стоп мгновенно реагировал, хотя приоритеты можно пересмотреть. Видимо для считывания угла мне надо устроить внепроцессную функцию типа void с критической секцией , а значение считанного c энкодера угла передавать по ссылке (в параметре ф_ции) типа Get_Angle(word&). функции с возвращаемым значением вроде как то не советовали в процессе использовать. Тогда эту функцию мог бы я в обоих процессах использовать?
|
|
|
|
|
May 18 2010, 17:33
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(Nikkola @ May 18 2010, 20:10)  Спасибо большущее! Значит чтение глобальной переменной можно не опасаясь, а модификацию -в критической секции. Нет  Чтение можно выполнять не опасаясь только из потока (процесса), который производит запись (модификацию переменной), при непременном условии, что он приоритетнее читателей, и к тому же единственный, кто выполняет модификацию. То есть, если модификация переменной производится из двух потоков, то и чтение (любое) надо обрамлять критической секцией. Или если модификация производится в менее приоритетном процессе. Я бы для начала рекомендовал не ломать голову, а обрамлять критическими секциями любые переменные, используемые в нескольких потоках. Оптимизация подождёт Цитата Видимо для считывания угла мне надо устроить внепроцессную функцию типа 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. И по прибытии команд рулил бы этими объектами. Тут главное понять сразу, что одна и та же функция может быть вызвана из разных процессов. Это как бы другая плоскость программы - объект (функция) и процесс.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
May 19 2010, 06:51
|
Группа: Участник
Сообщений: 11
Регистрация: 13-05-10
Пользователь №: 57 239

|
Цитата(AHTOXA @ May 18 2010, 20:33)  Нет  Чтение можно выполнять не опасаясь только из потока (процесса), который производит запись (модификацию переменной), при непременном условии, что он приоритетнее читателей, и к тому же единственный, кто выполняет модификацию. То есть, если модификация переменной производится из двух потоков, то и чтение (любое) надо обрамлять критической секцией. Или если модификация производится в менее приоритетном процессе. Я бы для начала рекомендовал не ломать голову, а обрамлять критическими секциями любые переменные, используемые в нескольких потоках. Оптимизация подождёт Функцию можно использовать любую, причём по значению как раз правильней. Такое чтение можно защитить критической секцией, в отличие от функции, возвращающей ссылку. Я бы сказал, что вариант со ссылкой вообще нонсенс. Как оформить - дело вкуса. Я бы организовал класс 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); } и соответственно вызывается в первом процессе? Буду пробовать!
|
|
|
|
|
May 19 2010, 11:23
|
Группа: Участник
Сообщений: 11
Регистрация: 13-05-10
Пользователь №: 57 239

|
Цитата(AHTOXA @ May 19 2010, 11:18)  В void process() засуньте весь код из первого поста. Новые цели обновляются сами по себе, из другого процесса (который UART). +1:) Но можно им сказать, что UART самый приоритетный, зачем расстраивать людей?  А что, можно одну функцию класса использовать другую функцию? В самом простом случае мой процесс будеть выглядеть просто process(){ if ( where()!= target) {go(target); } } а в сетевом (uart) использовать where() для ответ на запрос текущего угла?
|
|
|
|
|
May 19 2010, 12:58
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(Nikkola @ May 19 2010, 17:23)  А что, можно одну функцию класса использовать другую функцию? Конечно! (если она public ) Цитата В самом простом случае мой процесс будеть выглядеть просто
process(){ if ( where()!= target) {go(target); } } а в сетевом (uart) использовать where() для ответ на запрос текущего угла? Да. ЗЫ. Здесь есть маленький подвох - если go() будет длиться долго, то до её завершения нельзя будет снова изменить target, вернее, изменение не подействует. Поэтому желательно сделать go() достаточно короткой. Но это уже детали.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
May 24 2010, 12:11
|
Группа: Участник
Сообщений: 11
Регистрация: 13-05-10
Пользователь №: 57 239

|
Получилось, что неправильно распределены ресурсы Мк. Есть ли инструкция как расчитывать RSTACK CSTACK? Дебаггер пишет, что указатели стэков OUT of range. Что именно значат настройки проекта в GENERAL->System? Какая там арифметика в ИАР АВР? Заранее благодарен.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|