реклама на сайте
подробности

 
 
 
Reply to this topicStart new topic
> scmRTOS+485-й, Как правильно пользоваться каналом?
Colobox
сообщение Feb 4 2008, 09:18
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 36
Регистрация: 31-10-07
Пользователь №: 31 901



Доброго времени суток!
Простенькая вроде прога и все хорошо и логично, и работает… но только 40 сек.
Программка общения МК с терминалкой. Терминалка посылает каждые 50 мс команду опроса длиной 4 байта плюс кс- 3f 0 0 0 3f, в ответ МК кидает также 4 байта плюс кс: 47 0 0 0 47, но это детали. Проц АТмега 8, 12МГц, сист. тик- 6 мс
Проблема в том, что примерно через 40 сек, видимо, не проходит сброс счетчика принятых байт и контрольной суммы. Перерывания по- уарту (прием байта) вызываются.
Подскажите, где тут может быть баг или неправильное понимание?
Код
#define scmRTOS_ISRW_TYPE   TISRW_SS
……………………………………………………
#define  scmRTOS_CONTEXT_SWITCH_SCHEME      0
……………………………………………………
OS::channel<unsigned char,10> chn_Rx;//канал на 10 байт
……………………………………………………
//-------------------------------------------------------------------------
#pragma vector = USART_RXC_vect
OS_INTERRUPT void RX(void)
{
OS::scmRTOS_ISRW_TYPE ISR;
UART_Rx();
}
//-------------------------------------------------------------------------
void UART_Rx(void)  
{
unsigned char udrx=UDR;//принимаем байт
if(chn_Rx.get_free_size()) chn_Rx.push(udrx);// запихиваем принятый байт в канал
}
//---------------------------------------------------------------------------
…………………………………………………………………………
OS_PROCESS void TPRx::Exec()
{
  unsigned char count_rx_byte=0;// счетчик принятых байт
  unsigned char RxBuffer[LEN_RX];//приемный буфер
  unsigned char rx_crc=0;// контрольная сумма
    for(;;)
    {
    unsigned char rx=0;
     if (chn_Rx.pop(rx,2))//вытаскиваем из очереди очередной байт
         {
          RxBuffer[count_rx_byte]=rx;//в буфер его
          //вычисляем  КС:
          if(count_rx_byte<LEN_RX-1)  rx_crc=rx_crc^RxBuffer[count_rx_byte];
              else  //если подошел последний байт пакета и КС совпала:
                   if((count_rx_byte==LEN_RX-1)&&(RxBuffer[count_rx_byte]==rx_crc))
                                  Answer();//функция загрузки в ответ  первого байта передачи в UDR
// дальнейшие загрузки байтов- по прерыванию от UART (передача)
          count_rx_byte++;//на следующий байт
          }  else  //если через 2 тика сист. таймера (12 мс) ничего не пришло- сбрасываем параметры приема:
          {
           count_rx_byte=0;//сюда через сек 40 уже не приходим...
           rx_crc=0;
          };
     }//end_of_for(;;)
} end_of_ OS_PROCESS
//---------------------------------------------------------------------------
…………………………………………………………………


Еще по-теме,- в одной из веток по scmRTOS:
Цитата(Сергей Борщ @ Oct 1 2007, 17:53) *
Ну например прерывание передачи по UART забирает данные из OS:channel<uint8_t>. А данные там кончились... В этом случае pop() попытается передать управление другой задаче, и это приведет к краху. Поэтому прежде чем вызвать pop() надо проверить - а есть ли данные. Аналогично для push().


Почему должен быть крах? Вроде так и надо- нет работы- уйди… А в случае вызова рор() или push() из обработчика прерывания ,- перепланировщик там же не имеет действия!
Хотя, если из void UART_Rx(void) исключить "if(chn_Rx.get_free_size()) "- проц виснет савсем.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Feb 4 2008, 13:02
Сообщение #2


Гуру
******

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



или я не до конца понял ваш алгоритм, или в
Код
if((count_rx_byte==LEN_RX-1)&&(RxBuffer[count_rx_byte]==rx_crc))
      Answer();
count_rx_byte++;//на следующий байт
если контрольная сумма не совпала, то вы будете продолжать складывать следующие байты в RxBuffer[count_rx_byte]=rx; и выйдете за пределы буфера.

