|
|
  |
Использование SPI_DMA в AT91SAM9 |
|
|
|
May 14 2009, 05:28
|
Участник

Группа: Участник
Сообщений: 37
Регистрация: 4-05-06
Пользователь №: 16 758

|
Всем привет! Написал работающий код (без использования DMA) для передачи блока данных из SDRAM в SPI - все работает исправно. Решил использовать DMA - возникли проблемы. Использую следующий код (в котором вызываются функции из spi.c):
/******************* Инициализация модуля SPI *************************/ void InitSPI1 (void) { // Конфигурирование MISO, MOSI, SPCK, NPCS0 AT91C_BASE_PIOB->PIO_ASR =\ AT91C_BASE_PIOB->PIO_PDR =\ AT91C_BASE_PIOB->PIO_MDDR = 0x0000000F;
SPI_Configure(AT91C_BASE_SPI1, AT91C_ID_SPI1, AT91C_SPI_MSTR | AT91C_SPI_PS | AT91C_SPI_MODFDIS | (0x19UL << 24)); SPI_ConfigureNPCS(AT91C_BASE_SPI1, 0, (1 << 24)|(1 << 16)|(6UL << 8)|AT91C_SPI_BITS_16|AT91C_SPI_CSAAT|AT91C_SPI_NCPHA);
SPI_Enable(AT91C_BASE_SPI1); }
unsigned int INIT1[] = {0x00112233, 0x44556677, 0x8899AABB, 0xCCDDEEFF, 0x00112233, 0x44556677, 0x8899AABB, 0xCCDDEEFF};
/******************* Передача данных в SPI *****************************/ void SendData (void) { SPI_WriteBuffer(AT91C_BASE_SPI1, (void *)INIT1, 8); mswait(10); // Задержка 10 мс while(!SPI_IsFinished(AT91C_BASE_SPI1)); // Проверка окончания передачи данных }
При вызове SendData () в регистр SPI1_TPR записывается адрес INIT1 (адрес SDRAM), в SPI1_TCR - длина блока. Проверил - все правильно. Но передается всего 4 байта вместо 48. Адрес увеличивается на 4 (SPI1_TPR), а SPI1_TCR уменьшается на единицу. И полный затык. Ищу в гугле и на сайте атмела более подробную информацию, описывающую работу с SPI_DMA, но что-то ни наглядных примеров, ни каких-либо четких рекомендаций пока не нашел. Буду благодарен за любую информацию.
|
|
|
|
|
May 15 2009, 03:59
|
Участник

Группа: Участник
Сообщений: 37
Регистрация: 4-05-06
Пользователь №: 16 758

|
Цитата(defunct @ May 15 2009, 01:26)  Дык, а где код которым Вы собсно DMA инициализируете на передачу? Код xx_TPR = (U32)&pRing->storage[ pRing->CurrFrameHead ]; xx_TCR = pRing->CurrFrameSize; xx_PTCR = AT91C_PDC_TXTEN; // enable transfer Спасибо за ответ. Извиняюсь за неполноту, привожу функцию (это код взятый из файла spi.c в примерах от атмела): unsigned char SPI_WriteBuffer(AT91S_SPI *spi, void *buffer, unsigned int length) { // Check if first bank is free if (spi->SPI_TCR == 0) { spi->SPI_TPR = (unsigned int) buffer; spi->SPI_TCR = length; spi->SPI_PTCR = AT91C_PDC_TXTEN; return 1; } // Check if second bank is free else if (spi->SPI_TNCR == 0) { spi->SPI_TNPR = (unsigned int) buffer; spi->SPI_TNCR = length; return 1; } // No free banks return 0; } Есть значительное сходство с Вашим ответом. Порылся еще в поиске. В одном из сообщений говорилось, что при использовании DMA необходимо одновременно запускать процедуры для приема и передачи данных (в частности настраивать регистры SPI_TCR и SPI_TRCR на одинаковое количество). Сделал так - заработало, но нестабильно - данные передаются без остановки примерно до 500 байт, при заданной длине длине свыше примерно 500 передаются каждый раз разное количество байт (в диапазоне от 500 до 1000) причем количество переданных байт всегда равно количеству принятых. Мне же требуется передать блок данных от 10кБ до 50 кБ. Работаю с JTAG-отладчиком (IAR+MT_Link) - может он как-то влиять на работу DMA?
|
|
|
|
|
May 15 2009, 09:59
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(PuHaT @ May 15 2009, 07:59)  В одном из сообщений говорилось, что при использовании DMA необходимо одновременно запускать процедуры для приема и передачи данных (в частности настраивать регистры SPI_TCR и SPI_TRCR на одинаковое количество). Или сначала запустить прием, а затем передачу, что вполне логично. Цитата(PuHaT @ May 15 2009, 07:59)  Мне же требуется передать блок данных от 10кБ до 50 кБ. Не знаю ваших причин, но, ИМХО, это не очень удачная идея - работать огромными блоками. Цитата(PuHaT @ May 15 2009, 07:59)  Работаю с JTAG-отладчиком (IAR+MT_Link) - может он как-то влиять на работу DMA? Вполне вероятно, попробуйте без него.
|
|
|
|
|
Jul 17 2009, 13:47
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(Atridies @ Jul 17 2009, 17:30)  Хочу сделать передачу по DMA от USART. Вопрос: DMA должен быть включен постоянно - или он должен включаться только перед приемом и передачей? Странный несколько вопрос - если Вы ждете приема данных, то DMA должен быть включен. При передаче - на Ваше усмотрение. Цитата(Atridies @ Jul 17 2009, 17:30)  А если у меня принимаемые данные по USART разной длины? Как настраивать счетчик? Заводите два буфера - RCV и RCV_NEXT, по заполнению RCV подключаете следующий RCV_NEXT. Если данные идут в виде пакетов с паузами, то можете просто завести буфер заведомо большего размера и ловить окончание передачи по RX timeout.
|
|
|
|
|
Jul 23 2009, 08:18
|
Участник

Группа: Участник
Сообщений: 22
Регистрация: 21-07-08
Пользователь №: 39 116

|
Цитата(PuHaT @ May 15 2009, 06:59)  В одном из сообщений говорилось, что при использовании DMA необходимо одновременно запускать процедуры для приема и передачи данных (в частности настраивать регистры SPI_TCR и SPI_TRCR на одинаковое количество) Странное замечание. Каналы приема и передачи не зависимы друг от друга, имеют разные регистры и могут по желанию использоваться либо нет. DMA трансфер будет осуществлен только в том случае если соответствующий регистр счетчик (TCR/TNCR или RCR/RNCR) не нулевой и установлен бит присутствия данных в буффере перефирии (TDR/RDR) и естественно если DMA включен. Целиком от вас зависит хотите ли вы трансфер данных осуществлять вручную (записавая данные в TDR/читая из RDR) или возложить всю работу на DMA. В одном из проектов по ходу создании прошивки я начал с передачи и приема - оба вручную по прерываниям (TDRE/RDRF & TMEMPTY). После того как был не удовлетворен этим перевел прием на работу через DMA в то время как передача по прежнему висела на прерывании - вручную записывая новые данные в TDR регистр. Никаких потерь не наблюдалось. Далее и передачу перевел на работу через DMA. Итого во всех трех случаях прием передача были без потерь. Очень вероятно влияние кеширования данных (если оно у вас включено). Либо обратите внимание на скорость работы - может быть у вас скорость передачи данных (частота SPI) граничат со скоростью с которой микроконтроллер способен обработать один трансфер (8-16 бит). Убедитесь что за целый промежуток времени когда у вас пересылаются 10-50к данных не произошла ни разу потеря (OVRES бит в регистре статуса SR должен быть постоянно 0)
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|