Перейти к содержанию
    

Вопрос по 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?

Спасибо.

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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?

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

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

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

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

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

Сделал так:

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

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

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

 

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

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

 

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

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

 

 

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Сделал так:

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

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

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

 

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

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

 

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...