реклама на сайте
подробности

 
 
2 страниц V   1 2 >  
Reply to this topicStart new topic
> очередь данных для вывода через USART, как увеличить скорость вывода данных?
skopus
сообщение Mar 1 2006, 07:36
Сообщение #1


Участник
*

Группа: Свой
Сообщений: 65
Регистрация: 31-08-05
Из: Moscow
Пользователь №: 8 124



USART настроен на скорость 115200.

Проблема заключается в следующем :

Необходимо за 100 тактов таймера частотой Fosc/8 = 7.373/8 Mhz = 921.5 Khz выести через USART минимум 10 байт данных. Лучше даже 15.
Есть следующая функция, написанная на IAR C 3.11 :
Код
void MA_PutCharCh0_USART( unsigned char Data )
{
    /*--- Wait for USART data register empty ---*/
    while( !(UCSR0A & __BIT_MASK( UDRE0 ) ) )
    {
        /*--- Do nothing ---*/
       ;
    }
    /*--- Send a character ---*/
    UDR0 = Data;
} /* MA_PutCharCh0_USART */

Очень много теряется на ожидание - я успеваю в этом случае выводить только 2 байта данных.

Я пробовал организовать очередь вывода через линейный однонаправленный список - но здесь нет шансов. Функция malloc(..) выполняется очень долго.

Думаю что алгоритм должен быть таким :

1. Занести данные в очередь вывода
2. Если не установлен UDRE0, выйти из процедуры, иначе занести данные в UDR0 и удалить их из буффера
Все это нужно повторять как-то циклически, причем параллельно с программой прерывания...

Может можно организовать очередь вывода на ASMе без использования динамической памяти?
И как тогда запараллелить с прерыванием вывод данных из очереди в USART ?

Уже второй день не могу придумать как это реализовать в IAR C.
Сейчас MA_PutCharCh0_USART() вызывается в теле прерывания всего два раза sad.gif
Go to the top of the page
 
+Quote Post
defunct
сообщение Mar 1 2006, 07:47
Сообщение #2


кекс
******

Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326



Пользуйтесь прерываниями.

Данные складывайте в Fifo.
По прерыванию Tx переходите к отправке сл. байта.


вот заготовка:

Код
#include <io.h>
#include "com_routines.h"
#ifndef UDR
#define UDR UDR0
#endif
#define QUEUE_LENGTH (32)

char COMQueue[QUEUE_LENGTH];
unsigned char QueueHead, QueueTail;
unsigned char QueueBusy = 0;


void InitCOMQueue()
{
   QueueHead = 0;
   QueueTail = 0;
}


// Вызывать эту функцию в основном цикле программы
void CheckCOMQueue()
{
    if (!QueueBusy)
    if (QueueHead != QueueTail)
    {
      QueueBusy = 1;
      UDR = COMQueue[QueueHead];
      QueueHead++;
      if (QueueHead > QUEUE_LENGTH)
         QueueHead = 0;
    }
}

// А эту функцию в обработчике прерывания UART_TX
void CharSent()
{
  QueueBusy = 0;
}


void SendByte(unsigned char data)
{
  COMQueue[QueueTail] = data;
  QueueTail++;
  if (QueueTail > QUEUE_LENGTH)
     QueueTail = 0;
}
Go to the top of the page
 
+Quote Post
KRS
сообщение Mar 1 2006, 07:51
Сообщение #3


Профессионал
*****

Группа: Модераторы
Сообщений: 1 951
Регистрация: 27-08-04
Из: Санкт-Петербург
Пользователь №: 555



Лучше всего циклический буфер на двух указателях (примерно как еще в древних BIOS клавиатурных)
Для простоты кода отправлять данные имеет смысл только в прерывании, а после укладки байтов в очередь прерывание разрешать, а в прерывании если байтов для отправки нет запрещать их.

Для буфера можно использовать массив и 2 индекса
примерно так:

Код
char UartBuf[64];
volatile char UartPut=0;
volatile char UartGet=0;

//класть байты в очередь
char Tmp;
Tmp=UartPut;
UartBuf[Tmp++]=.....
Tmp&=63;
UartBuf[Tmp++]=.....
Tmp&=63;
UartPut=Tmp; //сохраняем указатель
UCSRB|=(1<<UDRIE); //разрешаем прерывание не важно было оно разрешено или нет



