UART и прерывания FIFO

32-разрядные микроконтроллеры разработки ОАО "НИИЭТ"

Модераторы: pip, _sva_

Ответить
Роман
Сообщения: 16
Зарегистрирован: 26 янв 2018, 12:01
Предприятие: ВНИИЭМ

UART и прерывания FIFO

Сообщение Роман » 26 янв 2018, 12:54

Добрый день, пытаюсь наладить обмен с К1921ВК01Т через UART0.
В планах обмен примерно такой: посылка контроллеру 8 байт и ответ контроллера (в зависимости от запроса) от 8-ми до нескольких сотен байт.
Соответственно желательно иметь прерывание от fifo приёмника при 8-ми байтах и от фифо передатчика при пустом буфере.
Из описания регистра IFLS поля RXIFLSEL и TXIFLSEL:
000 - Заполнение на 1/8,
001 Заполнение на 1/4,
010 Заполнение на 1/2 (по умолчанию),
011 Заполнение на 3/4,
100 Заполнение на 7/8.
Соответственно в моём случаю поле RXIFLSEL= 2, а TXIFLSEL=0 , прерывания от пустого фифо нет, значит "большие" блоки буду отправлять по 14 байт. Но тут пока проблема:
Посылаю контроллеру 8 байт и получаю прерывание (единственное) при RXIFLSEL= 1, странно, но пусть так.
Прерывание по отправке не могу победить совсем, пишу в NT_UART0->DR 16 байт.
void USART0_TX_IRQHandler(void)
{
NT_UART0->CR &= ~0x0100; // TXE
NT_UART0->ICR = 0x20;
}
С инициализацией поля TXIFLSEL в IFLS, пробовал разные варианты:
NT_UART0->IFLS = 8;
// NT_UART0->IFLS |= 0; // первый ответ контроллера 11 байт.
// NT_UART0->IFLS |= 1; // первый ответ контроллера 7 байт.
// NT_UART0->IFLS |= 2; // первый ответ контроллера 16 байт.
// NT_UART0->IFLS |= 3; // первый ответ контроллера 16 байт.
// NT_UART0->IFLS |= 4; // первый ответ контроллера 16 байт.
// NT_UART0->IFLS |= 5; // первый ответ контроллера 16 байт.
// NT_UART0->IFLS |= 6; // первый ответ контроллера 16 байт.
// NT_UART0->IFLS |= 7; // первый ответ контроллера 16 байт.
Точка останова в USART0_TX_IRQHandler срабатывает только при TXIFLSEL=0 и TXIFLSEL=1, т.е. пока прерывание от фифо предатчика получил только при 6 и 10 байтах в фифо.
Вопрос: кал получить прерывание при хотя бы 2-х байтах в фифо передатчика?

bkolbov
Сообщения: 132
Зарегистрирован: 14 дек 2015, 11:37
Предприятие: АО НИИЭТ
Откуда: Воронеж

Re: UART и прерывания FIFO

Сообщение bkolbov » 29 янв 2018, 16:39

Добрый день!
Посылаю контроллеру 8 байт и получаю прерывание (единственное) при RXIFLSEL= 1, странно, но пусть так.
Вроде ничего странного - это уровень "Заполнение на 1/4", т.е. заполнение на 8 байт (всё fifo это 32 байта).
Вопрос: кал получить прерывание при хотя бы 2-х байтах в фифо передатчика?
Такого уровня нет в наличии. Максимально близкий TXIFLSEL=0 - "Опустошение до 1/8", т.е. до 4 или менее байт из 32 возможных.

Роман
Сообщения: 16
Зарегистрирован: 26 янв 2018, 12:01
Предприятие: ВНИИЭМ

Re: UART и прерывания FIFO

Сообщение Роман » 30 янв 2018, 12:37

