[uquote="AlanDrakes",url="/forum/viewtopic.php?p=4171591#p4171591"][uquote="jcxz",url="/forum/viewtopic.php?p=4171336#p4171336"]А как именно работает это прерывание IDLE - знаете? А то в мануале оно очень туманно описано. И не факт, что удастся использовать его совместно с DMA.
И причём (насколько знаю): в разных STM32 есть разные средства обнаружения таймаута на UART.RXD. В младших, слыхал, есть RTOF, который похож, но не совсем.[/uquote]
По RM - 30.3.1
An Idle character is interpreted as an entire frame of “1”s followed by the start bit of the next frame which contains data (The number of “1” ‘s will include the number of stop bits).
Символ IDLE - целый фрейм из таймслотов в состоянии "1", за которым следует стартовый бит следующего фрейма, содержащий данные (Количество единиц включает так же стоп-биты).
Мне кажется, здесь не совсем корректно описан принцип работы события. Поскольку, собственно, детектирование свободной линии (Idle line) происходит после принятия IDLE фрейма. Внятных диаграмм не привели, но код работает с тем, что есть.[/uquote]Вот именно об этом месте мануала STM32F4 я и говорил. Судя по нему: IDLE должно наступать не после таймаута неактивности на RXD, а
после таймаута неактивности, сопровождаемого старт-битом следующего байта. Т.е. - в начале следующего байта следующего кадра после паузы. Кроме того, в самом начале описания USART мануала есть такое:
Ten interrupt sources with flags:
– CTS changes
– LIN break detection
– Transmit data register empty
– Transmission complete
– Receive data register full
– Idle line received
– Overrun error
– Framing error
– Noise error
– Parity error
• Multiprocessor communication - enter into mute mode if address match does not occur
• Wake up from mute mode (by idle line detection or address mark detection)
• Two receiver wakeup modes: Address bit (MSB, 9th bit), Idle line
Т.е. говорится, что есть прерывание "Idle line received" и что оно служит для "Wake up from mute mode" - пробуждения из сна, которое очевидно должно происходить
при возникновении активности на шине после паузы. А значит опять-же - косвенно намекает на то, что возникать прерывание должно после неактивности сопровождаемой старт-битом.
PS: Хотя вы правы - описание
ОЧЕНЬ туманное и косноязычное. И возможно имелось в виду что-то другое. А также есть подозрение, что в разных STM32 оно работает несколько по-разному.
Добавлено after 3 minutes 2 seconds:
[uquote="tonyk",url="/forum/viewtopic.php?p=4171606#p4171606"]IDLE задуман как детектор ошибок приёма для Модбас. Устанавливается строго после 20 идущих подряд единичных бит в линии. Отсюда и выстраивайте логику работы.[/uquote]Приведите пожалуйста мануал и страницу в котором это написано.
Добавлено after 3 minutes 31 second:
[uquote="Dimon456",url="/forum/viewtopic.php?p=4172203#p4172203"]А я что, где-то сказал, что я программист? Я уголь в топку кидаю.
Как ваш dma сюда прикрутить?[/uquote]Если вы не программист - то никак.
Добавлено after 29 minutes 34 seconds:
[uquote="Аlex",url="/forum/viewtopic.php?p=4172288#p4172288"]В общем, всё работает. Впрочем, всё как обычно
Код: Выделить всё
/********************************************************************************/
uint8_t uart_rx_buf[1000];
uint32_t uart_rx_cnt = 0;
/********************************************************************************/
extern "C" {
void UART5_IRQHandler(void) {
//----------
if(UART5->SR & USART_SR_IDLE) {
UART5->SR &= ~USART_SR_IDLE;
uart_rx_cnt = sizeof(uart_rx_buf) - DMA1_Stream0->NDTR;
if(uart_rx_cnt > sizeof(uart_rx_buf)) uart_rx_cnt = 0;
GPIO_ResetBits(GPIOG, GPIO_Pin_13);
UART5->CR1 &= ~USART_CR1_RXNEIE;
UART5->CR1 &= ~USART_CR1_IDLEIE;
UART5->CR1 &= ~USART_CR1_RE;
}
//----------
}
}
/********************************************************************************/
[/uquote]
Имхо: здесь во-первых - неоптимально; во-вторых - не корректно.
Операция
UART5->SR &= ~USART_SR_IDLE; - непонятно для чего? Флаг IDLE в SR - read-only и не может быть сброшен записью в SR (по-крайней мере в RM STM32F4). Опять же в RM написано как его сбрасывать:
It is cleared by a software sequence (an read to the USART_SR register followed by a read to the USART_DR register).
А вот
UART5->SR &= ~USART_SR_IDLE; сбросит не IDLE, а может сбросить совсем другие соседние флаги в SR. Писали уже об этом неоднократно.
И зачем 3 отдельные транзакции чтения-записи?:
Код: Выделить всё
UART5->CR1 &= ~USART_CR1_RXNEIE;
UART5->CR1 &= ~USART_CR1_IDLEIE;
UART5->CR1 &= ~USART_CR1_RE;
Всё это можно (и нужно) делать одной транзакцией чтения-модификации-записи CR1.
Во-вторых: 1-й из этих строк Вы маскируете прерывание RXNIE, и только последней - выключаете приёмник. Если между этими 2-мя событиями в RX.FIFO UART придёт очередной символ, то он там зависнет. Так как выключение UART не очищает его FIFO. И после нового разрешения UART этот символ вдруг выскочит в прерывание RXNE, как будто он пришёл с новым кадром.
Корректный порядок выключения:
UART5->CR1 = UART5->CR1 & ~(USART_CR1_RXNEIE | USART_CR1_IDLEIE | USART_CR1_RE);
После которого нужно считать SR и DR (чтобы сбросить потенциально возникшее за время обработки RXNE) и, если успел прийти новый символ - возможно здесь-же заново разрешить прерывания для нового кадра.
В UART5_Recive(void) аналогичные проблемы при манипуляции с флажками/регистрами. Прочитайте RM внимательнее!
Кроме того: непонятно - зачем Вы в каждом прерывании RXNE выключаете приёмник чтобы сразу его включить? Определённо будут проблемы, если выключите приёмник, а в этот момент начнёт поступать новый символ, потом его включите, и как стартовый бит будет воспринят один из информационных битов символа. Будет ошибка.