// а обработчик прерывания

char Tmp;
Tmp=UartGet;
if (Tmp==UartPut) {
  UCSRB&=~(1<<UDRIE); //запрещаем  прерывание байтов на отправку нет
} else {
  UDR=UartBuf[Tmp++];
  Tmp&=63;
  UartGet=Tmp; //сохраняем указатель
}
Go to the top of the page
 
+Quote Post
Old1
сообщение Mar 1 2006, 08:13
Сообщение #4


Знающий
****

Группа: Свой
Сообщений: 697
Регистрация: 26-07-05
Из: Могилев
Пользователь №: 7 095



На эту тему есть appnote AVR306 c примерами.
AVR306.pdf
AVR306.zip
Обратите внимание на файл UART2.c (в архиве avr306.zip).
Go to the top of the page
 
+Quote Post
defunct
сообщение Mar 1 2006, 08:22
Сообщение #5


кекс
******

Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326



Цитата(Old1 @ Mar 1 2006, 10:13) *
Обратите внимание на файл UART2.c (в архиве avr306.zip).

Сильно подвязан к платформе. Код, который я привел с легкостью переносится на любой МК.
Go to the top of the page
 
+Quote Post
skopus
сообщение Mar 1 2006, 08:24
Сообщение #6


Участник
*

Группа: Свой
Сообщений: 65
Регистрация: 31-08-05
Из: Moscow
Пользователь №: 8 124



Цитата(defunct @ Mar 1 2006, 10:47) *
Пользуйтесь прерываниями.

Данные складывайте в Fifo.
По прерыванию Tx переходите к отправке сл. байта.


вот заготовка:

Код
#include <io.h>
#include "com_routines.h"
#ifndef UDR
#define UDR UDR0
#endif
#define QUEUE_LENGTH (32)

char COMQueue[QUEUE_LENGTH];
unsigned char QueueHead, QueueTail;
unsigned char QueueBusy = 0;


void InitCOMQueue()
{
   QueueHead = 0;
   QueueTail = 0;
}


// Вызывать эту функцию в основном цикле программы
void CheckCOMQueue()
{
    if (!QueueBusy)
    if (QueueHead != QueueTail)
    {
      QueueBusy = 1;
      UDR = COMQueue[QueueHead];
      QueueHead++;
      if (QueueHead > QUEUE_LENGTH)
         QueueHead = 0;
    }
}

// А эту функцию в обработчике прерывания UART_TX
void CharSent()
{
  QueueBusy = 0;
}


void SendByte(unsigned char data)
{
  COMQueue[QueueTail] = data;
  QueueTail++;
  if (QueueTail > QUEUE_LENGTH)
     QueueTail = 0;
}


в смысле в основном цикле?
это сделать
Код
while(1)
{
  CheckCOMQueue();
}

а в моем прерывании просто использовать SendByte() столько раз, сколько хочу отправить байт?
Go to the top of the page
 
+Quote Post
defunct
сообщение Mar 1 2006, 08:27
Сообщение #7


кекс
******

Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326



Цитата(skopus @ Mar 1 2006, 10:24) *
в смысле в основном цикле?

Основной цикл - этот тот что в main() крутится..
Цитата
это сделать
Код
while(1)
{
  CheckCOMQueue();
}

а в моем прерывании просто использовать SendByte() столько раз, сколько хочу отправить байт?

Да, но в разумных пределах! длина очереди определеяется константой QUEUE_LENGTH

Сообщение отредактировал defunct - Mar 1 2006, 08:31
Go to the top of the page
 
+Quote Post
viakon
сообщение Mar 1 2006, 08:30
Сообщение #8


Местный
***

Группа: Участник
Сообщений: 290
Регистрация: 9-12-05
Из: г. Пермь
Пользователь №: 12 002



Ты пытаешься за 108мкс передать 10 байтов длиной 87 мкс, вот у тебя 2 байта максимум и получается. Увеличивай скорость уарта или временной интервал
Go to the top of the page
 
+Quote Post
arttab
сообщение Mar 1 2006, 08:37
Сообщение #9


Профессионал
*****

