Jump to content
    

Вопрос по usr::ring_buffer

Попытался использовать 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?

Спасибо.

 

 

Share this post


Link to post
Share on other sites

ring_buffer не обеспечивает безопасного многопоточного доступа. Используйте OS::channel, он специально предназначен для таких целей. Это, на самом деле, тот же самый ring_buffer, но с механизмами блокировки.

 

Share this post


Link to post
Share on other sites

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?

Где его использовать?

Share this post


Link to post
Share on other sites

Попробую выйти из положения пока так:

Вторая и третья функции - плохие, блокируют прерывания и, как следствие, перепланирование процессов на неопределённое время, особенно в случае длинных стрингов. Кроме того, они отличаются только типом параметра, можно было бы сделать шаблоном.

Зачем тогда ring_buffer нужен в чистом виде?

Только как основа для того же OS::channel?

В документации и в комментариях сказано, что он нужен для служебных операций, в частности, для OS::channel.

Где его использовать?

Его можно применять там, где не критично, т. е. если синхронизация между процессами (наполняющим и выгребающим) делается другими способами.

Share this post


Link to post
Share on other sites

Вторая и третья функции - плохие, блокируют прерывания и, как следствие, перепланирование процессов на неопределённое время, особенно в случае длинных стрингов.

 

Согласен, когда в программу вписывал - понял.

Сделал так:

    void WriteAnsiString(unsigned char *data)
    {
        TCritSect cs; 
        while (*data) {
                {
                TCritSect cs; 
                 fifo.push(*data++);
                }
        }
    }

Кроме того, они отличаются только типом параметра, можно было бы сделать шаблоном.

Хорошая мысль, осталось шаблоны освоить.

 

В документации и в комментариях сказано, что он нужен для служебных операций, в частности, для OS::channel.

Проглядел. Спасибо.

 

Его можно применять там, где не критично, т. е. если синхронизация между процессами (наполняющим и выгребающим) делается другими способами.

Какими? Не представил....

 

 

 

 

Share this post


Link to post
Share on other sites

Сделал так:

Если первую строку с TCritSect cs; выкинуть, то получится ещё лучше.

Хорошая мысль, осталось шаблоны освоить.

Это быстрее, чем Вы писали эту фразу. Хотя бы по примерам из той же scmRTOS.

Какими? Не представил....

Сигналами, семафорами или, на худой конец, так как в результате у Вас получилось с TCritSect cs. Но это всё не так красиво, как с каналами.

Share this post


Link to post
Share on other sites

Если первую строку с TCritSect cs; выкинуть, то получится ещё лучше.

Да, это я хорошо исправил...поспешил.

 

Это быстрее, чем Вы писали эту фразу. Хотя бы по примерам из той же scmRTOS.

Будем посмотреть

 

Сигналами, семафорами или, на худой конец, так как в результате у Вас получилось с TCritSect cs. Но это всё не так красиво, как с каналами.

Ясно. Спасибо.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...