|
|
  |
Кто как организует повтор обмена данными по UART'у через DMA?, LPC1768, IAR Embedded 5.4 |
|
|
|
Sep 8 2011, 15:53
|
Участник

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

|
Вопрос может показаться нелепым, но я на нем застрял. Если между сеансами передачи данных организовать хотя бы небольшую задержку, то проблем никаких нет. Но если по окончании одного сеанса необходимо тут же начать новый, то второй почему-то зависает. Сразу приходит мысль о том, что по окончании первого сеанса был некорректно закрыт канал, но ни один из вариантов не увенчался успехом. За основу был взят алгоритм из даташита 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); Вроде бы этого достаточно для определения окончания передачи, но судя по тому, что между передачами требуется задержка, о которой я писал в начале, складывается ощущение, что на этом передача не заканчивается. Хотелось бы узнать, есть ли здесь какие-то "подводные камни". Может кто поделится секретом?
|
|
|
|
|
Sep 9 2011, 04:52
|
Участник

Группа: Участник
Сообщений: 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
|
|
|
|
|
Sep 9 2011, 13:21
|
Участник

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

|
KRS, спасибо за подсказки. Сейчас пробую новые настройки уарт'а.
А интересно, возможна ли корректная работа DMА при разных значениях SBSize и DBSize в DMACC0CONTROL? Вроде бы нежелательно, чтобы эти значения отличались друг от друга, но зачем тогда было вводит два разных параметра? Достаточно было ввести один "BSize", который применялся бы и к источнику, и к приемнику.
|
|
|
|
|
Sep 9 2011, 14:25
|
Участник

Группа: Участник
Сообщений: 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). Однако все работало Цитата(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 прямо это не указывается.
|
|
|
|
|
Sep 13 2011, 06:52
|
Участник

Группа: Участник
Сообщений: 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, спасибо большое за помощь.
|
|
|
|
|
Sep 20 2011, 05:55
|
Участник

Группа: Участник
Сообщений: 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" уже устанавливается.
|
|
|
|
|
Sep 20 2011, 07:32
|
Местный
  
Группа: Свой
Сообщений: 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).
--------------------
Ковырял чукча отверткой в ухе, звук в телевизоре и пропал.
|
|
|
|
|
Sep 20 2011, 11:54
|
Участник

Группа: Участник
Сообщений: 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 также выставляется бит соответствующего канала после завершения передачи.
|
|
|
|
|
Sep 20 2011, 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...
--------------------
Ковырял чукча отверткой в ухе, звук в телевизоре и пропал.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|