Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: LPC177x UART, использовать FIFO для передачи
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
megajohn
первоначально передача была сделана по одному байту.

но после написания драйвера для отправки по SSP с использованием FIFO решил так же переписать уартовский, но не тут то было.

нет привычных битов TFE Transmit FIFO Empty, TNF Transmit FIFO Not Full

хотя в доке написано
16 byte Receive and Transmit FIFOs

у меня сложилось мнение что из указанных 16 остается 14 байт на RX и лишь два байта на TX. Так ?
GetSmart
Два независимых буфера для RX и TX.
К примеру, в LPC1768 кажется нет индикатора заполненности TX буфера. Как и в LPC21xx, LPC111x. Так что забиваются по полному освобождению сразу 16 байт.

В RX прерывании, если стоит уровень срабатывания 14, то можно вычитывать из RBR сразу 14 раз подряд, анализируя младший бит LSR.

Пример обработчика
Код
void UART0_IRQHandler()
{
    switch(U0IIR & 0x0f)
    {    uInt lsr;
        default:
            U0LSR;
            U0RBR;
            break;
        case 0x02:    //THRE interrupt
            proc_tx(&uart0);
            break;
        case 0x0C:    //timeout
        case 0x06:    //Rx line status error
        case 0x04:    //Receive data available
            while ((lsr = U0LSR) & 0x01) proc_rx(&uart0, U0RBR, lsr & 0x9e);
            break;
    }
    NVIC_ClearPendingIRQ(UART_IRQn);
}
//uart0 - структура с данными
Golikov A.
а разве не появляется флаг буфер передатчика занят когда все 16 байт заняты?
jcxz
Цитата(Golikov A. @ Sep 24 2013, 22:30) *
а разве не появляется флаг буфер передатчика занят когда все 16 байт заняты?

Нет. Там эмуляция стандартного, не самого удачного 16550. Флаг "буфер пуст" снимается при записи хотя-бы одного байта в TX-fifo.
Так что при обнаружении этого флага, писать надо сразу <= 16 байт.
С RX не так печально.
Terminator
Мне удалось нормально запустить uart TX на lpc1768 только с использованием DMA. Прерывания от самого uart весьма странно работают.
jcxz
А что там странного? Вполне соответствуют описанию в UM. И таких контроллеров полно во многих других процессорах других фирм - одна из самой распространённой периферии wink.gif
У меня в проекте все 4 UART на lpc1758 работают в параллель с FIFO и по прерываниям - никаких проблем. А на LPC1778 - все 5.
Terminator
беда в том что прерывание TX_EMPTY может возникнуть только после передачи. Если его просто разрешить, когда никакой передачи не идёт, ничего не произойдёт.
В других контроллерах (с которыми я имел дело) при разрешении такого прерывания немедленно вызывался обработчик. Такое поведение очень сильно упрощает "драйвер" работы с uart-ом.
Golikov A.
что значит вызывается обработчик при разрешении? Обработчик должен вызывать при возникновении прерывания а не просто при его разрешении...
ig_z
QUOTE (Golikov A. @ Sep 27 2013, 12:53) *
что значит вызывается обработчик при разрешении? Обработчик должен вызывать при возникновении прерывания а не просто при его разрешении...

При возникновении прерывания "должен" ставиться флаг запроса на прерывание и ничего более. При разрешении прерывания и установленном флаге запроса контроллер прерывания запускает обработчик.
Что курили голландские девелоперы, когда дизайнили уарт известно только им и богу. По факту код передачи по уарту для филипков должен быть продублирован в обработчике прерывания от уарта и в том месте кода, где нужно начать передачу. Для "нормальных" уарт архитектур достаточно разрешить прерывание "передатчик пуст"
Golikov A.
чего то я не понимаю видать....

у меня это было так.

функция послать данные:
если передатчик и доп буфер пусты пихает в передатчик 16 байт данных. Если их меньше и ладно, если их больше пихает 16 остальные кладет в буфер программный. если доп буфер был не пуст, кладет данные в него.

