|
Работа с UART в пакетном режиме и ОС |
|
|
|
Nov 15 2010, 08:03
|

Местный
  
Группа: Свой
Сообщений: 211
Регистрация: 3-06-06
Пользователь №: 17 742

|
Как правильно организовать работу с пакетным протоколом (что-то наподобие WAKE в собственной реализации) в условиях использования операционки? В данный момент все сделано просто - разбор пакета осуществляется по ходу его приема прямо в прерывании, по окончании приема выставляется событие, которое перехватывает процесс, занимающийся вызовом нужных команд. Ответный пакет формируется в функции обработки команды и запускается отправка по прерыванию. Для синхронного протокола все работает замечательно, но появилась необходимость обеспечить асинхронные сообщения, которые ведомое устройство может формировать самостоятельно, без запроса мастера. В этом случае возникает необходимость использования чего-то вроде кольцевого буфера для предотвращения потери данных. Как правильно реализовать такую схему при наличии операционки? Пока видится только такая схема работы: 1. Процесс, который занимается отправкой данных в порт, занят только тем, что висит в вечном channel.pop() из кольцевого буфера и в случае появления данных выполняет отправку байта в порт. 2. Процесс, который обрабатывает асинхронные события. Например, нажали кнопку. Процесс в этом случае вызывает некую функцию SendInputAsync() в которой формируется пакет и делается необходимое количество channel.push(). Затем процесс уходит в Sleep() на заданное настройками время. Возможно, необходимо сделать процесс на каждое асинхронное событие? Смущает передача управления для отправки каждого байта. Можно, конечно, вызывать channel.pop() с таймаутом и воспользоваться дополнительным событием, которое будет устанавливаться только по добавлению в канал полного пакета. Но как-то громоздко получается. Прошу помощи у более опытных товарищей
--------------------
Good News Everyone!
|
|
|
|
|
 |
Ответов
|
Nov 15 2010, 13:03
|

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

|
Цитата(Pavel V. @ Nov 15 2010, 10:03)  1. Процесс, который занимается отправкой данных в порт, занят только тем, что висит в вечном channel.pop() из кольцевого буфера и в случае появления данных выполняет отправку байта в порт. А почему бы не повесить кольцевой буфер на UART (и опустошать его в прерывании), а сам процесс отправки пакета не обрамить мутексом? Тогда любой процесс сможет оправлять пакеты асинхронно. Что-то типа такого (не wake, но подобный протокол): CODE class bus_frame { public: typedef uint16_t address_t; protected: enum { STA = 0xC0, STO = 0xC1, CTL = 0x7F, TRANSPARENCY = 0x20, }; typedef crc::ccitt crc_t; };
class frame : public bus_frame { public: frame(iodevice & uart); frame(iodevice & uart, address_t address); ~frame();
void send(void const * buffer, size_t size); void send(uint8_t data); // calculate CRC and send transparently
protected: void send_transparently(uint8_t data); static OS::TMutex Mutex; iodevice & Uart; crc_t CRC; };
frame::frame(iodevice & uart, address_t address) : Uart(uart) { Mutex.Lock(); Uart.send(STA); send(address >> 0); send(address >> 8); }
frame::frame(iodevice & uart) : Uart(uart) { Mutex.Lock(); Uart.send(STA); }
frame::~frame() { send_transparently(~CRC >> 0); send_transparently(~CRC >> 8); Uart.send(STO); Mutex.Unlock(); }
void frame::send(uint8_t data) { CRC.calculate(data); send_transparently(data); }
void frame::send_transparently(uint8_t data) { if((data == CTL) || (data == STA) || (data == STO)) { Uart.send(CTL); data ^= TRANSPARENCY; } Uart.send(data); }
void frame::send(void const * buffer, size_t size) { uint8_t const * pSrc = (uint8_t const *)buffer; while(size--) send(*pSrc++); }
void Test(bus_frame::address_t destination) { frame Frame(Uplink, destination); Frame.send("Tipa test", sizeof("Tipa test")); }
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Nov 15 2010, 13:50
|

Местный
  
Группа: Свой
Сообщений: 211
Регистрация: 3-06-06
Пользователь №: 17 742

|
Цитата(Сергей Борщ @ Nov 15 2010, 16:03)  А почему бы не повесить кольцевой буфер на UART (и опустошать его в прерывании), а сам процесс отправки пакета не обрамить мутексом? Тогда любой процесс сможет оправлять пакеты асинхронно. Что-то типа такого (не wake, но подобный протокол): Сергей, огромное спасибо! Вы уже не первый раз мне помогаете дельным советом. Идею Вашу понял, очень интересно! Насколько я понял, константы STA и STO служат признаками начала и конца пакета. Почему их отправку Вы поместили именно в конструктор и деструктор, а не в функцию send()? Функция Uart.send() помещает данные в кольцевой буфер, который опустошается в прерываниях? Не могли бы Вы показать как сделано это место? Интересует сама функция Uart.send() и обработчик прерывания. Я когда экспериментировал с модулем UART (на процессоре MSP430F2618), при постоянно разрешенных прерываниях по отправке, у меня были сложности. Поэтому в текущей реализации я запрещаю прерывание по отправке после отправки пакета целиком, а по попадании пакета в буфер отправки, соответственно, это прерывание разрешаю (тавтология какая-то получилась, но Вы, наверное, поняли что я имею в виду).
--------------------
Good News Everyone!
|
|
|
|
|
Nov 15 2010, 14:22
|

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

