DMA для dsPIC. Контроллер Прямого доступа к памяти (DMA). DMA контроллер. Регистр Смещения Адреса Начала A DPSRAM Канала DMA x, страница 19

В течение нормальной операции в этом режиме, Нулевая Запись Данных может произойти только в ответ на запрос DMA периферийного устройства (то есть, после того, как данные были получены и доступны для передачи). Начальная запись CPU на периферийное устройство обязана запускать прием первого слова, после которого DMA заботится обо всех записях последующих периферийных (нулевых) данных. То есть запись пустого указателя CPU начинается, SPI (хозяин) посылает/получает данные, которые в свою очередь в конечном счете генерируют DMA, просят переместить недавно полученные данные.

Альтернативно, может использоваться принудительная передача DMA, чтобы ‘пнуть начало’ процесса. Однако, это будет также включать избыточное периферийное чтение (данные не правильны) и связанная настройка указателя DPSRAM, которая должна быть принята во внимание.

Figure 22-20: Data Transfer With Null Data Write Mode

Пример 22-10: SPI and DMA With Null Data Write Mode

Set up SPI for Master mode:

SPI1CON1bits.MODE16 = 1;   //Communication is word-wide (16 bits)

SPI1CON1bits.MSTEN = 1;     //Master Mode Enabled

SPI1STATbits.SPIEN = 1;        //Enable SPI Module

Set up DMA Channel 1 for Null Data Write mode:

unsigned int BufferA[16] __attribute__((space(dma)));

unsigned int BufferB[16] __attribute__((space(dma)));

DMA1CON = 0x0802;             // Null Write, Continuous, Ping-Pong,

// Post-Increment, Periph-to-RAM

DMA1CNT = 15;                                 // Transfer 16 words at a time

DMA1REQ = 0x000A;             // Select SPI1 as DMA request source

DMA1STA = __builtin_dmaoffset(BufferA);

DMA1STB = __builtin_dmaoffset(BufferB);

DMA1PAD = (volatile unsigned int) &SPI1BUF;

IFS0bits.DMA1IF = 0;

IEC0bits.DMA1IE = 1;                         // Enable DMA interrupt

DMA1CONbits.CHEN = 1;                  // Enable DMA Channel

DMA1REQbits.FORCE = 1;                 // Force First word after Enabling SPI

Set up DMA Interrupt Handler:

void __attribute__((__interrupt__)) _DMA1Interrupt(void)

{

static unsigned int BufferCount = 0;      // Keep record of which buffer

// contains Rx Data

if(BufferCount == 0)

{

ProcessRxData(BufferA); // Process received SPI data in

// DMA RAM Primary buffer

}

else

{

ProcessRxData(BufferB); // Process received SPI data in

// DMA RAM Secondary buffer

}

BufferCount ^= 1;

IFS0bits.DMA1IF = 0;              // Clear the DMA1 Interrupt Flag

}

22.7 ЗАПУСК DMA ПЕРЕДАЧ

Прежде, чем передачи DMA могут начаться, канал DMA нужно разрешить, устанавливая CHEN бит в ‘1’ в регистре DMAxCON. Когда канал DMA активен, он может быть повторно инициализирован, отключая этот канал (CHEN = 0), сопровождая последующим его разрешением (CHEN = 1). Этот процесс сбрасывает счетчик передачи DMA и устанавливает активный буфер DMA на первичный буфер.

Когда канал DMA и периферийное устройство должным образом инициализированы, передачи DMA стартуют, как только периферийное устройство готово переместить данные и выпускает запрос DMA. Однако, некоторые периферийные устройства не могут выпустить запрос DMA (и поэтому не будут запускать передачу DMA), пока некоторые условия не выполнены. В этих случаях, должна быть применена комбинация различных режимов DMA, чтобы инициализировать передачу DMA:

22.7.1 Старт DMA с Последовательным Периферийным Интерфейсом (SPI)

Старт передач DMA в\из SPI периферийного устройства зависит от SPI направления данных и ведущего  или ведомого режима:

только Tx в режиме ведущего - В этой конфигурации, запрос DMA не будет выпущен, пока не пошлют первый блок SPI данных. Для Инициализации передач DMA, пользовательское приложение должно сначала отправить данные, используя режим Manual Transfer DMA, или оно должно сначала записать данные в буфер SPI (SPIxBUF) независимо от DMA.