прерывание уарт пуст - если буфер программный пуст и ладно, если нет, то берет данные из него и пихает в передатчик.

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


вообщем никакой проблемы я не вижу если честно, все мне кажется логично... А вот что делать с прерывание буфер пуст если оно возникает всегда когда буфер пуст для меня как раз вопрос. Ведь большую часть времени если обмена нет, он как раз и пуст, вы прерывание что-ли запрещаете, а когда данные кладете разрешаете? Не уверен, что это прям мего логично...
ig_z
QUOTE (Golikov A. @ Sep 27 2013, 14:51) *
вообщем никакой проблемы я не вижу если честно, все мне кажется логично... А вот что делать с прерывание буфер пуст если оно возникает всегда когда буфер пуст для меня как раз вопрос. Ведь большую часть времени если обмена нет, он как раз и пуст, вы прерывание что-ли запрещаете, а когда данные кладете разрешаете? Не уверен, что это прям мего логично...

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

Прерывания разрешаются когда есть данные и запрещаются когда из нет. Просто , логично, компактно и надежно

Ну и вы конечно правы, с уарт на лпс нет никаких проблем, одно мелкое неудобство.
Golikov A.
вы проверяете разрешено ли прерывание, и разрешаете их если запрещены.
я проверяю пустой ли буфер обмена

вы пихаете данные в кольцевой буфер а оттуда в фифо уарта
я в первом случае пихаю их сразу в фифо, на 1 копирование меньше

разрешать и запрещать прерывания - просто логично, но не факт что надежно, мало ли кто еще в программе решит их запретить и почему?

идиологии разные и обе имеют как плюсы так и минусы. И если вы всегда делали так, не значит что по другому не удобно. Главное что это все описано в мануале, а значит проблем нет.
jcxz
Да, конечно, 16550 уже давно морально устарел и можно сделать гораздо более удобный и современный интерфейс для UART (примеры есть).
Но NXP решили для UART реализовать стандартный 16550 (с доп. фичами) и у этого подхода есть и серьёзный '+':
UART - это единственная периферия, драйвера для которой я переношу между разными контроллерами практически без изменений, а это серьёзный '+' когда приходится одновременно работать с разными контроллерами.
И реализовали они его грамотно - без багов.

Цитата(ig_z @ Sep 27 2013, 17:35) *
Что курили голландские девелоперы, когда дизайнили уарт известно только им и богу. По факту код передачи по уарту для филипков должен быть продублирован в обработчике прерывания от уарта и в том месте кода, где нужно начать передачу.
В си есть такая чудесная вещь как функция(). Попробуйте - вам понравится wink.gif

Цитата(ig_z @ Sep 27 2013, 17:35) *
Для "нормальных" уарт архитектур достаточно разрешить прерывание "передатчик пуст"
Это уж не в тех-ли нормальных (типа STM), где забыли добавить FIFO в UART? wink.gif
ig_z
QUOTE (jcxz @ Sep 27 2013, 19:40) *
Это уж не в тех-ли нормальных (типа STM), где забыли добавить FIFO в UART? wink.gif

s3c4530 догадливый вы наш
Terminator
это всё конечно красиво, но попробуйте сделать вывод в отладочный порт из разных задач. Останавливать задачу ради вывода отладки нельзя, что влезло в буфер, то влезло. Заводить отдельную задачу для слежения за заполненостью буфера, очень не хочется. Запрещать прерывания перед каждым обращением в uart тоже (тут я конечно несколько лукавлю, т.к. при складывании в буфер прерывания всё равно запрещаются).
Golikov A.
Цитата(Terminator @ Sep 28 2013, 08:52) *
это всё конечно красиво, но попробуйте сделать вывод в отладочный порт из разных задач. Останавливать задачу ради вывода отладки нельзя, что влезло в буфер, то влезло. Заводить отдельную задачу для слежения за заполненостью буфера, очень не хочется. Запрещать прерывания перед каждым обращением в uart тоже (тут я конечно несколько лукавлю, т.к. при складывании в буфер прерывания всё равно запрещаются).


так в чем проблема то?

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


в остальном проблем нет. Я же писал функции работают идентично, просто вместо вашей проверки на запрет прерывания и его разрешение, у нас делает проверка на пустоту буфера и его запуск на передачу. Дальше у всех циклический буфер в который кладутся остатки сообщения.
jcxz
Возможно товарищи по каким-то причинам (религиозным?) очень хотят писать в FIFO именно из ISR. Непреодолимое желание сиё понять трудно... twak.gif
Но, коли так уж хочется, после разрешения empty-tx IRQ можно программно возбудить прерывание при помощи NVIC.
Golikov A.
Аминьsm.gif
Terminator
Цитата(jcxz @ Sep 28 2013, 18:34) *
Возможно товарищи по каким-то причинам (религиозным?) очень хотят писать в FIFO именно из ISR. Непреодолимое желание сиё понять трудно... twak.gif
Но, коли так уж хочется, после разрешения empty-tx IRQ можно программно возбудить прерывание при помощи NVIC.

Чем плохо писать в FIFO из ISR? Это позволяет (не в случае с LPC конечно) в коде записать в буфер данные и разрешить прерывание. Всё остальное делается в прерывании.

Пинать NVIC не пробовал. При случае попробую. Хотя это чревато лишними вызовами прерываний.
megajohn
Цитата(jcxz @ Sep 28 2013, 15:34) *
Возможно товарищи по каким-то причинам (религиозным?) очень хотят писать в FIFO именно из ISR. Непреодолимое желание сиё понять трудно... twak.gif
Но, коли так уж хочется, после разрешения empty-tx IRQ можно программно возбудить прерывание при помощи NVIC.


про первичное наполнение FIFO из ISR это можно охарактеризовать как странность восприятия мира
но "докладка" в процессе передачи - вполне обыденное действие.

К примеру на RTOS: задача utx_task принимает от других задач task0, taskN то что нужно передать.
тогда есть два варианта разруливания:
#1
utx_task заполняет FIFO и размещает в глобальной переменной ptr и len чего еще не успело передать и ожидает события завершения ВСЕЙ передачи
в прерывании после опустошения FIFO передачи проверяется len и если != 0 то в ISR досылаем в FIFO иначе выставляем признак события чтобы разбудить utx_task задачу для повторения всех циклов

#2
utx_task заполняет FIFO и ожидает события завершения передачи FIFO
в прерывании после опустошения FIFO выставляем признак события чтобы разбудить utx_task задачу для повторения заполнения FIFO и так по кругу

вроде одинаковый результат, но сдается мне что во втором случае будет чаще дергатся шедуллер

Цитата(Terminator @ Sep 28 2013, 08:52) *
это всё конечно красиво, но попробуйте сделать вывод в отладочный порт из разных задач.
Останавливать задачу ради вывода отладки нельзя, что влезло в буфер, то влезло.
Заводить отдельную задачу для слежения за заполненостью буфера, очень не хочется.
Запрещать прерывания перед каждым обращением в uart тоже (тут я конечно несколько лукавлю, т.к. при складывании в буфер прерывания всё равно запрещаются).


