Артём__ 1 January 21, 2012 Posted January 21, 2012 · Report post Попытался использовать 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? Спасибо. Quote Share this post Link to post Share on other sites More sharing options...
AHTOXA 25 January 21, 2012 Posted January 21, 2012 · Report post ring_buffer не обеспечивает безопасного многопоточного доступа. Используйте OS::channel, он специально предназначен для таких целей. Это, на самом деле, тот же самый ring_buffer, но с механизмами блокировки. Quote Share this post Link to post Share on other sites More sharing options...
Артём__ 1 January 21, 2012 Posted January 21, 2012 · Report post 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? Где его использовать? Quote Share this post Link to post Share on other sites More sharing options...
IgorKossak 1 January 22, 2012 Posted January 22, 2012 · Report post Попробую выйти из положения пока так: Вторая и третья функции - плохие, блокируют прерывания и, как следствие, перепланирование процессов на неопределённое время, особенно в случае длинных стрингов. Кроме того, они отличаются только типом параметра, можно было бы сделать шаблоном. Зачем тогда ring_buffer нужен в чистом виде? Только как основа для того же OS::channel? В документации и в комментариях сказано, что он нужен для служебных операций, в частности, для OS::channel. Где его использовать? Его можно применять там, где не критично, т. е. если синхронизация между процессами (наполняющим и выгребающим) делается другими способами. Quote Share this post Link to post Share on other sites More sharing options...
Артём__ 1 January 22, 2012 Posted January 22, 2012 · Report post Вторая и третья функции - плохие, блокируют прерывания и, как следствие, перепланирование процессов на неопределённое время, особенно в случае длинных стрингов. Согласен, когда в программу вписывал - понял. Сделал так: void WriteAnsiString(unsigned char *data) { TCritSect cs; while (*data) { { TCritSect cs; fifo.push(*data++); } } } Кроме того, они отличаются только типом параметра, можно было бы сделать шаблоном. Хорошая мысль, осталось шаблоны освоить. В документации и в комментариях сказано, что он нужен для служебных операций, в частности, для OS::channel. Проглядел. Спасибо. Его можно применять там, где не критично, т. е. если синхронизация между процессами (наполняющим и выгребающим) делается другими способами. Какими? Не представил.... Quote Share this post Link to post Share on other sites More sharing options...
IgorKossak 1 January 22, 2012 Posted January 22, 2012 · Report post Сделал так: Если первую строку с TCritSect cs; выкинуть, то получится ещё лучше. Хорошая мысль, осталось шаблоны освоить. Это быстрее, чем Вы писали эту фразу. Хотя бы по примерам из той же scmRTOS. Какими? Не представил.... Сигналами, семафорами или, на худой конец, так как в результате у Вас получилось с TCritSect cs. Но это всё не так красиво, как с каналами. Quote Share this post Link to post Share on other sites More sharing options...
Артём__ 1 January 22, 2012 Posted January 22, 2012 · Report post Если первую строку с TCritSect cs; выкинуть, то получится ещё лучше. Да, это я хорошо исправил...поспешил. Это быстрее, чем Вы писали эту фразу. Хотя бы по примерам из той же scmRTOS. Будем посмотреть Сигналами, семафорами или, на худой конец, так как в результате у Вас получилось с TCritSect cs. Но это всё не так красиво, как с каналами. Ясно. Спасибо. Quote Share this post Link to post Share on other sites More sharing options...