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

 
 
 
Reply to this topicStart new topic
> Кто как организует повтор обмена данными по UART'у через DMA?, LPC1768, IAR Embedded 5.4
sambotey
сообщение Sep 8 2011, 15:53
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 20
Регистрация: 25-08-11
Пользователь №: 66 868



Вопрос может показаться нелепым, но я на нем застрял. rolleyes.gif
Если между сеансами передачи данных организовать хотя бы небольшую задержку, то проблем никаких нет. Но если по окончании одного сеанса необходимо тут же начать новый, то второй почему-то зависает. Сразу приходит мысль о том, что по окончании первого сеанса был некорректно закрыт канал, но ни один из вариантов не увенчался успехом. За основу был взят алгоритм из даташита UM10360. LPC17xx. User manual:

Код
  
DMACC0CONFIGURATION_bit.H         = 1;   //any future DMA requests will be ignored
while (DMACC0CONFIGURATION_bit.A);      // wait, while channel FIFO has any data
DMACC0CONFIGURATION_bit.E         = 0;   //channel 0 disabled
while (DMACENBLDCHNS & 0x1);                //wait, while channel 0 is enabled


Но всевозможные очистки очереди запросов прерываний (DMACINTTCCLEAR), отключения DMA для UART'a (U1FCR), отключения каналов DMA (DMACCONFIGURATION = 0) и прочие не помогли.

На всякий случай приведу один из вариантов кода инициализации канала DMA:
Код
// Clear ALL DMA interrupt and error flag
DMACINTTCCLEAR = 0xFF;
DMACINTERRCLR = 0xFF;
DMACC0SRCADDR = 0x40010000;
DMACC0DESTADDR = (unsigned long)srcAddress;
DMACC0CONTROL = (size & 0x0FFF) //TransferSize
                             | (5 << 12)        //Source burst size is 32 bit
                             | (5 << 15)        //Destination burst size is 32 bit
                             | (0 << 18)        //Source transfer width is 1 byte
                             | (0 << 21)        //Destination transfer width is 1 byte  
                             | (0 << 26)        //Source address is NOT incremented              
                             | (1 << 27)        //Destination address is incremented    
                             | 0x80000000;   //The terminal count interrupt is enabled.
DMACCONFIGURATION = 0x01;       // Enable DMA channels, little endian      
DMACC0CONFIGURATION = (1  <<  0) //CHANNEL 0 ENABLE
                                       | (11 <<  1) //Source peripheral is UART1 Rx
                                       | (0  <<  6) //Destination peripheral is memory                          
                                       | (2  << 11) //Transfer type is "peripheral to memory"
                                       | (1  << 14) //Error interrupts are NOT masked out
                                       | (1  << 15) //Terminal count interrupts are NOT masked out
                                       | (0  << 18);//Enable DMA requests
while(!(DMACENBLDCHNS));
DMACINTTCCLEAR = 0x0F;



Однако мне интересно прежде всего, как Вы инициализируете и заканчиваете организацию передачи по UART'у через DMA. В частности, какие регистры и в какой последовательности при этом задействуете, а какие инициализируете в начале программы и не трогаете при повторении инициализации очередного сеанса.
Ни в даташите, ни в интернете, ни в примерах ИАР'а я не нашел однозначного ответа. В частности, из даташита не понятно, для чего нужны регистры, указывающие состояние передачи до маскирования (DMA Raw Error Interrupt Status register и DMA Raw Terminal Count Status register). Ведь мы маскируем прерывания еще до начала сеанса и какая может быть передача до этого момента?

В качестве обработчика прерываний я использую обработчик из примера.
Код
DWORD regVal;

__enable_interrupt();  

regVal = DMACINTTCSTATUS;
if ( regVal )
{
  DMATCCnt++;
  DMACINTTCCLEAR = regVal;
}

regVal = DMACINTERRSTAT;
if ( regVal )
{
  DMAErrCnt++;
  DMACINTERRCLR = regVal;
}

NVIC_ClrPend(NVIC_GP_DMA);


Вроде бы этого достаточно для определения окончания передачи, но судя по тому, что между передачами требуется задержка, о которой я писал в начале, складывается ощущение, что на этом передача не заканчивается.
Хотелось бы узнать, есть ли здесь какие-то "подводные камни". Может кто поделится секретом? rolleyes.gif
Go to the top of the page
 