тут только отдельная задача, которая:
1. для синхронной отправки ( блокирующая задача ) - выставляет семафор/событие для блокировки текущей задачи
2. для ассинхронной отправки ( неблокирующая задача ) отправка буфера из кучи - сохраняет в своей очереди ptr и len что передать, и по завершению FREE
3. для ассинхронной отправки ( неблокирующая задача ) отправка из стека - свой MALLOC и MEMCPY и предыдущий вариант 2
4. для ассинхронной отправки ( неблокирующая задача ) отправка из const и CODEMEM/FLASH - вариант 2 без FREE
Terminator
Отправка выглядела примерно так: уарт не занят, разрешаем прерывание tx_empty, пихаем в фифо первый(или заполняем всё fifo) байт посылки, остальное в очередь которую проверит isr. Если уарт занят, то пихаем всё в очередь.
В моём случае заморочка была в том что прерывание tx_empty бывало, что не срабатывало.
Перебрал кучу вариантов, всё равно случались пропуски. Стабильно заработало когда завёл dma на передачу.
GetSmart
По поводу докладывания FIFO 16-тью элементами. Цитата из UM10360 (LPC17xx user manual)
Цитата
4.14 UARTn FIFO Level register (U0FIFOLVL - 0x4000 C058, U2FIFOLVL - 0x4009 8058, U3FIFOLVL - 0x4009 C058)

UnFIFOLVL register is a read-only register that allows software to read the current FIFO
level status. Both the transmit and receive FIFO levels are present in this register.

Так что можно докладывать не заходя в прерывание. Точнее, не дожидаясь полного освобождения Tx FIFO.

Жаль, во многих других процах нет этого регистра.
jcxz
Цитата(Terminator @ Sep 30 2013, 16:34) *
Отправка выглядела примерно так: уарт не занят, разрешаем прерывание tx_empty, пихаем в фифо первый(или заполняем всё fifo) байт посылки, остальное в очередь которую проверит isr. Если уарт занят, то пихаем всё в очередь.
В моём случае заморочка была в том что прерывание tx_empty бывало, что не срабатывало.

Что-то вы криво делали - у меня стабильно работает всегда.
Например - после разрешения tx_empty и перед пиханием в буфер, вы не забывали запрещать прерывания? sm.gif
К тому же - по вашему алгоритму придётся запрет прерывания продлить до конца пихания в очередь всех данных.
Логичнее делать по-другому:
В задаче пишем всё в очередь (с разрешёнными прерываниями). После писания - проверим разрешено-ли прерывание UART (ну или программного флага, если в ISR не запрещаем IRQ TX_EMPTY при опустошении, а просто игнорим его), если запрещено - запрещаем прерывания CPU, вызываем функцию переписывающую из очереди в TX FIFO (эту же функцию вызываем из ISR при TX_EMPTY).
Внутри этой функции, если в очереди имеется хотя-бы один байт - она разрешает прерывания TX_EMPTY (ставит программный флаг), заполняет FIFO из очереди. Если на входе в функцию очередь пуста, она запрещает TX_EMPTY (сбрасывает программный флаг).
Если всё реализуете аккуратно, в том числе очередь - реерентерабельную для перекрывающихся чтений/записей, то всё будет работать как часы.
Grape
Цитата(GetSmart @ Oct 1 2013, 00:39) *
По поводу докладывания FIFO 16-тью элементами. Цитата из UM10360 (LPC17xx user manual)

Так что можно докладывать не заходя в прерывание. Точнее, не дожидаясь полного освобождения Tx FIFO.

Жаль, во многих других процах нет этого регистра.


UM10360, rev2, 20100819

Modifications:
• UART0/1/2/3: FIFOLVL register removed.
GetSmart
Цитата(Grape @ Oct 1 2013, 16:02) *
UM10360, rev2, 20100819

Modifications:
• UART0/1/2/3: FIFOLVL register removed.

Removed from document or removed from new revision chip?

