|
|
  |
DMA - для чего он и как его использовать |
|
|
|
Feb 1 2007, 14:08
|
Местный
  
Группа: Свой
Сообщений: 211
Регистрация: 9-11-06
Пользователь №: 22 136

|
Цитата(Karl @ Feb 1 2007, 13:26)  Спасибо, вроде все понятно. А с приемом Вы не разбирались? Нет, мне пока без надобности. Я на прием PDC использую с ADC. Код надо?
|
|
|
|
|
Feb 1 2007, 16:47
|
Частый гость
 
Группа: Свой
Сообщений: 179
Регистрация: 4-02-05
Пользователь №: 2 429

|
Цитата(Kitsok @ Feb 1 2007, 16:08)  Цитата(Karl @ Feb 1 2007, 13:26)  Спасибо, вроде все понятно. А с приемом Вы не разбирались?
Нет, мне пока без надобности. Я на прием PDC использую с ADC. Код надо? Да, пригодится. Кстати, передача заработала сразу  Спасибо! У меня на SPI АЦП сидит. Так что надо и передачу и прием.
|
|
|
|
|
Feb 1 2007, 19:38
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(sonycman @ Jan 31 2007, 23:40)  The Memory Controller has a simple, hard-wired priority bus arbiter that gives the control of the bus to one of the two masters. The Peripheral DMA Controller has the highest priority; the ARM processor has the lowest one. [AT91SAM7S.pdf, 6175G–ATARM–22-Nov-06, page 120]
Действительно, курить в сторонке будет процессор, а не DMA... Причем по другому для периферийного железа которое не имеет своих буферов и быть не может, например, летит в 100 Mbit интерфейс 1500 байтовый пакет. Куда ему прикажете его девать? Тут уж или терять, или процессор идет на перекур. Без вариантов. Цитата(ASN @ Jan 31 2007, 22:05)  zltigo Режим работы контроллера DMA определяется в первую очередь типом используемой накристальной шины. Определяется, например, свежие LPC23xx имеют два банка памяти и соответственно две шины, что позволяет достаточно независимо работать DMA (в своих 8K) и CPU каждому в своем банке большую часть времени. Обычные ARM7 такого не имеют.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Feb 2 2007, 11:48
|
Местный
  
Группа: Свой
Сообщений: 211
Регистрация: 9-11-06
Пользователь №: 22 136