Почему не попадаете в точку выхода по тайм-ауту действительно непонятно. А системный таймер тикает, его прерывания происходят? Поставьте дерганье ногой в OS::SystemTimerUserHook(), убедитесь, что прерывания работают.

Цитата(Colobox @ Feb 4 2008, 11:18) *
Почему должен быть крах? Вроде так и надо- нет работы- уйди… А в случае вызова рор() или push() из обработчика прерывания ,- перепланировщик там же не имеет действия!
если нет работы (очередь пуста или переполнена) pop() или push() вызовет перепланировку и перевод текущего процесса в ожидание. Но ведь во-первых невозможно предугадать, какой из процессов будет текущим на момент вызова прерывания. И может он спать совсем не хочет smile.gif А во-вторых, вызов планировщика и процедура смены контекста вернет программу в один из потоков, но не в окончание обработчика прерывания. В результате выход из прерывания никогда не произойдет, прерывания обстанутся заблокированными, а на стеке прерванного процесса - каша из регистров, сохраненных обработчиком и переключателем контекста. Примерно так.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
Colobox
сообщение Feb 5 2008, 06:47
Сообщение #3


Участник
*

Группа: Участник
Сообщений: 36
Регистрация: 31-10-07
Пользователь №: 31 901



Цитата(Сергей Борщ @ Feb 4 2008, 16:02) *
если контрольная сумма не совпала, то вы будете продолжать складывать следующие байты в RxBuffer[count_rx_byte]=rx; и выйдете за пределы буфера.

Абсолютно правильное замечание; исправил, но порочный эффект не исчез.
Цитата(Сергей Борщ @ Feb 4 2008, 16:02) *
Почему не попадаете в точку выхода по тайм-ауту действительно непонятно. А системный таймер тикает, его прерывания происходят? Поставьте дерганье ногой в OS::SystemTimerUserHook(), убедитесь, что прерывания работают.

В системе крутится еще один процесс-просто лампочкой мигает, прерывание также сигнализирует о себе; после сбоя связи с ними ничего не происходит- как мигали, так и мигают. Так-что системный таймер тикает.
Цитата(Сергей Борщ @ Feb 4 2008, 16:02) *
если нет работы (очередь пуста или переполнена) pop() или push() вызовет перепланировку и перевод текущего процесса в ожидание. Но ведь во-первых невозможно предугадать, какой из процессов будет текущим на момент вызова прерывания. И может он спать совсем не хочет smile.gif

Серьезный эффект, согласен. Но тогда, может, стоит предусмотреть в этом сервисе, перед переводом текущего процесса в ожидание, некую проверку, скажем, ISR_Nest_Count,- если отлична от нуля, перевод не производить. По-крайней мере, в мануале на ось это стоит оговорить!
Цитата(Сергей Борщ @ Feb 4 2008, 16:02) *
А во-вторых, вызов планировщика и процедура смены контекста вернет программу в один из потоков, но не в окончание обработчика прерывания. В результате выход из прерывания никогда не произойдет, прерывания обстанутся заблокированными, а на стеке прерванного процесса - каша из регистров, сохраненных обработчиком и переключателем контекста. Примерно так.