Спасибо за ответ, с прерыванием от приёмного фифо понятно - я пользовался устаревшей версией описания в которой указан размер фифо 16 байт.
Но это, не объясняет, почему при TXIFLSEL = 0 прерывание возникает при 10-и байтах в фифо , TXIFLSEL = 1 при 6.
Инициализация полностью такая:
void uart0_hw_init(void)
{
// в описании на 31 стр. фигурирует UART_CLK_CTRL (имелся ввиду UART_SPI_CLK_SEL?) где 0 - это OSC_CLK,
// На рисуноке 15.1 (стр. 118) 0 - это SysCLK (!ТАК И ЕСТЬ).

// После сброса UART_SPI_CLK_SEL = 0, т.е. все uart и spi тактируются от SysCLK,
// NT_COMMON_REG->UART_SPI_CLK_SEL |= 1; // переключу UART0 на OSC_CLK.

// Разрешил UART0
NT_COMMON_REG->PER_RST0 |= (1<<7);
// Частота тактового сигнала определяется по формуле Fosc/(2*(X+1)), X – значение поля DIV_UARTn
NT_COMMON_REG->UART_CLK |= 0x1f; // 6.25мГц (от SysCLK - 100мГц).
// NT_COMMON_REG->UART_CLK |= 0x07; // 6.25мГц (от OSC_CLK - 25мГц).

NT_UART0->CR = 0;
NT_UART0->IBRD = 3; // BAUD_DIVINT
NT_UART0->FBRD = 25; // BAUD_DIVFRAC
// Нет проверки четности, лина посылки 8 бит, 1 стоп-бит
NT_UART0->LCR_H = 0x70; // WLEN = 3, FEN = 1
// уровни заполнения фифо - прерывания
// XXX В описании: поле RXIFLSEL - биты 3,4,5, 010 - Заполнение на 1/2 (указан размер fifo 16 байт?)
// но при длине посылки 8 байт прерывание возникант и crc совпадает только если там 001
// NT_UART0->IFLS = 0x10; // RXIFLSEL = 2 (1/2 fifo), TXIFLSEL = 0 (1/8 fifo)
NT_UART0->IFLS = 8;
// с прерыванием по отправке тоже фигня.
// Эксперименты при отправке кладу в фифо 16 байт
// void USART0_TX_IRQHandler(void)
// {
// NT_UART0->CR &= ~0x0100; // TXE
// NT_UART0->ICR = 0x20; // запись нуля игнорируется.
// }
// NT_UART0->IFLS |= 0; // первый ответ контроллера 11 байт.
NT_UART0->IFLS |= 1; // первый ответ контроллера 7 байт. (т.е. по фифо - 6 байт).
// NT_UART0->IFLS |= 2; // первый ответ контроллера 16 байт (нет пр-я).
// NT_UART0->IFLS |= 3; // первый ответ контроллера 16 байт (нет пр-я).
// NT_UART0->IFLS |= 4; // первый ответ контроллера 16 байт (нет пр-я).
// NT_UART0->IFLS |= 5; // первый ответ контроллера 16 байт (нет пр-я).
// NT_UART0->IFLS |= 6; // первый ответ контроллера 16 байт (нет пр-я).
// NT_UART0->IFLS |= 7; // первый ответ контроллера 16 байт (нет пр-я).

NT_UART0->IMSC = 0x70; // RT, TX, RX
// NT_UART0->DMACR = 0x0; // Запретить DMA
NT_UART0->ICR = 0x7ff; // сброс всех флагов пр-й

NT_UART0->CR = 0x0301; // RXE, TXE, UARTEN
// GPIO
NT_COMMON_REG->GPIOPCTLC_bit.PIN3 = 1; // выбор альтернативной ф-ии UART0_TxD
NT_COMMON_REG->GPIOPCTLC_bit.PIN4 = 1; // выбор альтернативной ф-ии UART0_RxD
//
NT_GPIOC->ALTFUNCSET = USART0_GPIOC_EN_MSK; // перевод n-го вывода порта в режим альтернативной функции
// разрешил выводы
NT_COMMON_REG->GPIODENC |= USART0_GPIOC_EN_MSK;

NVIC_ClearPendingIRQ(UART0_TX_IRQn);
NVIC_EnableIRQ(UART0_TX_IRQn);

NVIC_ClearPendingIRQ(UART0_RX_IRQn);
NVIC_EnableIRQ(UART0_RX_IRQn);

NVIC_ClearPendingIRQ(UART0_RT_IRQn);
NVIC_EnableIRQ(UART0_RT_IRQn);
}

bkolbov
Сообщения: 132
Зарегистрирован: 14 дек 2015, 11:37
Предприятие: АО НИИЭТ
Откуда: Воронеж

Re: UART и прерывания FIFO

Сообщение bkolbov » 30 янв 2018, 13:08