+Quote Post
KRS
сообщение Sep 8 2011, 20:06
Сообщение #2


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

Группа: Модераторы
Сообщений: 1 951
Регистрация: 27-08-04
Из: Санкт-Петербург
Пользователь №: 555



Вы уверены что вам для UART нужен DMA?
для начала попробуйте настроить burst в 1 байт и ширину в 1 байт и для памяти и для уарта.
Go to the top of the page
 
+Quote Post
sambotey
сообщение Sep 9 2011, 04:52
Сообщение #3


Участник
*

Группа: Участник
Сообщений: 20
Регистрация: 25-08-11
Пользователь №: 66 868



Да, DMA очень нужен. Потому и приходится биться с ним уже сколько времени.
А рекомендуемую настройку я уже применял:

Код
DMACC0CONTROL = (size & 0x0FFF) //TransferSize
                | (2 << 12)        //SBSize. Source burst size is 8 bit
                | (2 << 15)        //DBSize. Destination burst size is 8 bit
                | (0 << 18)        //SWidth. Source transfer width is 1 byte
                | (0 << 21)        //DWidth. Destination transfer width is 1 byte  
                | (0 << 26)        //SI. Source address is NOT incremented              
                | (1 << 27)        //DI. Destination address is incremented    
                | 0x80000000;   //I. The terminal count interrupt is enabled.


Что касается burst size, то в даташите такое описание "indicates the number of transfers..." из которого не понятно, в каких единицах вычисляется это число - в байтах или битах. Впрочем, я перебрал все варианты этих параметров. Данные передаются лишь при SWidth=0, DWidth=0, SBSize=[3..7], DBSize=[3..7]. Но чему бы ни были равны SBSize и DBSize в указанных пределах, эффект не меняется при изменении этих параметров от 3 до 7 - передача идет, но между сеансами нужна задержка. При SBSize и DBSize равных 0, 1 и 2 данные не передаются вообще. Непонятно почему, ведь при SBSize и DBSize равных 0 по SPI нет проблем вообще.

Сообщение отредактировал sambotey - Sep 9 2011, 04:57
Go to the top of the page
 
+Quote Post
KRS
сообщение Sep 9 2011, 10:15
Сообщение #4


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

Группа: Модераторы
Сообщений: 1 951
Регистрация: 27-08-04
Из: Санкт-Петербург
Пользователь №: 555



Цитата(sambotey @ Sep 9 2011, 08:52) *
то в даташите такое описание "indicates the number of transfers..." из которого не понятно, в каких единицах вычисляется это число - в байтах или битах.

что непонятного - в пересылках, т.е. и не в битах и не в байтах, а в еденицах пересылки, которые вы задали в ширине шины.
А UART правильно настроен, там же надо trigger level у фифо в соотв. с барстом подбирать.
Go to the top of the page
 
+Quote Post
sambotey
сообщение Sep 9 2011, 13:21
Сообщение #5


Участник
*

Группа: Участник
Сообщений: 20
Регистрация: 25-08-11
Пользователь №: 66 868



KRS, спасибо за подсказки. Сейчас пробую новые настройки уарт'а.

А интересно, возможна ли корректная работа DMА при разных значениях SBSize и DBSize в DMACC0CONTROL? Вроде бы нежелательно, чтобы эти значения отличались друг от друга, но зачем тогда было вводит два разных параметра? Достаточно было ввести один "BSize", который применялся бы и к источнику, и к приемнику.
Go to the top of the page
 
+Quote Post
sambotey
сообщение Sep 9 2011, 14:25
Сообщение #6


Участник
*

Группа: Участник
Сообщений: 20
Регистрация: 25-08-11
Пользователь №: 66 868



Увы, пока безрезультатно.

Изначально, у меня были такие настройки UART'a:
Код
/**** Процедура инициализации UART ****/
PCONP_bit.PCUART1 = 1;
PCONP |= (1 << 29); // Enable GPDMA clock        

U1LCR = 0x83;          // 8 bits, no parity, 1 stop bit + DLAB bit;
U0FDR = 0x92;          // Uart baudrate is 1228800 bps
U0DLM = 0x00;
U0DLL = 0x04;    
U1LCR = 0x03;          // DLAB=0

U1IER = 0x07;
U1FCR = 0x0F;


