Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Прикрутить программный FIFO для UART LPC17XX
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
kt368
Здравствуйте! Вывожу в UART с помощью printf(), предварительно подправив Retarget.c, в функцию fputc() внес следующее:
Код
int fputc(int c, FILE *f) {
    UART_SendByte(LPC_UART0, c);
    return (c);}
Когда я предаю по UART длинные строки при помощи printf, то реально передаётся только первая часть строки, это по-идее происходит из-за наличия в модуле UART 16-и байтового аппаратного FIFO. Хочу подправить функцию fputc(), введя в неё программный FIFO, дабы иметь возможность передавать одной командой printf() большие строки. Можно, конечно, ввести в fputc() проверку освобождения аппаратного FIFO, но тогда процессор будет тратить такты впустую, чего не хочется. Подскажите, как бы его так сделать, чтобы между printf() и модулем UART'a был программный FIFO, и в то же время этот FIFO со как-то освобождался, то-ли по прерыванию от таймера, то-ли ... Как правильнее это реализовать?
Lagman
Что то Вы тут все в кучу свалили, каким образом printf знает что у вас 16 байтовый аппаратный фифо, вроде как через fputc по одному символу выдается? Какой длины не влезает строка, а какой влезает? Даже 8 битники нормально printf обрабатывают.
Смотрите на UART_SendByte(), скорей всего там ошибка. И кажется надо править putc() а не fputc() (зависит не только от компилятора, про который вы ни слова не сказали, а может вы вызываете fprinf()). Но проверка нужна будет обязательно т.к. вы не узнаете что буфер освободился, ставьте RTOS пусть она в задачах сама переключает, либо через прерывания. А можно через sprintf выводить в буфер и уже его по прерыванию выдавать на UART.
kt368
Не до конца объяснил. printf действительно про фифо ничего не знает, вот и гонит в UART_SendByte() по байтику всю строку, а UART_SendByte() вот такая:
Код
void UART_SendByte(LPC_UART_TypeDef* UARTx, uint8_t Data)
{
    UARTx->THR = Data & UART_THR_MASKBIT;
}

То есть эта функция просто вносит в регистр передаваемых данных ещё один байт, не проверяя есть ли свободная ячейка в аппаратном фифо.
....Хм, пересмотрел код, у меня, кажется, аппаратный фифо был выключен. Попробую его включить, завтра получу доступ к железу - протестирую как теперь будет работать printf() с большими строками и отпишусь.
Lagman
Цитата(kt368 @ Oct 12 2013, 01:30) *
Не до конца объяснил. printf действительно про фифо ничего не знает, вот и гонит в UART_SendByte() по байтику всю строку, а UART_SendByte() вот такая:
Код
void UART_SendByte(LPC_UART_TypeDef* UARTx, uint8_t Data)
{
    UARTx->THR = Data & UART_THR_MASKBIT;
}

То есть эта функция просто вносит в регистр передаваемых данных ещё один байт, не проверяя есть ли свободная ячейка в аппаратном фифо.
....Хм, пересмотрел код, у меня, кажется, аппаратный фифо был выключен. Попробую его включить, завтра получу доступ к железу - протестирую как теперь будет работать printf() с большими строками и отпишусь.

Так в этом случае не то что длинные строки, любая строка должна выводиться абракадаброй т.к. THR постоянно перезаписывается новыми данными, а что в сдивговый регистр попадет никто не узнает пока не увидит результат вывода на экран. (общий рецепт может не иметь ничего общего с LPC17XX)
_pv
Код
#ifndef __FIFO_H_
#define __FIFO_H_

#include "type.h"

template <u8 size, typename T = u8> class Fifo{
  T buf[size];
  u8 _count;
  u8 _first;
  u8 _last;
public:
  Fifo(){ _count = _last = _first = 0; }
  void clear(){ _count = _last = _first = 0; }
  u8 count(){ return _count; }
  u8 free(){ return size - _count; }

  void push(T item){
    if(_count == size) return;
    _count++;
    buf[_last++] = item;
    if(_last >= size) _last = 0;
  }

  T pop(){
    if(_count == 0) return 0;
    _count--;
    T item = buf[_first++];
    if(_first == size) _first = 0;
    return item;
  }

  u8 write(T * data, u8 num){
    if (num > (size - _count)) num = size - _count;
    u8 n = num;
    while (num--) push(*data++);
    return n;
  }

  u8 read(T * data, u8 num){
    if (num > _count) num = _count;
    u8 n = num;
    while (num--) *data++ = pop();
    return n;
  }

  T at(s16 index){
    s16 i = index + (index < 0) ? _last : _first;
    while (i < 0) i += size;
    while (i >= size) i -= size;
    return buf[i];
  }
};

#endif /* __FIFO_H_ */



Fifo <64> txFifo;

соответственно в
UART_SendByte(char data){
txFifo.push(data);
__UART_TX_INTERRUPT_ENABLE();
}

а в прерывании передатчика
if (txFifo.count()) UARTx->THR = txFifo.pop();
else __UART_TX_INTERRUPT_DISABLE();
mdmitry
Цитата(_pv @ Oct 12 2013, 02:42) *
[code]
template <u8 size, typename T = u8> class Fifo{
...
}

Уважаемый _pv, с какой целью жестко ограничена глубина FIFO 255 элементами? Пакеты могут быть и длиннее, чем 255 байт (протокол WAKE, например).

Уважаемый kt368, пример кольцевого буфера можно найти в usrlib.* из scmRTOS. И смотрите внимательно на умолчания шаблона.
_pv
Цитата(mdmitry @ Oct 13 2013, 01:11) *
Уважаемый _pv, с какой целью жестко ограничена глубина FIFO 255 элементами? Пакеты могут быть и длиннее, чем 255 байт (протокол WAKE, например).

скопировано оттуда где пакетов больше 255 быть не может, а делать еще и задание типа для хранения индексов было лень.
кому сильно надо может поменять на template <int size, typename idxT = u8, typename T = char>
жаль нельзя сделать template <idxT size, typename idxT = u8, typename T = char>. было бы совсем красиво.
kt368
Все, разобрался. Включил аппаратный FIFO, также добавил свой программный буфер, по примеру _pv. Ещё зачем-то хочется сделать динамическое выделение памяти под это FIFO, но сейчас не до этого.
Всем спасибо!
SSerge
В функциях push и pop есть инкремент и декремент счётчика _count.
Это не безопасно.
Например, если во время исполнения в функции push() оператора _count++ произойдёт прерывание по готовности передатчика. И случится это как раз после чтения из памяти старого значения счётчика, но до записи в память нового, увеличенного.
В обработчике прерывания будет вызов pop(), а в ней есть декремент счётчика.


Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.