abutorin 0 13 января, 2013 Опубликовано 13 января, 2013 · Жалоба Добрый вечер. Пробую сделать передачу по USART с использование буфера. Для межпроцессорного удобства очень нравится использовать OS::channel. Возможно ли его использовать и в прерываниях? Точнее интересует процедура получения элемента из канала? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 18 13 января, 2013 Опубликовано 13 января, 2013 · Жалоба Использовать канал в прерывании можно. Учтите только, что если вы в него что-то заталкиваете, а он полон, то будет сделана попытка усыпить прерванный процесс и дождаться освобождения (или при доставании из пустого канала). Вероятно, это не то поведение, которое ожидается в прерывании:) Поэтому проверяйте наличие свободного места при запихивании чего-то в канал, и наличие данных при доставании из канала. Примерно вот так: 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(); } } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
abutorin 0 14 января, 2013 Опубликовано 14 января, 2013 · Жалоба Спасибо, проверку заполнености, проверку пустоты я уже учел. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Vasya777 0 15 января, 2013 Опубликовано 15 января, 2013 (изменено) · Жалоба Мне кажется для обмена по интерфейсам связи лучше использовать message, там есть специальный метод для вызова из прерываний. А уже в обычном процессе складывать сообщения в буфер. Поправьте, если я что-то не так сказал, я ещё новичёк. Изменено 15 января, 2013 пользователем Vasya777 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
abutorin 0 15 января, 2013 Опубликовано 15 января, 2013 (изменено) · Жалоба Использовать канал в прерывании можно. Учтите только, что если вы в него что-то заталкиваете, а он полон, то будет сделана попытка усыпить прерванный процесс и дождаться освобождения (или при доставании из пустого канала). Вероятно, это не то поведение, которое ожидается в прерывании:) Поэтому проверяйте наличие свободного места при запихивании чего-то в канал, и наличие данных при доставании из канала. Примерно так и делал. 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. Изменено 15 января, 2013 пользователем abutorin Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Артём__ 0 15 января, 2013 Опубликовано 15 января, 2013 · Жалоба Не знаю почему зависает, наверное что-то неправильно ... Не пойму, в чём сермяга посать всюду this->? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
abutorin 0 15 января, 2013 Опубликовано 15 января, 2013 · Жалоба Не знаю почему зависает, наверное что-то неправильно ... Не пойму, в чём сермяга посать всюду 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, запрет снимается в деструкторе, так вот деструктор не вызовется, т.к. потребитель канала находится в прерывании. Получается что канал использовать с прерываниями не получится. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Артём__ 0 15 января, 2013 Опубликовано 15 января, 2013 · Жалоба Объектный подход, Объектный - это хорошо, только this-> зачем всегда писать? попробуйте без него. Писанины меньше. Посмотрел поглубже, помоему нашел в чем проблема: Проблема в отсутствии метода push_isr. А вот почему его нет - вопрос? Наверное руки недошли...Применять то можно судя по примерам выше. т.к. потребитель канала находится в прерывании. Хуже того - будет усыплён процесс прерванный прерыванием (Idle например) и наверное не только это . Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
abutorin 0 15 января, 2013 Опубликовано 15 января, 2013 · Жалоба Проблему решил использовав События: 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); } Решение черновое в плане оформления класа, но концептуально думаю досточно простое и надежное. Оно правда подразумевает что заполнять буфер будет только один поток, т.к. из средств синхронизации используется только критическая секция на проверку заполненности. Объектный - это хорошо, только this-> зачем всегда писать? попробуйте без него. Писанины меньше. если писать this то IDE подставляет выбор членов класса ). Так что this писать зачастую короче чем помнить точное название члена. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Артём__ 0 15 января, 2013 Опубликовано 15 января, 2013 · Жалоба если писать this то IDE подставляет выбор членов класса ). Так что this писать зачастую короче чем помнить точное название члена. На что только не пойдёт человек, лишь бы новое не осваивать. IDE у вас какая-то устаревшая. А IO-регистры подсказывает? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
abutorin 0 15 января, 2013 Опубликовано 15 января, 2013 · Жалоба На что только не пойдёт человек, лишь бы новое не осваивать. IDE у вас какая-то устаревшая. А IO-регистры подсказывает? Второйдовод писать всегда, этоодним взглядом на код понятно что это член класса а не какаянибудь переменная локальная. IDE у меня Eclipse под линуксом. Последнее время работают только с STM32 и использую стандартную библиотеку, до регистров решил не опускатся. Сейчас больше интересует "бизнес-логика" алгоритмов. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Артём__ 0 15 января, 2013 Опубликовано 15 января, 2013 · Жалоба Второйдовод писать всегда, этоодним взглядом на код понятно что это член класса а не какаянибудь переменная локальная. Если писать всега this, то сомнений не возникнет... а не какаянибудь переменная локальная. обычно так делаю if (local_variable != GlobalVariable) , то есть через правила именования, но они у каждого свои, да. IDE у меня Eclipse под линуксом. Ошибся, IDE - не устаревшая. Последнее время работают только с STM32 и использую стандартную библиотеку, до регистров решил не опускатся. Сейчас больше интересует "бизнес-логика" алгоритмов. "решил не опускатся" или решил не подниматься? Сейчас больше интересует "бизнес-логика" алгоритмов. Логика у вас... в смысле логика тоже дело... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 143 15 января, 2013 Опубликовано 15 января, 2013 · Жалоба Судя по коду, push выполняется с запретом прерывания. Как я понимаю работу TCritSect, запрет снимается в деструкторе, так вот деструктор не вызовется, т.к. потребитель канала находится в прерывании.Прерывания будут разрешены во время suspend() при передаче управления другому процессу. Что касается вашей проблемы - мне кажется причина в том, что вы делаете USART_ClearITPendingBit(this->PORT,USART_IT_TXE); даже если данных не было и ничего не было передано. И когда данные в канале появляются - у процессора нет причин вызвать прерывание и отправить их. Хотя я не очень хорошо помню, как этот механизм (pending) работает в кортексах. Также полагаю, что объект типа OS::TCritSect вы в начале обработчика прерывания создаете. Если нет - это тоже может быть причиной. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
abutorin 0 16 января, 2013 Опубликовано 16 января, 2013 · Жалоба Прерывания будут разрешены во время 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 я не нашел включение прерываний. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Артём__ 0 16 января, 2013 Опубликовано 16 января, 2013 · Жалоба А в какой момент происходи включение прерываний? в suspend я не нашел включение прерываний. В suspend произойдёт перепланировка (reschedule), запустится на выполнение очередной готовый процесс и где-то в конце этой процедуры будут разрешены прерывания. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться