Артём__ 0 21 января, 2012 Опубликовано 21 января, 2012 · Жалоба Попытался использовать usr::ring_buffer для выдачи отладочного лога в свободный УАРТ. Алгоритм такой: 1. Задача заполняет его данными 2. В прерывании таймера проверяется не пуст ли буфер, если не пуст, то разрешается прерывание по пустому буферу передачика уарт. 3. В прерывании DRE посылается след.байт и запрещаются прерывания если байтов больше нет. class TExtTxBuffer { usr::ring_buffer<unsigned char, EXTERNAL_UART_TX_BUFFER, unsigned short> fifo; public: void WriteByte(unsigned char new_byte) { fifo.push(new_byte); } unsigned char ReadByte(void) { return fifo.pop(); } void WriteAnsiString(unsigned char __flash *data) { while (*data) { fifo.push(*data++); } } void WriteAnsiString(unsigned char *data) { while (*data) { fifo.push(*data++); } } unsigned char BufferNotEmpty(void) { if (fifo.get_count()) return 1; return 0; } }; void StopExtUartTx() { UCSR0B&=~(1<<UDRIE0); } #pragma vector=USART0_UDRE_vect __interrupt void ExtUartTx() { OS::TISRW_SS ISRW; unsigned char i=ExtTxPtr.ReadByte(); UDR0=i; if (ExtTxPtr.BufferNotEmpty()==0) StopExtUartTx(); } В какой-то момент обнаружил что передача данных прекратилась. Остановил программу. Увидел следующее (цифры примерные): First=10; Last=9; Count=0; B соответственно код if (ExtTxPtr.BufferNotEmpty()) StartExtUartTx(); прерывание USART0_UDRE_vect запускать не стал. Что неправильно делаю? Неправильно объявил (не использовал volatile)? usr::ring_buffer<unsigned char, EXTERNAL_UART_TX_BUFFER, unsigned short> fifo; Нужны ли критические секции перед вызовом BufferNotEmpty и WriteByte? Спасибо. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 18 21 января, 2012 Опубликовано 21 января, 2012 · Жалоба ring_buffer не обеспечивает безопасного многопоточного доступа. Используйте OS::channel, он специально предназначен для таких целей. Это, на самом деле, тот же самый ring_buffer, но с механизмами блокировки. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Артём__ 0 21 января, 2012 Опубликовано 21 января, 2012 · Жалоба ring_buffer не обеспечивает безопасного многопоточного доступа. Спасибо, AHTOXA. Чувствовал когда писал что граблю закладываю. Предчуствия меня не обманули. Попробую выйти из положения пока так: usr::ring_buffer<unsigned char, EXTERNAL_UART_TX_BUFFER, volatile unsigned short> fifo; void WriteByte(unsigned char new_byte) { TCritSect cs; fifo.push(new_byte); } void WriteAnsiString(unsigned char __flash *data) { TCritSect cs; while (*data) { fifo.push(*data++); } } void WriteAnsiString(unsigned char *data) { TCritSect cs; while (*data) { fifo.push(*data++); } } Используйте OS::channel, он специально предназначен для таких целей Понял, channel подходящее будет. Это, на самом деле, тот же самый ring_buffer, но с механизмами блокировки. Зачем тогда ring_buffer нужен в чистом виде? Только как основа для того же OS::channel? Где его использовать? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
IgorKossak 0 22 января, 2012 Опубликовано 22 января, 2012 · Жалоба Попробую выйти из положения пока так: Вторая и третья функции - плохие, блокируют прерывания и, как следствие, перепланирование процессов на неопределённое время, особенно в случае длинных стрингов. Кроме того, они отличаются только типом параметра, можно было бы сделать шаблоном. Зачем тогда ring_buffer нужен в чистом виде? Только как основа для того же OS::channel? В документации и в комментариях сказано, что он нужен для служебных операций, в частности, для OS::channel. Где его использовать? Его можно применять там, где не критично, т. е. если синхронизация между процессами (наполняющим и выгребающим) делается другими способами. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Артём__ 0 22 января, 2012 Опубликовано 22 января, 2012 · Жалоба Вторая и третья функции - плохие, блокируют прерывания и, как следствие, перепланирование процессов на неопределённое время, особенно в случае длинных стрингов. Согласен, когда в программу вписывал - понял. Сделал так: void WriteAnsiString(unsigned char *data) { TCritSect cs; while (*data) { { TCritSect cs; fifo.push(*data++); } } } Кроме того, они отличаются только типом параметра, можно было бы сделать шаблоном. Хорошая мысль, осталось шаблоны освоить. В документации и в комментариях сказано, что он нужен для служебных операций, в частности, для OS::channel. Проглядел. Спасибо. Его можно применять там, где не критично, т. е. если синхронизация между процессами (наполняющим и выгребающим) делается другими способами. Какими? Не представил.... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
IgorKossak 0 22 января, 2012 Опубликовано 22 января, 2012 · Жалоба Сделал так: Если первую строку с TCritSect cs; выкинуть, то получится ещё лучше. Хорошая мысль, осталось шаблоны освоить. Это быстрее, чем Вы писали эту фразу. Хотя бы по примерам из той же scmRTOS. Какими? Не представил.... Сигналами, семафорами или, на худой конец, так как в результате у Вас получилось с TCritSect cs. Но это всё не так красиво, как с каналами. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Артём__ 0 22 января, 2012 Опубликовано 22 января, 2012 · Жалоба Если первую строку с TCritSect cs; выкинуть, то получится ещё лучше. Да, это я хорошо исправил...поспешил. Это быстрее, чем Вы писали эту фразу. Хотя бы по примерам из той же scmRTOS. Будем посмотреть Сигналами, семафорами или, на худой конец, так как в результате у Вас получилось с TCritSect cs. Но это всё не так красиво, как с каналами. Ясно. Спасибо. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться