|
|
  |
Возможность использования OS::channel в прерываниях |
|
|
|
Jan 13 2013, 19:25
|
Участник

Группа: Участник
Сообщений: 40
Регистрация: 3-09-12
Пользователь №: 73 374

|
Добрый вечер. Пробую сделать передачу по USART с использование буфера. Для межпроцессорного удобства очень нравится использовать OS::channel. Возможно ли его использовать и в прерываниях? Точнее интересует процедура получения элемента из канала?
|
|
|
|
|
Jan 13 2013, 20:45
|

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

|
Использовать канал в прерывании можно. Учтите только, что если вы в него что-то заталкиваете, а он полон, то будет сделана попытка усыпить прерванный процесс и дождаться освобождения (или при доставании из пустого канала). Вероятно, это не то поведение, которое ожидается в прерывании  Поэтому проверяйте наличие свободного места при запихивании чего-то в канал, и наличие данных при доставании из канала. Примерно вот так: Код void uart_t::irq_handler(){ uint16_t status = USARTx->SR; if (status & USART_SR_RXNE){ uint8_t ch = USARTx->DR; if (RxChannel.get_free_size()) RxChannel.push(ch); } if (status & USART_SR_TXE){ if (TxChannel.get_count()){ char ch = 0; TxChannel.pop(ch); USARTx->DR = ch; } else disable_tx_interrupt(); } }
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Jan 14 2013, 02:40
|
Участник

Группа: Участник
Сообщений: 40
Регистрация: 3-09-12
Пользователь №: 73 374

|
Спасибо, проверку заполнености, проверку пустоты я уже учел.
|
|
|
|
|
Jan 15 2013, 15:07
|
Участник

Группа: Участник
Сообщений: 29
Регистрация: 22-01-12
Пользователь №: 69 790

|
Мне кажется для обмена по интерфейсам связи лучше использовать message, там есть специальный метод для вызова из прерываний. А уже в обычном процессе складывать сообщения в буфер. Поправьте, если я что-то не так сказал, я ещё новичёк.
Сообщение отредактировал Vasya777 - Jan 15 2013, 15:08
|
|
|
|
|
Jan 15 2013, 19:16
|
Участник

Группа: Участник
Сообщений: 40
Регистрация: 3-09-12
Пользователь №: 73 374