Группа: Свой
Сообщений: 1 432
Регистрация: 7-12-04
Из: Новосибирск
Пользователь №: 1 371



Ага: на 115200 на 1 байт уйдет 86,8 мксек. на 10 байт 0,868 мсек. Это реальность. А максимум скорости передачи, действительно надо по прерыванию - буфер пуст.


--------------------
OrCAD, Altium,IAR, AVR....
Go to the top of the page
 
+Quote Post
skopus
сообщение Mar 1 2006, 16:11
Сообщение #10


Участник
*

Группа: Свой
Сообщений: 65
Регистрация: 31-08-05
Из: Moscow
Пользователь №: 8 124



Цитата(viakon @ Mar 1 2006, 11:30) *
Ты пытаешься за 108мкс передать 10 байтов длиной 87 мкс, вот у тебя 2 байта максимум и получается. Увеличивай скорость уарта или временной интервал


увеличить временной интервал невозможно.
А скорость уарта должна быть из стандартного ряда
Go to the top of the page
 
+Quote Post
Валера1968
сообщение Mar 2 2006, 06:45
Сообщение #11





Группа: Новичок
Сообщений: 4
Регистрация: 1-02-06
Из: Новосибирск
Пользователь №: 13 835



если тебе нужна стандартная скорость 115200 то ты всяко не успеешь передать 10 байт, тебе минимум в пять раз надо поднять скорость передачи
Go to the top of the page
 
+Quote Post
skopus
сообщение Mar 2 2006, 09:59
Сообщение #12


Участник
*

Группа: Свой
Сообщений: 65
Регистрация: 31-08-05
Из: Moscow
Пользователь №: 8 124



ну поэтому я и создал эту тему.
Ща попробую через очередь сделать
Go to the top of the page
 
+Quote Post
viakon
сообщение Mar 2 2006, 10:15
Сообщение #13


Местный
***

Группа: Участник
Сообщений: 290
Регистрация: 9-12-05
Из: г. Пермь
Пользователь №: 12 002



Цитата(skopus @ Mar 2 2006, 14:59) *
ну поэтому я и создал эту тему.
Ща попробую через очередь сделать

За 108 мкс посылку длиной 870 мкс никак не передать, хоть какие очереди создавай.
Go to the top of the page
 
+Quote Post
ArtemK
сообщение Mar 2 2006, 10:21
Сообщение #14


Участник
*

Группа: Свой
Сообщений: 36
Регистрация: 27-09-05
Из: Украина, г. Херсон
Пользователь №: 8 994



Цитата
ну поэтому я и создал эту тему.
Ща попробую через очередь сделать

Видимо, Вы не совсем поняли, о чем говорилось в четырех предыдыдущих сообщениях. При выбранном Вами битрейте 115200 невозможно отправить 10 байт за 108 мкс даже при самой оптимальной по скорости программе и дело вовсе не в буферизации.

Сообщение отредактировал ArtemK - Mar 2 2006, 10:24
Go to the top of the page
 
+Quote Post
defunct
сообщение Mar 2 2006, 11:58
Сообщение #15


кекс
******

Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326



Цитата(ArtemK @ Mar 2 2006, 12:21) *
Видимо, Вы не совсем поняли, о чем говорилось в четырех предыдыдущих сообщениях. При выбранном Вами битрейте 115200 невозможно отправить 10 байт за 108 мкс даже при самой оптимальной по скорости программе и дело вовсе не в буферизации.


Автор вопроса нигде не говорил, что ему надо отправить 10 байт за 108 мкс. Упоминалось лишь только то, что надо "отправить по UART" 10 байт накопленных за 100 тиков таймера. Отправить 10 байт можно "мгновенно" если их физически не отправлять, а просто складывать в очередь.. Потом выбирать из очереди на текущей скорости UART'а хоть на 9600. Главное здесь чтобы очередь была достаточного объема, чтобы хранить все подготовленные к отправке данные.

Сообщение отредактировал defunct - Mar 2 2006, 12:05
Go to the top of the page
 
+Quote Post

2 страниц V   1 2 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 9th July 2025 - 02:47
Рейтинг@Mail.ru


Страница сгенерированна за 0.01515 секунд с 7
ELECTRONIX ©2004-2016