/
Direct Memory Access (DMA)

Direct Memory Access (DMA)

Direct Memory Access (or DMA), is a microcontroller feature, which allows peripheral interfaces to directly access memory, completely bypassing the CPU. The CPU only needs to setup the transfer of data. The rest of the process is done without it.

DMA is a commonly used in graphic, network, and sound cards. More importantly, it is used in multi-core processors, which is essentially the usage of DMA in the PICpilot.

One DMA cycle follows this procedure:

In the PICpilot, the only peripheral that uses DMA is the SPI interface, although many other ones are supported.

When a DMA transfer occurs, first a peripheral makes a request to the DMA controller (based on a predefined channel number). The request causes the DMA controller to read or write to a preconfigured peripheral address. Once this is completed, the DMA controller writes the data to the DPSRAM location (this is RAM dedicated to the DMA controller) or reads from it. The direction in which this transfer occurs depends on the register value corresponding to the predefined settings of the DMA controller.

In the PICpilot, the Direct Memory Access module is constantly active through the SPI1 module. This means that the data transmission is continuous between both chips. Essentially, when this process is continuous it provides a way to share global variables between two physical microcontrollers simultaneously. This is how path data gets transmitted to the attitude manager. The path data is made global between the two chips.

It should be noted that DMA is also used between the path manager chip and the GPS.

On the PIC microcontroller, the DMA must only be initialized. The DMA controller continues operation automatically without direct processor input. The code to initialize the interface is below.

In the code

In order to transfer data using DMA, both chips must have been initialized. In the PICpilot, only the DMA interface is initialized for data transfer between the GPS and the Path Management Chip (PM Chip), as well as the PM Chip and the Attitude Management Chip (AM Chip). Both of these connections are enabled using SPI (see previous section).

The GPS continuously sends data as soon as it is plugged in. It sends data in the following data format:

typedef struct _GPSData { long double latitude; //8 Bytes long double longitude; //8 Bytes float time; //4 Bytes float speed; int altitude; int heading; char satellites; //1 Byte char positionFix; } GPSData;

In order to properly configure this connection the following code is used:

GPSData gpsData __attribute__((space(dma))); /* * */ void __attribute__((__interrupt__, no_auto_psv)) _DMA2Interrupt(void){ newGPSDataAvailable = 1; IFS1bits.DMA2IF = 0;// Clear the DMA0 Interrupt Flag } void init_DMA2(){ IFS1bits.DMA2IF = 0; IEC1bits.DMA2IE = 1; DMA2CONbits.AMODE = 0b00; //Register Indirect Mode DMA2CONbits.DIR = 0; //Transfer from SPI to DSPRAM DMA2CONbits.MODE = 0b00; //Transfer continuously DMA2CONbits.SIZE = 1; //Transfer bytes (8 bits) DMA2STA = __builtin_dmaoffset(&gpsData); //Primary Transfer Buffer DMA2PAD = (volatile unsigned int) &SPI2BUF; //Peripheral Address DMA2CNT = sizeof(GPSData) - 1; //+1 for checksum //DMA Transfer Count Length DMA2REQ = 0b0100001; //IRQ code for SPI2 DMA2CONbits.CHEN = 1; //Enable the channel }

Note how a block of memory ("GPSData") is reserved for the incoming data from the GPS unit. The register values are configured as follows:

Register

Value

Function

Register

Value

Function

DMA2CONbits.AMODE

0

This enables Register Indirect with Post Increment Mode. This enables data to be stored in chunks one after another (incremented locations).

DMA2CONbits.DIR

0

This indicates the direction that data travels on the bus. In this case, the data is always incoming. Therefore, it is copied from the SPI interface to the DSPRAM.

DMA2CONbits.MODE

0

This indicates if the transfer occurs a single time, or continuously, and whether a ping pong buffer should be used. It is currently enabled for continuous usage without a ping pong buffer.

DMA2CONbits.SIZE

1

Indicates if each DMA transfer is 8 bits or 16 bits. In this case, it is 8 bits.

DMA2STA

&gpsData with an added DMA offset

This indicates where the primary buffer is located. This memory block was initialized at the beginning of the above code snippet, where "space(dma)" is called.

DMA2PAD

&SPI2BUF

This stores the referenced location from where the data is obtained. (This DMA channel will use the SPI2 buffer to get the data).

DMA2CNT

Number of bytes in GPSData - 1

This is a counter variable, which indicates the number of transfers that need to be completed per DMA request.

DMA2REQ

0b0100001

This is the IRQ (Interrupt Request) code for the SPI2 interface. This allows the peripheral to send an interrupt request to the DMA controller instead of the CPU.

DMA2CONbits.CHEN

1

Enables the DMA channel.

On the other hand, the setup between the PM chip and the AM chip is slightly different. These two chips communicate with each other simultaneously through the SPI1 interface. The code controlling the initialization found in InterchipDMA.c/.h.

The data being sent to the PM chip from the AM chip is in the form of:

typedef struct _AMData { WaypointWrapper waypoint; float pathGain; float orbitGain; float calibrationHeight; char command; char checksum; } AMData;

Vice-versa, the data being sent to the AM chip from the PM chip is in the form of:

The initialization process is extremely similar for both chips (PM and AM). Each chip requires a DMA channel to read the incoming data, as well as to write the outgoing data. As a result, both the AM chip and the PM chip have the same setup with a few different variables names:

The above code is very similar to the first example with the GPS. The differences include the direction of data transfer, the buffer variables, the IRQ codes, as well as the 16 bit mode interfacing.

Also, in order to initialize transfer, the SPI master must send the first packet. This is evident in the DMA0 interrupt routine:

A DMA request is forced by setting the DMA1REQbits.FORCE bit to 1. The following sets of data do not need to be forced, they happen automatically (since continuous mode was enabled).

Related content