|
Цитата(AHTOXA @ Jan 14 2013, 00:45)  Использовать канал в прерывании можно. Учтите только, что если вы в него что-то заталкиваете, а он полон, то будет сделана попытка усыпить прерванный процесс и дождаться освобождения (или при доставании из пустого канала). Вероятно, это не то поведение, которое ожидается в прерывании  Поэтому проверяйте наличие свободного места при запихивании чего-то в канал, и наличие данных при доставании из канала. Примерно так и делал. Код class usart_t { public: OS::channel<uint8_t,4> Rxbuf; OS::channel<uint8_t,4> Txbuf; USART_TypeDef * PORT;
INLINE void it_handler () {
if (USART_GetITStatus(this->PORT,USART_IT_TXE) != RESET) { { if(this->Txbuf.get_count()) { uint8_t data; this->Txbuf.pop(data); USART_SendData(this->PORT,data); } else { USART_ITConfig(this->PORT, USART_IT_TXE, DISABLE); }
}
USART_ClearITPendingBit(this->PORT,USART_IT_TXE); }
}
void send(const uint8_t & data) { this->Txbuf.push(data); USART_ITConfig(this->PORT, USART_IT_TXE, ENABLE);
} Размер буфера 4 элемента. заполняю его в одном из потоков: Код for(i=0;i<8;i++) { usart.send(i+0x30); }
OS::sleep(1000); Задача проверить работоспособность при заполнении буфера до отказа. В результата камень зависает в прерывании. Причем смотрю терминалом на компьютере, нормально отправляется только 2 байта. Поэкспериментировал немного с размером буфера и размером отправляемых данных, если размер буфера поставить 5 и отправлять 8 байт то все работает нормально, размер буфера 14 количество отправляемых данных 16 тоже нормально. На лицо правило размер буфера = количество отправляемых данных - 2.
Сообщение отредактировал abutorin - Jan 15 2013, 19:03
|
|
|
|
|
Jan 15 2013, 19:31
|
Участник

Группа: Участник
Сообщений: 40
Регистрация: 3-09-12
Пользователь №: 73 374

|
Цитата(_Артём_ @ Jan 15 2013, 23:26)  Не знаю почему зависает, наверное что-то неправильно ... Не пойму, в чём сермяга посать всюду this->? Объектный подход, да можно былобы статичным класом обойтись, думаю это не критично. Посмотрел поглубже, помоему нашел в чем проблема: Код template<typename T, uint16_t Size, typename S> void OS::channel<T, Size, S>::push(const T& item) { TCritSect cs;
while(!pool.get_free_size()) { // channel is full, suspend current process until data removed suspend(ProducersProcessMap); }
pool.push_back(item); resume_all(ConsumersProcessMap); } Судя по коду, push выполняется с запретом прерывания. Как я понимаю работу TCritSect, запрет снимается в деструкторе, так вот деструктор не вызовется, т.к. потребитель канала находится в прерывании. Получается что канал использовать с прерываниями не получится.
|
|
|
|
|
Jan 15 2013, 20:10
|
Гуру
     
Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322

|
Цитата(abutorin @ Jan 15 2013, 21:31)  Объектный подход, Объектный - это хорошо, только this-> зачем всегда писать? попробуйте без него. Писанины меньше. Цитата(abutorin @ Jan 15 2013, 21:31)  Посмотрел поглубже, помоему нашел в чем проблема: Проблема в отсутствии метода push_isr. А вот почему его нет - вопрос? Наверное руки недошли...Применять то можно судя по примерам выше. Цитата(abutorin @ Jan 15 2013, 21:31)  т.к. потребитель канала находится в прерывании. Хуже того - будет усыплён процесс прерванный прерыванием (Idle например) и наверное не только это .
|
|
|
|
|
Jan 15 2013, 20:14
|
Участник

Группа: Участник
Сообщений: 40
Регистрация: 3-09-12
Пользователь №: 73 374

|
Проблему решил использовав События: Код class usart { public: usr::ring_buffer<uint8_t, 10, uint8_t> TxPool;
OS::TEventFlag TxNotFull;
USART_TypeDef * PORT;
INLINE void it_handler () {
if (USART_GetITStatus(this->PORT,USART_IT_TXE) != RESET) { { if(this->TxPool.get_count()) { USART_SendData(this->PORT,this->TxPool.pop()); this->TxNotFull.signal_isr(); } else { USART_ITConfig(this->PORT, USART_IT_TXE, DISABLE); } } USART_ClearITPendingBit(this->PORT,USART_IT_TXE); }
}
INLINE bool full () { TCritSect cs;
return !this->TxPool.get_free_size();
}
void send(const uint8_t & data) {
this->TxNotFull.clear();
while (this->full()) { this->TxNotFull.wait(); }
this->TxPool.push(data);
USART_ITConfig(USART1, USART_IT_TXE, ENABLE);
} Решение черновое в плане оформления класа, но концептуально думаю досточно простое и надежное. Оно правда подразумевает что заполнять буфер будет только один поток, т.к. из средств синхронизации используется только критическая секция на проверку заполненности. Цитата(_Артём_ @ Jan 16 2013, 00:10)  Объектный - это хорошо, только this-> зачем всегда писать? попробуйте без него. Писанины меньше. если писать this то IDE подставляет выбор членов класса ). Так что this писать зачастую короче чем помнить точное название члена.
|
|
|
|
|
Jan 15 2013, 20:24
|
Участник

Группа: Участник
Сообщений: 40
Регистрация: 3-09-12
Пользователь №: 73 374

|
Цитата(_Артём_ @ Jan 16 2013, 00:20)  На что только не пойдёт человек, лишь бы новое не осваивать. IDE у вас какая-то устаревшая.
А IO-регистры подсказывает? Второйдовод писать всегда, этоодним взглядом на код понятно что это член класса а не какаянибудь переменная локальная. IDE у меня Eclipse под линуксом. Последнее время работают только с STM32 и использую стандартную библиотеку, до регистров решил не опускатся. Сейчас больше интересует "бизнес-логика" алгоритмов.
|
|
|
|
|
Jan 15 2013, 20:52
|
Гуру
     
Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322

|
Цитата(abutorin @ Jan 15 2013, 22:24)  Второйдовод писать всегда, этоодним взглядом на код понятно что это член класса а не какаянибудь переменная локальная. Если писать всега this, то сомнений не возникнет... Цитата(abutorin @ Jan 15 2013, 22:24)  а не какаянибудь переменная локальная. обычно так делаю Код if (local_variable != GlobalVariable) , то есть через правила именования, но они у каждого свои, да. Цитата(abutorin @ Jan 15 2013, 22:24)  IDE у меня Eclipse под линуксом. Ошибся, IDE - не устаревшая. Цитата(abutorin @ Jan 15 2013, 22:24)  Последнее время работают только с STM32 и использую стандартную библиотеку, до регистров решил не опускатся. Сейчас больше интересует "бизнес-логика" алгоритмов. "решил не опускатся" или решил не подниматься? Цитата(abutorin @ Jan 15 2013, 22:24)  Сейчас больше интересует "бизнес-логика" алгоритмов. Логика у вас... в смысле логика тоже дело...
|
|
|
|
|
Jan 15 2013, 22:46
|

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

|
QUOTE (abutorin @ Jan 15 2013, 21:31)  Судя по коду, push выполняется с запретом прерывания. Как я понимаю работу TCritSect, запрет снимается в деструкторе, так вот деструктор не вызовется, т.к. потребитель канала находится в прерывании. Прерывания будут разрешены во время suspend() при передаче управления другому процессу. Что касается вашей проблемы - мне кажется причина в том, что вы делаете USART_ClearITPendingBit(this->PORT,USART_IT_TXE); даже если данных не было и ничего не было передано. И когда данные в канале появляются - у процессора нет причин вызвать прерывание и отправить их. Хотя я не очень хорошо помню, как этот механизм (pending) работает в кортексах. Также полагаю, что объект типа OS::TCritSect вы в начале обработчика прерывания создаете. Если нет - это тоже может быть причиной.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jan 16 2013, 03:29
|
Участник

Группа: Участник
Сообщений: 40
Регистрация: 3-09-12
Пользователь №: 73 374

|
Цитата(Сергей Борщ @ Jan 16 2013, 02:46)  Прерывания будут разрешены во время suspend() при передаче управления другому процессу. Что касается вашей проблемы - мне кажется причина в том, что вы делаете USART_ClearITPendingBit(this->PORT,USART_IT_TXE); даже если данных не было и ничего не было передано. И когда данные в канале появляются - у процессора нет причин вызвать прерывание и отправить их. Хотя я не очень хорошо помню, как этот механизм (pending) работает в кортексах. Также полагаю, что объект типа OS::TCritSect вы в начале обработчика прерывания создаете. Если нет - это тоже может быть причиной. USART_ClearITPendingBit(this->PORT,USART_IT_TXE); Это очистка признака возникновения прерывания, в у STM32 большинство битов (признаков) прерывания необходимо очищать вручную. Прерывание по USART_IT_TXE выключается командой USART_ITConfig(this->PORT, USART_IT_TXE, DISABLE); только в случае если канал пустой. А в процедуре которая заполняет канал send это прерывание всегда включаетсся. USART_ITConfig(USART1, USART_IT_TXE, ENABLE); Посмотрел еще раз Код void OS::TService::suspend(TProcessMap volatile & waiters_map) { TProcessMap PrioTag = cur_proc_prio_tag(); set_prio_tag(waiters_map, PrioTag); // put current process to wait map clr_prio_tag(ready_process_map(), PrioTag); // remove current process from ready map #if scmRTOS_DEBUG_ENABLE == 1 cur_proc_waiting_for() = this; // catch current service address to process debug data #endif
#if scmRTOS_PROCESS_RESTART_ENABLE == 1 cur_proc_waiting_map() = &waiters_map; #endif reschedule(); #if scmRTOS_DEBUG_ENABLE == 1 cur_proc_waiting_for() = 0; // remove current service address from process debug data #endif #if scmRTOS_PROCESS_RESTART_ENABLE == 1 cur_proc_waiting_map() = 0; #endif }
void OS::channel<T, Size, S>::push(const T& item) { TCritSect cs;
while(!pool.get_free_size()) { // channel is full, suspend current process until data removed suspend(ProducersProcessMap); }
pool.push_back(item); resume_all(ConsumersProcessMap); } А в какой момент происходи включение прерываний? в suspend я не нашел включение прерываний.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|