|
QUOTE (Pavel V. @ Nov 15 2010, 15:50)  Идею Вашу понял, очень интересно! Насколько я понял, константы STA и STO служат признаками начала и конца пакета. Почему их отправку Вы поместили именно в конструктор и деструктор, а не в функцию send()? Потому что функцию send() можно вызывать несколько раз во время передачи пакета. CODE void raw_message::send(frame & link) const { link.send(Type); link.send(&Header, sizeof(Header)); link.send(this + 1, Size); } void Test() { frame Frame(Uplink); pMessage->send(Frame); } QUOTE (Pavel V. @ Nov 15 2010, 15:50)  Функция Uart.send() помещает данные в кольцевой буфер, который опустошается в прерываниях? Не могли бы Вы показать как сделано это место? Интересует сама функция Uart.send() и обработчик прерывания. Под MSP430F2618 у меня нет, вот под AVR: CODE #define UART_H__ #include <stdint.h> #include <avr/io.h> #include <avr/pgmspace.h> #include <scmRTOS.h> #define UART_RX_BUFF_SIZE 64 #define UART_TX_BUFF_SIZE 64
ISR(USART_RXC_vect); ISR(USART_UDRE_vect);
class uart_t { public: uart_t() {}; bool hasinput(); uint8_t receive(); template <typename T> bool receive(T & item, timeout_t timeout = 0) { return RxBuffer.read((uint8_t * const)&item, sizeof(T), timeout); } void send(uint8_t byte); void sendHEX(uint8_t byte); void send(PGM_P pString); bool tx_complete() { return UCSRA & ( 1 << TXC ); } private: friend void USART_RXC_vect(); friend void USART_UDRE_vect(); void RXC_Handler(); void UDRE_Handler(); private: OS::channel<uint8_t, UART_RX_BUFF_SIZE> RxBuffer; OS::channel<uint8_t, UART_TX_BUFF_SIZE> TxBuffer; }; inline bool uart_t::hasinput (void) { return RxBuffer.get_count(); }
extern uart_t UART; #endif // UART_H__ // ========= uart.cpp ============== #include <avr/interrupt.h> #include "Hardware.h" #include "UART.h"
uint8_t uart_t::receive () { uint8_t Data; RxBuffer.pop(Data); return Data; }
void uart_t::send(uint8_t byte) { TxBuffer.push(byte); UCSRB |= (1<<UDRIE); // UCSRB in io-space, no critical section required } #include <avr/pgmspace.h> void uart_t::sendHEX(uint8_t byte) { static char const PROGMEM Table[] = "0123456789ABCDEF"; send(pgm_read_byte(&Table[byte >> 4])); send(pgm_read_byte(&Table[byte & 0x0F])); } void uart_t::send(PGM_P pString) { char c; while( (c = pgm_read_byte(pString++)) ) { send©; } }
inline void uart_t::RXC_Handler() { char RxData = UDR; if(RxBuffer.get_free_size()) { RxBuffer.push(RxData); } }
OS_INTERRUPT void USART_RXC_vect() { OS::TISRW isr; UART.RXC_Handler(); }
inline void uart_t::UDRE_Handler() { UCSRB &= ~(1<<UDRIE); sei(); { if(TxBuffer.get_count()) { uint8_t Data; TxBuffer.pop(Data); UDR = Data; cli(); // avoid recursive call UCSRB |= (1<<UDRIE); } } }
OS_INTERRUPT void USART_UDRE_vect() { OS::TISRW isr; UART.UDRE_Handler(); }
uart_t UART; QUOTE (Pavel V. @ Nov 15 2010, 15:50)  Я когда экспериментировал с модулем UART (на процессоре MSP430F2618), при постоянно разрешенных прерываниях по отправке, у меня были сложности. Поэтому в текущей реализации я запрещаю прерывание по отправке после отправки пакета целиком, а по попадании пакета в буфер отправки, соответственно, это прерывание разрешаю (тавтология какая-то получилась, но Вы, наверное, поняли что я имею в виду). В AVR иначе и не сделаешь. Там нет возможности программно сбросить флаг готовности передатчика, и мне кажется это правильно: все передали (буфер пуст), нет необходимости в дальнейших прерываниях - запретили прерывания. Появилась необходимость (положили что-то в буфер) - разрешили прерывания, и если передатчик готов (флаг взведен) - сразу побежали в обработчик. А если прерывание было разрешено, опустошило буфер и отключило само себя до того, как в send() его разрешили снова - в обработчике есть проверка на пустоту буфера. Минимум лишних движений.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
Сообщений в этой теме
Pavel V. Работа с UART в пакетном режиме и ОС Nov 15 2010, 08:03 dxp Добавлю свои "пять копеек" к обсуждению.... Nov 17 2010, 04:06 Сергей Борщ QUOTE (dxp @ Nov 17 2010, 06:06) Приемная... Nov 17 2010, 07:58 ReAl Цитата(dxp @ Nov 17 2010, 06:06) Добавлю ... Nov 17 2010, 20:10  dxp Цитата(ReAl @ Nov 18 2010, 02:10) Только ... Nov 18 2010, 06:40   ReAl Цитата(dxp @ Nov 18 2010, 08:40) А за тай... Nov 19 2010, 19:59 Sirko Дабы не создавать похожий топик, спрошу здесь.
Воз... Nov 19 2010, 06:25 remote_job Цитата(Sirko @ Nov 19 2010, 09:25) Отсюда... Nov 19 2010, 07:52 Pavel V. Спасибо за продуктивное обсуждение!
Вынес для... Nov 22 2010, 15:09 AHTOXA Вот тут про стек. Nov 22 2010, 15:17
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|