Как видно, RX Trigger Level (в U1FCR) = 0, т.е. UART1 FIFO = 1 байт, что не подходило к моему burst size, который был равен 32 байта (SBSize=DBSize=5). Однако все работало cranky.gif

Цитата(KRS @ Sep 9 2011, 13:15) *
А UART правильно настроен, там же надо trigger level у фифо в соотв. с барстом подбирать.

Как я понял, требуется, чтобы "RX Trigger Level" и "burst size" были равны. Однако это не принесло ничего нового.

Сейчас читаю документацию архитектуры АРМ, есть ряд деталей, которых я не нашел в даташите от NXP. В частности,

Цитата
you must set the Enable bit of the DMAC before you enable any channels.

А у NXP прямо это не указывается.
Go to the top of the page
 
+Quote Post
KRS
сообщение Sep 9 2011, 19:29
Сообщение #7


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

Группа: Модераторы
Сообщений: 1 951
Регистрация: 27-08-04
Из: Санкт-Петербург
Пользователь №: 555



Цитата(sambotey @ Sep 9 2011, 17:21) *
А интересно, возможна ли корректная работа DMА при разных значениях SBSize и DBSize в DMACC0CONTROL? Вроде бы нежелательно, чтобы эти значения отличались друг от друга, но зачем тогда было вводит два разных параметра?

Возможно конечно! DMA должен сам перепаковать и т.п. у него же свой фифо есть!
Еще можно попробовать flow controller ом назначить UART (хотя у nxp в даташите это reserved)
Go to the top of the page
 
+Quote Post
sambotey
сообщение Sep 13 2011, 06:52
Сообщение #8


Участник
*

Группа: Участник
Сообщений: 20
Регистрация: 25-08-11
Пользователь №: 66 868



Увы, так я от необходимости задержки между сеансами и не избавился... В итоге, отложил эту проблему. Этот обмен данными выполняется однократно лишь в начале моей программы (этап инициализации), потому, по большому счету, все же не критично. Я так долго занимался этой проблемой, потому что мне казалось, что она тесно связана с действительно критичной проблемой, описанной мною в этом топике. Ее решением оказались следующие настройки:
UART: U1FCR = 0xCF
DMA: SBSize = DBSize = 0

Хотя и тут не обошлось без "танцев с бубнами", потому что мой этап инициализации программы при burst size = 0 уже не работает, ему burst size нужне не менее 3 (т.е., учитывая, что одна передача содержит 14 байт (U1FCR=0xCF), burst size = 3 означает передачу 16*14=224 байта, хотя у меня происходит обмен данными по 6 байт. Или я ошибаюсь в расчетах?)

Парадокс... Надеюсь, найду время попозже вернуться к нему.

Кстати, вышеприведенные настройки все же не приводят к желаемой скорости обмена данными, но работает более-менее стабильно. А вот желаемую скорость я смог получить при SBSize = DBSize = 7, и SWidth = 2 (32байта), но вот работа была нестабильной - через несколько сеансов не могу дождаться ответа от периферии.

KRS, спасибо большое за помощь.
Go to the top of the page
 
+Quote Post
KRS
сообщение Sep 13 2011, 07:36
Сообщение #9


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

Группа: Модераторы
Сообщений: 1 951
Регистрация: 27-08-04
Из: Санкт-Петербург
Пользователь №: 555



Цитата(sambotey @ Sep 13 2011, 10:52) *
хотя у меня происходит обмен данными по 6 байт.

В таком случае DMA не нужен, FIFO более чем достаточно!
Честно говоря вообще сомнительно использование DMA c UART.

DMA к UARTу особенно с переменным числом байтов в пакете проблематично цеплять, а у NXP судя по описанию он вообще криво подцеплен - там же только Burst Request подцеплен. А еще в описании UART таймаут тоже генерирует запрос к DMA, а т.к. подцеплен только барст то сколько байт по таймауту выгребет неизвестно если burst > 1. По идее таймаут к last линии должен быть подключен и flow контроллером должен быть UART но NXP данную конфигурацию не поддерживает!
Go to the top of the page
 
+Quote Post
sambotey
сообщение Sep 20 2011, 05:55
Сообщение #10


Участник
*

Группа: Участник
Сообщений: 20
Регистрация: 25-08-11
Пользователь №: 66 868