Т.е. мк грузит 16 байт в передающее fifo, начинает передачу, а когда возникает прерывание по передаче - вы её отключаете, и смотрите сколько байт передалось до отключения? Я верно вас понял?
NT_UART0->IFLS |= 0; // первый ответ контроллера 11 байт.
NT_UART0->IFLS |= 1; // первый ответ контроллера 7 байт.
Когда TXIFLSEL=0:
вы грузите 16 байт в fifo, передаются первые 11 байт, потом из fifo вычитывается и начинает передаваться 12-й байт. Сразу же возникает прерывание по передаче, так как в fifo осталось 4 байта (произошло опустошение до 1/8 уровня от fifo), и вы отключаете передачу в обработчике. 12-й байт при этом обрывается и не успевает завершиться - передано полностью лишь 11 байт.

Аналогично когда TXIFLSEL=1:
вы грузите 16 байт в fifo, передаются первые 7 байт, потом из fifo вычитывается и начинает передаваться 8-й байт. Сразу же возникает прерывание по передаче, так как в fifo осталось 8 байт (произошло опустошение до 1/4 уровня от fifo), и вы отключаете передачу в обработчике. 8-й байт при этом обрывается - передано полностью лишь 7 байт.

Роман
Сообщения: 16
Зарегистрирован: 26 янв 2018, 12:01
Предприятие: ВНИИЭМ

Re: UART и прерывания FIFO

Сообщение Роман » 30 янв 2018, 13:53

Получается что так (я неверно интерпритировал результат своего эксперимента), спасибо.
Хотя на стр. 119 есть такая фраза "Если приемопередатчик переводится в отключенное состояние
во время передачи или приема, то перед остановкой он завершает выполняемую
операцию." из которой складывается впечатление что 12-й байт (и 8-й во втором случае ) д.б. отправиться.

Но по работе uart в следующих контроллерах хотелось бы выдеть следующие улучшения:
1. возможность задать прерывания по FIFO приёмника полон и FIFO передатчика пуст,
в идеале уровень прерываия от фифо д.б. задаваем не в процентах а байтах,
т.к. не всегда м.б. возможность изменить размер запроса контроллеру.
2. возможность задать прерывания по FIFO передатчик пуст,
в идеале уровень прерываия от фифо д.б. задаваем не в процентах а байтах.
3. возможность определить сколько байт сейчас в FIFO приёмника.
4. возможность сбросить FIFO приёмника. т.к. допустим штатно размер пакета контроллеру
равен уровню заполнения FIFO вызывающему прерывания.
Ситуация: в FIFO оказалось некоторое, недостаточное для возникновения прерывания к-во байт,
которые надо проигнорировать для корректной обработки следующего пакета.
Для этого удобно использовать прерывание по таймауту в котором приходится делать нечто такое:
void USART0_RT_IRQHandler(void)
{
// Таймаут, формат обмена такой что это точно мусор.
do {
(void)NT_UART0->DR;
} while (!(NT_UART0->FR & 0x10)); // RXFE = 1 - Буфер пуст
}
что выглядит не очень и приводит к лишним обращениям через AHB/APB.
Или 3 или 4 можно и сейчас?

bkolbov
Сообщения: 132
Зарегистрирован: 14 дек 2015, 11:37
Предприятие: АО НИИЭТ
Откуда: Воронеж

Re: UART и прерывания FIFO

Сообщение bkolbov » 30 янв 2018, 15:09

Хотя на стр. 119 есть такая фраза "Если приемопередатчик переводится в отключенное состояние
во время передачи или приема, то перед остановкой он завершает выполняемую
операцию." из которой складывается впечатление что 12-й байт (и 8-й во втором случае ) д.б. отправиться.
Да, такая фраза есть и она верна. Я сообщением выше несколько некорректно объяснил.
Новое значение из fifo читается когда выставляется стоповый бит предыдущего байта. Далее, возникает прерывание и отключение передачи. При этом текущая операция "удерживания" стопового бита выполняется до конца, а далее т.к. передача отключена - новый байт не начинает передаваться. Т.е. ничего не теряется, и остальные байты начнут передаваться как только передатчик снова будет включен.
Или 3 или 4 можно и сейчас?
Нет, сейчас так нельзя сделать без вычитывания fifo.
Благодарю за предложения, посмотрим что можно будет сделать.

Роман
Сообщения: 16
Зарегистрирован: 26 янв 2018, 12:01
Предприятие: ВНИИЭМ

Re: UART и прерывания FIFO

Сообщение Роман » 30 янв 2018, 20:07

Ясно, спасибо за поддержку.

Ответить

Вернуться в «32-разрядные микроконтроллеры на ядре ARM Cortex»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость