Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Использование SPI_DMA в AT91SAM9
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
PuHaT
Всем привет!
Написал работающий код (без использования 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, но что-то ни наглядных примеров, ни каких-либо четких рекомендаций пока не нашел. Буду благодарен за любую информацию.
defunct
Цитата(PuHaT @ May 14 2009, 08:28) *
Буду благодарен за любую информацию.

Дык, а где код которым Вы собсно DMA инициализируете на передачу?

Код
xx_TPR = (U32)&pRing->storage[ pRing->CurrFrameHead ];
xx_TCR = pRing->CurrFrameSize;
xx_PTCR = AT91C_PDC_TXTEN; // enable transfer
PuHaT
Цитата(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?
aaarrr
Цитата(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?

Вполне вероятно, попробуйте без него.
Atridies
Вопрос по этой же теме, поэтому не стал создавать нового топика.
Хочу сделать передачу по DMA от USART. Вопрос: DMA должен быть включен постоянно - или он должен включаться только перед приемом и передачей?
А если у меня принимаемые данные по USART разной длины? Как настраивать счетчик?

P.S. Впервые сталкиваюсь с DMA. И проца под рукой пока нет, чтобы проверить работу.

Заранее спасибо за ответ.
aaarrr
Цитата(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.
vmp
Добавлю. Если речь идет про ARM9, то при включенном кешировании данных буфера для DMA нужно либо располагать в некешируемой области памяти, либо каждый раз вручную сбрасывать кеш. Автоматическая синхронизация кеша в ARM9 отсутствует.
Albun
Цитата(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)
aaarrr
Цитата(Albun @ Jul 23 2009, 12:18) *
Странное замечание.

Ничего странного. Очевидно, что замечания касалось случая, когда и прием и передача осуществляются при помощи PDC. Если сначала включить передачу, а затем прием - можно получить потерю данных.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.