Обмен по 6 байт происходит лишь периодически, на этапах инициализации периферии и квитирования. Между этими этапами происходит активный обмен данными по 512 байт. А DMA я решил использовать постоянно, чтобы не переключаться все время между ФИФО и ДМА.
Но вот чего я никак не могу понять, так это разницы между регистрами "DMA Interrupt Terminal Count Request Status register" и "DMA Raw Terminal Count Status register". По даташиту вся разница заключается в том, что первый сигнализирует об успешном окончании передачи ПОСЛЕ МАСКИРОВАНИЯ, а второй - ДО МАСКИРОВАНИЯ. Какое маскирование здесь имеется ввиду? То, наличие или отсутствие которого мы определяем 15м битом регистра конфигурации DMACCхCONFIGURATION? Но ведь до задания этого регистра еще не происходит никакой передачи данных. Да и в своей программе я обнаружил странную вещь: передача данных еще не завершилась, а бит в регистре "DMA Interrupt Terminal Count Request Status register" уже устанавливается.
Go to the top of the page
 
+Quote Post
Lotor
сообщение Sep 20 2011, 07:32
Сообщение #11


Местный
***

Группа: Свой
Сообщений: 476
Регистрация: 3-07-07
Из: Санкт-Петербург
Пользователь №: 28 866



Цитата(sambotey @ Sep 20 2011, 09:55) *
Но вот чего я никак не могу понять, так это разницы между регистрами "DMA Interrupt Terminal Count Request Status register" и "DMA Raw Terminal Count Status register". По даташиту вся разница заключается в том, что первый сигнализирует об успешном окончании передачи ПОСЛЕ МАСКИРОВАНИЯ, а второй - ДО МАСКИРОВАНИЯ.

А что Вам непонятного? В регистре GPDMA_RAW_INT_TCSTAT устанавливается бит соответствующего канала после завершения передачи, если выставлен 31 бит в регистре GPDMA_CHX_CTRL (не зависимо от бита 15 в регистре GPDMA_CHX_CFG).


--------------------
Ковырял чукча отверткой в ухе, звук в телевизоре и пропал.
Go to the top of the page
 
+Quote Post
sambotey
сообщение Sep 20 2011, 11:54
Сообщение #12


Участник
*

Группа: Участник
Сообщений: 20
Регистрация: 25-08-11
Пользователь №: 66 868



Цитата(Lotor @ Sep 20 2011, 10:32) *
В регистре GPDMA_RAW_INT_TCSTAT устанавливается бит соответствующего канала после завершения передачи, если выставлен 31 бит в регистре GPDMA_CHX_CTRL (не зависимо от бита 15 в регистре GPDMA_CHX_CFG).

Понятно, что он выставляется. Мне не понятно ОТЛИЧИЕ регистра GPDMA_RAW_INT_TCSTAT от GPDMA_INT_TCSTAT(надеюсь, верно написал название второго регистра, т.к. не знаю, в каких терминах Вы написали их названия). Ведь и в регистре GPDMA_INT_TCSTAT также выставляется бит соответствующего канала после завершения передачи.
Go to the top of the page
 
+Quote Post
Lotor
сообщение Sep 20 2011, 13:13
Сообщение #13


Местный
***

Группа: Свой
Сообщений: 476
Регистрация: 3-07-07
Из: Санкт-Петербург
Пользователь №: 28 866



Цитата(sambotey @ Sep 20 2011, 15:54) *
Понятно, что он выставляется. Мне не понятно ОТЛИЧИЕ регистра GPDMA_RAW_INT_TCSTAT от GPDMA_INT_TCSTAT(надеюсь, верно написал название второго регистра, т.к. не знаю, в каких терминах Вы написали их названия). Ведь и в регистре GPDMA_INT_TCSTAT также выставляется бит соответствующего канала после завершения передачи.

В регистре GPDMA_INT_TCSTAT бит выставляется только в том случаи, если разрешены прерывания в GPDMA_CHX_CFG.
Проще говоря GPDMA_RAW_INT_TCSTAT используется тогда, когда отказываются от прерываний и завершение передачи определяют методом опроса.

ЗЫ Меня вот удивило, что копирование памяти (из sdram в sdram) по DMA выходит дольше, чем использование memcpy...


--------------------
Ковырял чукча отверткой в ухе, звук в телевизоре и пропал.
Go to the top of the page
 
+Quote Post

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

 


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


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