|
Это инициализация Код #define NCHANNELS 8
extern volatile unsigned portSHORT sADC_RAW[NCHANNELS*2]; #define TRGEN (0x0) // Hardware triggering #define TRGSEL (0x0) // Use a Timer output signal (on rising edge) from TIOA0 (for this example) #define LOWRES (0x0) // 8-bit result output #define SLEEP (0x0) // Normal Mode #define PRESCAL (0x0f) // Max value #define STARTUP (0xc) // This time period must be higher than 20 ╣s and not 20 ms #define SHTIM (0x2) // Must be higher than 3 ADC clock cycles but depends on output // impedance of the analog driver to the ADC input
void InitADC(void) {
// Reset ADC AT91F_ADC_SoftReset (AT91C_BASE_ADC);
// Open PDC for ADC AT91F_PDC_Open (AT91C_BASE_PDC_ADC);
// Configure PDC for 2 buffers NCHANNELS bytes long each (Warning! Depends on LOWRES bit) AT91F_PDC_ReceiveFrame ( AT91C_BASE_PDC_ADC , (char *) &sADC_RAW[0], NCHANNELS, (char *) &sADC_RAW[NCHANNELS], NCHANNELS);
// Configure ADC AT91F_ADC_CfgModeReg (AT91C_BASE_ADC, (SHTIM << 24) | (STARTUP << 16) | (PRESCAL << 8) | (SLEEP << 5) | (LOWRES <<4) | (TRGSEL << 1) | (TRGEN ) );
// Enable all 8 channes AT91F_ADC_EnableChannel(AT91C_BASE_ADC, (1<<NCHANNELS) - 1);
// Fire conversion AT91F_ADC_StartConversion(AT91C_BASE_ADC); } А это собственно работа Код // Check what buffer to use from ADC if (AT91C_BASE_PDC_ADC->PDC_RCR == 0) { ptrADC_RAW=NCHANNELS; AT91F_PDC_ReceiveFrame ( AT91C_BASE_PDC_ADC , (char *) &sADC_RAW[0], NCHANNELS, (char *) &sADC_RAW[NCHANNELS], NCHANNELS); } else { ptrADC_RAW=0; }
// Re-fire conversion AT91F_ADC_StartConversion(AT91C_BASE_ADC); Тут возможно следовало бы использовать библиотечные функции, но я не запарился и читаю напрямую PDC_RCR. ptrADC_RAW нужен для того, чтобы знать, в какой части буфера лежат свежие данные: Код // Convert 10-bit wide ADC results into 8-bit wide // Clean target array for(i=0;i<(NCHANNELS*10/8);i++) ucAxes[i]=0;
// Do bit manipulations // The trick with +0x0200 & 0x03ff is - we need negative 10-bit wide number for(i=0;i<(NCHANNELS*10);i++) { ucAxes[i/8] += (((((sADC_RAW[ptrADC_RAW+(i/10)] + 0x0200)&0x03ff)>> (i%10)) & 0x01) << (i%8)); }
Сообщение отредактировал Kitsok - Feb 2 2007, 11:51
|
|
|
|
|
Feb 6 2007, 15:28
|
Местный
  
Группа: Свой
Сообщений: 211
Регистрация: 9-11-06
Пользователь №: 22 136

|
Цитата(Karl @ Feb 6 2007, 13:16)  Можно ли одновременно передавать массив данных в SPI через ДМА и получать данные из SPI через тот же ДМА? Что-то у меня не получается такой обмен... Передача идет, а прием - нет. Ну вообще, PDA - штука двунаправленная, но конкретику надо смотреть в даташите и всяких примерах. Я не реализовывал двунаправленную передачу по SPI.
|
|
|
|
|
Feb 7 2007, 08:44
|
Частый гость
 
Группа: Свой
Сообщений: 179
Регистрация: 4-02-05
Пользователь №: 2 429

|
Цитата(Kitsok @ Feb 6 2007, 17:28)  Цитата(Karl @ Feb 6 2007, 13:16)  Можно ли одновременно передавать массив данных в SPI через ДМА и получать данные из SPI через тот же ДМА? Что-то у меня не получается такой обмен... Передача идет, а прием - нет.
Ну вообще, PDA - штука двунаправленная, но конкретику надо смотреть в даташите и всяких примерах. Я не реализовывал двунаправленную передачу по SPI. Спасибо, вроде разобрался. Заработало.
|
|
|
|
|
Feb 12 2007, 19:01
|
Местный
  
Группа: Свой
Сообщений: 211
Регистрация: 9-11-06
Пользователь №: 22 136

|
Цитата(Karl @ Feb 7 2007, 08:44)  Спасибо, вроде разобрался. Заработало. Добрый день! А можете код показать? Удалось ли принимать данные с использованием PDC?
|
|
|
|
|
Feb 15 2007, 07:26
|
Частый гость
 
Группа: Свой
Сообщений: 179
Регистрация: 4-02-05
Пользователь №: 2 429

|
Цитата(Kitsok @ Feb 12 2007, 21:01)  Цитата(Karl @ Feb 7 2007, 08:44)  Спасибо, вроде разобрался. Заработало.
Добрый день! А можете код показать? Удалось ли принимать данные с использованием PDC? Да, передачу и прием по PDC организовать удалось. Проблемы, как оказалось, были не с PDC, а с некорректной работой с SPI. Инициализация SPI: Код void SPI_ini(void) {
AT91F_SPI_Reset(AT91C_BASE_SPI); //delay_ms(5); // Инициализация SPI. Запустим на работу с частотой примерно 2,5 МГц // Конфигурация канала АЦП (2 канал) AT91F_PMC_EnablePeriphClock(AT91C_BASE_PMC, 1 << AT91C_ID_SPI); // Тактирование на SPI AT91F_SPI_CfgMode(AT91C_BASE_SPI, 1<<0| //Интерфейс работает в режиме ведущего. 0<<1| //Фиксированный выбор корпуса внешнего периферийного устройства. 0<<2| //PCSDEC: Декодирование выбора корпуса 0 = Периферийные устройства непосредственно подключены к выводам выбора корпуса. 0<<4| //MODFDIS: Определение ошибки режима работы 0 =Определение ошибки режима работы запрещено. 0<<7| // Зацикливание 0 - отключено 0xb<<16); // PCS: Выбор корпуса периферии Корпус 3 AT91F_SPI_CfgCs(AT91C_BASE_SPI,2, AT91C_SPI_BITS_8| // 8 бит в пакете 400<<8| // Частота SPI в 20 наза меньше MCK (необходимо не более 2,5 МГц) 2<<16| // Задержка перед выдачей тактовой частоты 0<<24| // Задержка между последовательными передачами данных 1<<1);
AT91F_SPI_Enable(AT91C_BASE_SPI); AT91F_PDC_Open(AT91C_BASE_PDC_SPI); } Собственно работа: Код for(;;)
{ while(AT91F_SPI_SendFrame(AT91C_BASE_SPI,(char*) &SPI_buf_TX[0],sizeof(SPI_buf_TX),0,0) == 0); u08 a = AT91F_SPI_ReceiveFrame(AT91C_BASE_SPI,(char*) &SPI_buf_RX[0],sizeof(SPI_buf_TX),0,0); // Ожидаем, пока приемный буфер заполнится. В дальнейшем включу на прерывание. while(!( a = AT91C_BASE_SPI->SPI_SR & AT91C_SPI_ENDRX)); ... ... ... }
|
|
|
|
|
Feb 15 2007, 19:59
|

Профессионал
    
Группа: Свой
Сообщений: 1 065
Регистрация: 8-10-05
Из: Kiev, UA
Пользователь №: 9 380

|
Цитата Собственно работа: Код for(;;)
{ while(AT91F_SPI_SendFrame(AT91C_BASE_SPI,(char*) &SPI_buf_TX[0],sizeof(SPI_buf_TX),0,0) == 0); u08 a = AT91F_SPI_ReceiveFrame(AT91C_BASE_SPI,(char*) &SPI_buf_RX[0],sizeof(SPI_buf_TX),0,0); // Ожидаем, пока приемный буфер заполнится. В дальнейшем включу на прерывание. while(!( a = AT91C_BASE_SPI->SPI_SR & AT91C_SPI_ENDRX)); ... ... ... } Кстати абсолютно не вижу кайфа в такой конструкции. ДМА гонит данные, ядро ожидает завершения. Точно так же можно использовать и программные счетчик и указатель. Чтобы действительно получить выигрыш, флажок завершения приема/передачи надо прицепить к прерыванию. В таком случае действительно ДМА будет жить своей жизнью, а ядро отвлекаться на подготовку/обработку данных один раз на фрейм, а в остальное время заниматься чем-то полезным.
--------------------
Вони шукають те, чого нема, Щоб довести, що його не існує.
|
|
|
|
|
Feb 16 2007, 09:29
|
Частый гость
 
Группа: Свой
Сообщений: 179
Регистрация: 4-02-05
Пользователь №: 2 429

|
Цитата(beer_warrior @ Feb 15 2007, 21:59)  Цитата Собственно работа: Код for(;;)
{ while(AT91F_SPI_SendFrame(AT91C_BASE_SPI,(char*) &SPI_buf_TX[0],sizeof(SPI_buf_TX),0,0) == 0); u08 a = AT91F_SPI_ReceiveFrame(AT91C_BASE_SPI,(char*) &SPI_buf_RX[0],sizeof(SPI_buf_TX),0,0); // Ожидаем, пока приемный буфер заполнится. В дальнейшем включу на прерывание. while(!( a = AT91C_BASE_SPI->SPI_SR & AT91C_SPI_ENDRX)); ... ... ... } Кстати абсолютно не вижу кайфа в такой конструкции. ДМА гонит данные, ядро ожидает завершения. Точно так же можно использовать и программные счетчик и указатель. Чтобы действительно получить выигрыш, флажок завершения приема/передачи надо прицепить к прерыванию. В таком случае действительно ДМА будет жить своей жизнью, а ядро отвлекаться на подготовку/обработку данных один раз на фрейм, а в остальное время заниматься чем-то полезным. А Вы прочитайте внимательнее комментарии. Я выложил кусок тестовой програмки. Так проще разобраться в коде тем, кто будет смотреть. Реально у меня все на прерываниях.
|
|
|
|
|
Feb 16 2007, 11:46
|
Местный
  
Группа: Свой
Сообщений: 211
Регистрация: 9-11-06
Пользователь №: 22 136

|
Цитата(beer_warrior @ Feb 15 2007, 19:59)  Кстати абсолютно не вижу кайфа в такой конструкции. ДМА гонит данные, ядро ожидает завершения. Точно так же можно использовать и программные счетчик и указатель. Чтобы действительно получить выигрыш, флажок завершения приема/передачи надо прицепить к прерыванию. В таком случае действительно ДМА будет жить своей жизнью, а ядро отвлекаться на подготовку/обработку данных один раз на фрейм, а в остальное время заниматься чем-то полезным. Ну почему-же нету кайфа. Я например под FreeRTOS клепаю, так у меня, пока данные не готовы, будет отдаваться выполнение другим задачам  Другой вопрос меня интересует, может доку не внимательно читал. Вот допустим, я так сделал железо, что один и тот-же ChipSelect у меня работает и на передачу и на прием (разнос по сигналами MOSI/MISO). Запускаю я одновременно и передачу и прием. SPI может дупелксно и передавать и принимать?
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|