А разве из обработчика прерывания можно вызвать планировщик и менять контексты? Точнее, будет ли вызов планировщика иметь эффект:
Код
if scmRTOS_CONTEXT_SWITCH_SCHEME == 0
void OS::TKernel::Scheduler()
{
TCritSect cs;
if(ISR_NestCount) return;//в прерывании  ISR_NestCount>0
..........................................
..........................................
..........................................

А уже после отработки прерывания, перед выходом в программу (ISR_NestCount==0), и произойдет вызов планировщика, возымеющий эффект…
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Feb 5 2008, 10:11
Сообщение #4


Гуру
******

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



Цитата(Colobox @ Feb 5 2008, 08:47) *
Так-что системный таймер тикает.
Понятно.
Цитата(Colobox @ Feb 5 2008, 08:47) *
Серьезный эффект, согласен. Но тогда, может, стоит предусмотреть в этом сервисе, перед переводом текущего процесса в ожидание, некую проверку, скажем, ISR_Nest_Count,- если отлична от нуля, перевод не производить. По-крайней мере, в мануале на ось это стоит оговорить!
В вашем же коде есть такая проверка: if(chn_Rx.get_free_size()) т.е. если места нет, то не надо тратить время в прерывании на попытку что-то засунуть а потом на попытку вызвать планировщик. В документации это есть:
Цитата
При использовании сервисов в прерываниях есть определенные особенности. Например, очевидно, что использовать TMutex::Lock() внутри обработчика прерывания является достаточно плохой идеей, т.к., во-первых, мутексы предназначены для разделения доступа к ресурсам на уровне процессов, а не на уровне прерываний, и, во-вторых, ожидать освобождения ресурса, если он был занят, внутри обработчика прерывания все равно не удастся и это приведет только к тому, что процесс, прерванный данным прерыванием, просто будет переведен состояние ожидания в неподходящей и непредсказуемой точке. Фактически процесс будет переведен в неактивное состояние, из которого его вывести можно будет только с помощью функции ForceWakeUpProcess. В любом случае ничего хорошего из этого не получится.
Аналогичная в некотором роде ситуация может получиться при использовании объектов-каналов в обработчике прерываний. Ждать данных из канала внутри ISR не получится и последствия будут аналогичны вышеописанным, а записывать данные в канал тоже не вполне безопасно. Если, к примеру, при записи в канал в нем не окажется достаточно места, то поведение программы окажется далеко не таким, как ожидает пользователь.
И только два типа из всех средств межпроцессного взаимодействия позволяют безопасное и полезное их использование. Это OS::TEventFlag и OS::message. Естественно, безопасность и полезность относятся не к любому их использованию, а только лишь к вызову функций TEventFlag::Signal, TEventFlag::SignalISR, message<T>::send, message<T>::sendISR, и обуславливаются тем обстоятельством, что внутри этих функций ни при каких условиях не производится попыток встать на ожидание и никаких вопросов по поводу достаточного количества памяти (как в случае с каналами) нет.
Цитата(Colobox @ Feb 5 2008, 08:47) *
А разве из обработчика прерывания можно вызвать планировщик и менять контексты? Точнее, будет ли вызов планировщика иметь эффект:
Да, действительно, защита есть, тут вы правы. Судя по этому кусочку кода, вы используете версию 2.0x. Уже больше года развивается версия 3.0, настоятельно рекомендую перейти на нее пока проект не разросся. Версия 2.0 больше развиваться не будет. Возможно вы наткнулись на ошибку, которая в 3.0 исправлена. Если эффект с версией 3.0 повторится, вышлите мне исходник на почту, чтобы я мог погонять его у себя.

P.S. Сейчас scmRTOS живет тут: sourceforge, сайт.

С момента последнего релиза прошло довольно много времени, проект развивается, баги правятся. Лучше всего брать последнюю правку из репозитория:
1) ставите svn
2) Набираете:
Код
svn co https://scmrtos.svn.sourceforge.net/svnroot/scmrtos/trunk/Samples/AVR/IAR_v4.20 scmRTOS_AVR
svn switch https://scmrtos.svn.sourceforge.net/svnroot/scmrtos/trunk/Common scmRTOS_AVR/scmRTOS/Common
svn switch https://scmrtos.svn.sourceforge.net/svnroot/scmrtos/trunk/Ports/AVR/IAR_v4.20 scmRTOS_AVR/scmRTOS/AVR
Получаете папочку scmRTOS_AVR с самыми свежими исходниками. После обновления репозитория (можно следить здесь) заходите в эту папочку, пишете svn up и снова получаете самые свежие исходники. Очень удобно, рекомендую.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
Colobox
сообщение Feb 5 2008, 11:09
Сообщение #5


Участник
*

Группа: Участник
Сообщений: 36
Регистрация: 31-10-07
Пользователь №: 31 901



Цитата(Сергей Борщ @ Feb 5 2008, 13:11) *
В документации это есть.

Да, поторопился...
Цитата(Сергей Борщ @ Feb 5 2008, 13:11) *
Судя по этому кусочку кода, вы используете версию 2.0x.

Версия 3.00, стянутая с сайта, но без обновлений из репозитория.
Прошу прощения,- кусок кода, не проверив, взял из существующего мануала.
Цитата(Сергей Борщ @ Feb 5 2008, 13:11) *
Лучше всего брать последнюю правку из репозитория...
Очень удобно, рекомендую.

Премного благодарен, буду пробовать!
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 19th June 2025 - 21:48
Рейтинг@Mail.ru


Страница сгенерированна за 0.01422 секунд с 7
ELECTRONIX ©2004-2016