11. Direct Memory Access

Dynamic C version 10 introduced support for the internal DMA controller of the Rabbit 4000 micropro­cessor. DMA stands for “Direct Memory Access.” The DMA controller takes control of the address and data bus from the CPU so that data transfers occur without processor handling.There are eight DMA chan­nels; a DMA channel is a system pathway for transferring data directly to or from memory and peripheral devices without using the CPU. DMA memory addresses are always physical addresses and are never translated by the MMU.

The rest of this section discusses DMA from a software perspective. For detailed information about the DMA controller, see the Rabbit 4000 Microprocessor User’s Manual.

11.1 DMA Registers and Global Resources

There are some global resources associated with all DMA channels. These resources are managed by Dynamic C libraries because it would be difficult for most users to determine their optimal usage. The library DMA.LIB contains all of the DMA functionality available to the user. The advanced user can man­ually override the library settings by directly manipulating the DMA control registers; however, this is not recommended.

The debug function DMAprintRegs() lets you view the values of the DMA master registers:

For more information on Rabbit registers, click on “I/O Registers” on the Dynamic C help menu or consult the Rabbit 4000 Microprocessor User’s Manual (or the user’s manual specific to your Rabbit) to get infor­mation about directly manipulating the DMA registers.

11.2 API Functions

Dynamic C provides several API functions for use with the DMA controller that was introduced with the Rabbit 4000. These functions make it unnecessary for an application to directly manipulate the DMA reg­isters. Complete descriptions for all DMA API functions can be found from within Dynamic C using the Function Lookup feature from the help menu (Ctrl+H); also, in the Dynamic C Function Reference Man­ual. In this section we will look at some of these functions.

The function DMAalloc() is called to allocate a DMA channel; the function DMAunalloc() is called to release it. The handle returned by DMAalloc() is passed to all the DMA transfer functions (see Section 11.4) and must be passed to DMAunalloc() to release the channel. All eight channels are iden­tical, with the priority between them either fixed or rotating.

The function DMAsetParameters() accepts parameters that set transfer and interrupt priority levels, channel priority, maximum bytes per burst and minimum clocks between bursts. DMAsetParameters() must be called by an application before a DMA channel can be used; however, the channel can be allocated before DMAsetParameters() is called. The DMA parameters set in DMAsetParameters() are global, that is, they apply to all channels.

Some low-level functions are also provided for the DMA controller. These functions use the DMA channel number instead of the handle returned by DMAalloc(). The function DMAhandle2chan() provides a DMA channel number when passed a valid handle.

The low-level functions DMAsetBufDesc() and DMAloadBufDesc() work with a buffer descriptor associated with a DMA channel. A buffer descriptor is a memory structure that controls the DMA opera­tion. It contains a control byte, a byte count for the data, a source address, a destination address and an optional link address. Low-level transfer functions are provided for use with the buffer descriptor func­tions. They are DMAstartAuto() and DMAstartDirect().

Sample programs located in Samples\Rabbit4000\DMA\ illustrate many of the API functions.

11.3 DMA Interrupts

An interrupt may be requested when a DMA channel has completed transferring data. All channels assert this type of interrupt at the same priority level, which can be set to level 1, 2, or 3 with a call to DMAsetParameters(). Whether or not an interrupt is requested at the end of a transfer is determined by flag options in the DMA transfer function. See Section 11.4.4 for more information.

Each channel has its own interrupt vector in the processor’s external interrupt vector table.

11.4 DMA Transfer Information

A DMA transfer is requested when the channel wants the DMA controller to take control of the address and data buses.

11.4.1  DMA Transfer Priority

DMA transfers may be programmed to occur at any priority level (0, 1, 2, or 3). Relative prioritization among the DMA channels is set using one of the following constants:

The DMA transfer priority and the relative prioritization among channels are set in DMAsetParameters().

11.4.2  DMA Transfer Mode

DMA transfers can happen in burst or single-cycle mode. The “chunkiness” parameter passed to the DMA transfer function determines the burst size.

11.4.3  DMA Transfer Functions

There are three types of transfers, with associated transfer functions.

  1. Memory-to-memory transfers. Use DMAmem2mem().

  2. Internal I/O address transfers to or from memory. Use DMAioi2mem() and DMAmem2ioi(), respectively.

  3. External I/O address transfers to or from memory. Use DMAioe2mem() and DMAmem2ioe(), respectively.

11.4.4  DMA Transfer Function Flags

The DMA transfer functions accept the following flags:

11.5 DMA with Ethernet

Use of the Rabbit 4000 Ethernet imposes some restrictions on the global DMA settings. It is recommended that applications make use of the DMA API functions to avoid possibly breaking Ethernet by using DMA settings that are not compatible with the Ethernet restrictions. For example, Ethernet uses DMA channels 6 and 7 and fixed prioritization among the channels. There are also requirements regarding burst size and the minimum time between bursts. If you are using Ethernet and call the function DMAsetParameters() with parameters that are not compatible with the Ethernet restrictions, those parameters will be quietly ignored.