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

 
 
> STM32F4+HAL+FIFO_DMA+UART_TX
vitmeat
сообщение Aug 26 2015, 14:26
Сообщение #1





Группа: Участник
Сообщений: 13
Регистрация: 22-01-11
Пользователь №: 62 402



Доброго времени суток.

Я пытаюсь настроить передачу по UART при помощи кольцевого FIFO буфера с использованием соответствующего режима DMA.
Но как то не получилось у меня приостанавливать передачу, и стартовать ее заново с того же места, всегда получается с начала.
Функции HAL_UART_DMAPause и HAL_UART_DMAResume не работают, по крайней мере так, как я ожидаю.
__HAL_DMA_GET_COUNTER - возвращает количество еще не переданных данных.
__HAL_DMA_SET_COUNTER - устанавливает количество еще не переданных данных, но она опять же не работает.

Настройки DMA
Код
    hdma_tx.Init.Channel             = USARTx_TX_DMA_CHANNEL;
    hdma_tx.Init.Direction           = DMA_MEMORY_TO_PERIPH;
    hdma_tx.Init.PeriphInc           = DMA_PINC_DISABLE;
    hdma_tx.Init.MemInc              = DMA_MINC_ENABLE;
    hdma_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_tx.Init.MemDataAlignment    = DMA_MDATAALIGN_BYTE;
    hdma_tx.Init.Mode                = DMA_CIRCULAR;
    hdma_tx.Init.Priority            = DMA_PRIORITY_LOW;
    hdma_tx.Init.FIFOMode            = DMA_FIFOMODE_ENABLE;
    hdma_tx.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
    hdma_tx.Init.MemBurst            = DMA_MBURST_SINGLE;
    hdma_tx.Init.PeriphBurst         = DMA_MBURST_SINGLE;


В итоге сейчас остановился на реализации отдельного кольцевого FIFO буфера и обычной передаче по DMA, а в прерывании DMA дописываю в буфер то, что еще пришло за время передачи. Но получается что у меня два буфера, один FIFO другой DMA.

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

Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
SasaVitebsk
сообщение Aug 27 2015, 05:14
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521



wacko.gif
Работаешь - работаешь. Читаешь доки - читаешь. А потом послушаешь некоторых из местных, и таким... э... идиотом себя чувствуешь... ))

Прошу прощения, а можно мне пояснить ...
Зачем использовать DMA с FIFO. Скажем, что это даёт? Я когда читал, то прошёл это по диагонали. Подумал, что это используется с устройствами которые с FIFO. А так как в UART FIFO нет, то и сделал без этого ... Растолкуйте по русски плиз. ))
Go to the top of the page
 
+Quote Post
SSerge
сообщение Aug 27 2015, 07:30
Сообщение #3


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

Группа: Свой
Сообщений: 1 719
Регистрация: 13-09-05
Из: Novosibirsk
Пользователь №: 8 528



Цитата(SasaVitebsk @ Aug 27 2015, 12:14) *
Прошу прощения, а можно мне пояснить ...
Зачем использовать DMA с FIFO. Скажем, что это даёт?

Буферизация ввода/вывода в любом случае полезна, даже без DMA.
Вот написали Вы в своей программе printf("Hello world!\n"); что приведёт к передаче в stdout тринадцати байт, а то и 14, если \n заменяется при выводе на пару \n\r.
Ну что теперь, ждать пока все эти байты будут переданы уартом и только после этого возвращать управление из printf ?
Конечно же нет, гораздо лучше передаваемые данные закинуть в некий промежуточный буфер, инициировать начало передачи и вернуться в основную программу, следующий оператор исполнять. А уж драйвер, обслуживающий уарт пусть сам разбирается с передачей, нам по большому счёту неважно как он будет это делать, по прерываниям или с использованием DMA.

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

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

В примере с printf буферизация на самом деле выполняется дважды. Ведь stdout это указатель на структуру FILE, в этой структуре лежат указатели на несколько буферов, т.е. эта структура вместе с низкоуровневыми функциями является фифо-буфером. В случае с уартом в принципе можно обойтись однократной буферизацией, либо работая напрямую с буферами из FILE либо заменив его своей реализацией фифо (и потерять с возможность использовать printf и putchar). Для более сложных устройств двойная буферизация - в программе и в драйвере - обычное дело.


--------------------
Russia est omnis divisa in partes octo.
Go to the top of the page
 
+Quote Post
SasaVitebsk
сообщение Aug 27 2015, 09:02
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521



Цитата(SSerge @ Aug 27 2015, 10:30) *
Буферизация ввода/вывода в любом случае полезна, даже без DMA.