Читая мануал на LPC122x этот регистр снова присутствует. Разработчики развлекаются или мануальщики...
yanvasiij
Люди, идиотский вопрос. Столкнулся тоже с этим ньюансом про прерывание при опустошении FIFO и подумал, если такие хлопоты, то почему бы просто не запретить аппаратные FIFO в регистре UART1 FIFO Control Register. И тогда прерывание по THRE будет происходить при отправке каждого байта. И тогда кольцевые буфферы без всяких нарезаний по 16 байт можно поместить в прерывание по отправке. Это будет работать и чем это плохо?
Golikov A.
отсутствием FIFO, например.... тем что нельзя пихнуть 16 байт и делать свои дела пока их выдавливает, а надо постоянно отвлекаться и по байту класть. А если у вас ModBus с условием определения конца по паузе между байтами посылки?
yanvasiij
Цитата(Golikov A. @ Jan 30 2015, 14:46) *
отсутствием FIFO, например.... тем что нельзя пихнуть 16 байт и делать свои дела пока их выдавливает, а надо постоянно отвлекаться и по байту класть. А если у вас ModBus с условием определения конца по паузе между байтами посылки?


Да, но так ли это заметно, если процессор работает на частоте под 100 MГц. Ему переложить из регистра в регистр что из fifo, что вручную велика ли разница?
Golikov A.
Велика, если есть критические секции в которых у вас может быть запрещено прерывание, или есть какое-то более приоритетное прерывание.
Если класть по символу у вас есть время 1 символ, если класть по фифо, то задержка может быть до 16 символов

Это все удобства.
У СТМ вот к примеру нет фифо ни на входе ни на выходе. Иногда это неудобно, иногда ДМА решает все проблемы. Но в целом наличие фифо все же благо, и просто от него отказываться я бы не стал
Kabdim
Цитата(yanvasiij @ Jan 30 2015, 13:08) *
Да, но так ли это заметно, если процессор работает на частоте под 100 MГц. Ему переложить из регистра в регистр что из fifo, что вручную велика ли разница?

Если ничего не нужно делать в процессе отправки, то почему бы и нет. Только как правило позже выясняется что что-то делать нужно.
yanvasiij
Golikov A., Kabdim Спасибо за разъяснения! Буду тогда нарезать по 16. Я правильно понял, что нет регистра в линейке LPC177x_178x, который бы дал понять FIFO TX уже заполнен и нужно вручную считать по 16, а потом дожидаться THRE и отсчитывать следующие 16?
jcxz
Цитата(yanvasiij @ Jan 30 2015, 16:31) *
Я правильно понял, что нет регистра в линейке LPC177x_178x, который бы дал понять FIFO TX уже заполнен и нужно вручную считать по 16, а потом дожидаться THRE и отсчитывать следующие 16?

Такого нет. Действовать надо так: появился статус - TX-буфер пуст - значит можно записать не более 16 байт. Пишете по счётчику.
megajohn
Цитата(jcxz @ Sep 24 2013, 20:19) *
Нет. Там эмуляция стандартного, не самого удачного 16550.


хотел высказаться об еще одном неудачном месте в LPC: MultimediaCardIntarface

есть три регистра MCI-CLOCK MCI-DATACTRL MCI-COMMAND
После записи в которые надо
Note: After a data write, data cannot be written to this register for three MCLK clock periods plus two PCLK clock periods.
конечно не сложно это сделать, но не нравятся три фактора
1. на этапе иннициализации частота MCLK 200кГц а потом уже и 10МГц может быть, так что эту времянку нужно в рантайме менять
2. PCLK тоже они проекта к проекту может быть разный
3. ладно, записал, подождал указанное время, потом снова записал. Но от предыдущей записи до новой выполнялись же такты, и можно было бы и по меньше ждать времянку. Но не таймер же заводить для этого.

Как мне видится аппаратное решение: три бита занятости, clock_busy, datactrl_busy, command_busy
перед записью ждешь просто готовность соответствующего бита, и вот она программная независимость от аппаратных заморочек. Ляпота

может донести эту мысль инженерам NXP на их форуме ? Но с английским туго.

P.S. а как вы красиво решали ожидание на LPC ?
P.P.S на других платформах есть такая заморочка с MCI ?
Golikov A.
Цитата
, который бы дал понять FIFO TX уже заполнен и нужно вручную считать по 16, а потом дожидаться THRE и отсчитывать следующие 16?

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