Наверное я объяснил неверно. Буферизация мне понятна. Вот сделал я буфер и отсылаю этот готовый пакет в UART. Я его отсылаю ч/з DMA. А причём здесь FIFO. Вот это непонятно.
Вот так я передаю
Код
// Передача в nCOM. nCOM = 0, 1, 2.
// Через DMA
void vUSARTTransmit(uint32_t nCom)
{
  DMA_Stream_TypeDef *DMA_Stream;
  
  // Выбрать канал DMA
  // Остановить его на всякий случай
  // Очистить флаги
  // Выбрать канал
  // Инициализировать адрес периферии в DMA контроллере
  if(nCom == 1)
  {
    USART2_WR;                                                // Переключаю на передачу
    //vTaskDelay(10);                                            // Сделать паузу
    DMA_Stream = DMA1_Stream6;
    //DMA_Stream->CR &= ~DMA_SxCR_EN;
    //DMA1->LIFCR = DMA_LIFCR_CTCIF2 | DMA_LIFCR_CHTIF2 | DMA_LIFCR_CTEIF2 | DMA_LIFCR_CDMEIF2 | DMA_LIFCR_CFEIF2;
    DMA_Stream->PAR = (uint32_t)&USART2->DR;                // USART 2
    USART2->CR3 |= USART_CR3_DMAT;                            // разрешить передачу
    USART2->CR1 &= ~USART_CR1_RE;                            // для подавления эха запретить чтение
    //USART2->SR = (uint16_t)~USART_SR_TC;
  }
  else if(nCom == 2)
  {
    USART3_WR;                                                // Переключаю на передачу
    //vTaskDelay(10);                                            // Сделать паузу
    DMA_Stream = DMA1_Stream3;
    //DMA_Stream->CR &= ~DMA_SxCR_EN;
    //DMA1->LIFCR = DMA_LIFCR_CTCIF3 | DMA_LIFCR_CHTIF3 | DMA_LIFCR_CTEIF3 | DMA_LIFCR_CDMEIF3 | DMA_LIFCR_CFEIF3;
    DMA_Stream->PAR = (uint32_t)&USART3->DR;                // USART 3
    USART3->CR3 |= USART_CR3_DMAT;                            // разрешить передачу
    //USART3->SR = (uint16_t)~USART_SR_TC;
  }
  else
  {
    DMA_Stream = DMA2_Stream7;
    //DMA_Stream->CR &= ~DMA_SxCR_EN;
    //DMA1->LIFCR = DMA_LIFCR_CTCIF1 | DMA_LIFCR_CHTIF1 | DMA_LIFCR_CTEIF1 | DMA_LIFCR_CDMEIF1 | DMA_LIFCR_CFEIF1;
    DMA_Stream->PAR = (uint32_t)&USART1->DR;                // USART 1
    USART1->CR3 |= USART_CR3_DMAT;                            // разрешить передачу
    //USART1->SR = (uint16_t)~USART_SR_TC;
  }

  ComData[nCom].fRead = FALSE;
  // CR Memory & Peripheral single transfer, Priority level Medium, Peripheral increment PSIZE, Memory & Peripheral data size = byte
  // Memory increment, Peripheral no increment, не повторять, Memory-to-peripheral, Transfer complete interrupt enable, канал 4
  DMA_Stream->CR = DMA_SxCR_CHSEL_2 | DMA_SxCR_PL_0 | DMA_SxCR_MINC | DMA_SxCR_DIR_0 | DMA_SxCR_TCIE;
  // Указать буфер
  DMA_Stream->M0AR = (uint32_t)ModbusData[nCom].pTxBuf;
  // Загрузить длину пакета
  DMA_Stream->NDTR = ModbusData[nCom].Ptr;
  // FIFO is full
  //DMA_Stream->FCR = DMA_SxFCR_FTH;
  ComData[nCom].state = - ModbusData[nCom].Ptr;
  
  
  // Разрешить работу DMA
  DMA_Stream->CR |= DMA_SxCR_EN;
}

ну и два прерывания. По завершению DMA (разрешаю прерывание по завершению передачи). И по завершению передачи (переключение на приём).
Go to the top of the page
 
+Quote Post

Сообщений в этой теме
- vitmeat   STM32F4+HAL+FIFO_DMA+UART_TX   Aug 26 2015, 14:26
- - DrGluck   Этимологию и топонимику DMA в студию ... ( дубль 2...   Aug 26 2015, 14:41
- - Golikov A.   да ничего они не индифферентны.... они шаряться по...   Aug 26 2015, 16:22
- - vitmeat   Ну в общем суть такая: * Послали данных, настрои...   Aug 26 2015, 16:51
|- - SSerge   Цитата(vitmeat @ Aug 26 2015, 23:51) Как ...   Aug 26 2015, 17:33
|- - vitmeat   Цитата(SSerge @ Aug 26 2015, 20:33) А зач...   Aug 26 2015, 17:39
- - Golikov A.   __HAL_DMA_SET_COUNTER __HAL_DMA_GET_COUNTER как ...   Aug 26 2015, 17:03
- - vitmeat   Ну, в общем, один и тот же: #define __HAL_DMA_SET_...   Aug 26 2015, 17:11
- - DrGluck   "... да ничего они не индифферентны.... они ш...   Aug 26 2015, 17:18
- - SSerge   Настроить в регистрах DMA начальный адрес и количе...   Aug 26 2015, 18:04
- - Golikov A.   Цитата- записал на скрижали ... sm.gif копирайт не...   Aug 26 2015, 19:48
|- - king2   Можно еще настроить DMA в режим curcular? чтобы он...   Aug 26 2015, 22:05
- - SSerge   Ну так модбасу больше одного пакета за раз передав...   Aug 27 2015, 09:21


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

 


RSS Текстовая версия Сейчас: 20th August 2025 - 15:24
Рейтинг@Mail.ru


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