Author Topic: Peripheral DMA  (Read 12959 times)

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3238
    • View Profile
    • uTasker
Peripheral DMA
« on: December 24, 2007, 05:28:13 PM »
Hi All

Before releasing a new service pack for the SAM7X (which is in the last stage of preporation) I have decided to add some support for the peripheral DMA controller.

This is in the form of DMA support for the serial interfaces (USARTs). Below is a report on the peripheral DMA controller as found in the SAM7X and some details about the USART DMA driver integration.




Peripheral DMA Controller

The AT91SAM7X has 17 peripheral DMA channels. Each channel is defined for use by a certain transfer direction of a certain serial peripheral device. This means that all serial peripheral devices have the capability of using DMA rather than interrupt or polling operation without restrictions to the number of general purpose DMA channels allocated to such peripherals.

The DMA transfers are always between a serial peripheral device and memory, whereas the memory could be internal or external memory (if the device were to support external memory).

The AT91SAM7X does not support DMA transfer between two memory locations, as is used to optimise data moves in some systems (eg. uMemcpy with DMA support).

The control registers for the DMA channel belonging to the peripheral are always positioned at an offset of 0x100 from the start of the peripheral control block. A counter value enables a block transfer of up to 64k bytes to take place. A next counter value then allows a follow on transfer to already be prepared while the present transfer is still in operation. When a transfer completes it is possible to program it to generate a peripheral interrupt.


A useful application of DMA is when sending blocks of data to the serial interface. Rather than having to handle an interrupt for each character sent, only one interrupt is required to signal that a complete block was sent. The block can be up to 64k in size (assuming there is enough data memory to prepare such a block prior to transmission.

This support has been added to the V1.3 SP2 version of the uTasker for the SAM7X. To activate the DMA support, the define SERIAL_SUPPORT_DMA needs to be activated (app_hw_sam7x.h). Although the code is then available, the use of DMA transfer is still selected on a per-interface basis. The following additional configuration activates the mode when a USART is configured:

    tInterfaceParameters.ucDMAConfig = UART_TX_DMA;  // activate DMA on transmission

A value of 0 should be set if the DMA option is not to be used.

The internal operation of the peripheral DMA is based on two flags in the USART status register. The first flag, TXRDY, signals that the transmitter can accept a transmit character – this flag is used in character interrupt mode to cause an interrupt to be generated in order to load the next character. Since the flag is usually set – it is only 0 while there is actually a character transmission in progress – the interrupt is thus only enabled when character transmission is actually in progress. When performing transmission with peripheral DMA support this interrupt is never enabled – the flag is however used by the peripheral DMA controller to cause the next DMA transfer to take pace (when the DMA transfer count is not 0).

The second flag is not usually used when operating in character interrupt mode but signals that the DMA transfer has terminated in DMA mode. This flag is the ENDTX flag and is set whenever the DMA transfer count is 0, which is also the case when no actual transmission is in progress. Therefore the interrupt is only enabled when a block transmission is really taking place.

A block transfer is therefore configured by setting the DMA transmit pointer to the start of the block in data memory and then the DMA transfer count to the length of the data. Since the TXRDY flag is generally already set, the first data transfer starts immediately. On each transfer (controlled by the TXRDY flag after each character transmission) the DMA count value is decremented until it finally reaches 0 (after the last character in the block has been transferred to the USART transmit register). The ENDTX interrupt is called which is used to either initiate further block transfers of else terminate the sequence (in this case it disables further ENDTX interrupts since the ENDTX flag will remain active).

This solution results in a simple and compatible interface for the uTasker serial driver. The “next DMA” capability was not used since its benefits are negligible in comparison to its additional complication and the otherwise interface incompatibility.


Generally, DMA for USART reception is not as useful as for transmission. The transmission case can be activated without any implications for the application since the interface and its operation are effectively identical. The advantage is in the DMA driver efficiency since it avoids interrupt handling of each character.

Receive DMA operation requires programming the length of receive data blocks, whereas a block size of 1 will give no improvements over character interrupt mode. Larger block sizes will however result in improved character reception performance but the data will only be available once the complete block size has been received or else a timeout has occurred. Although the SAM7X USART implementation supports hardware timeouts, the solution is not generically compatible and so is generally avoided. Rx DMA operation is thus not very suited to applications which receive occasional single characters (eg. the input from a keyboard) and also has problems with XON/XOFF operation since such sequences are also queued by hardware in the input buffer before a complete DMA block size has been received.

Receive DMA is however useful when the serial protocol operates using frames of fixed sizes, resulting in an optimal efficiency due to the fact that there is only one interrupt when the complete frame has been received. The uTasker serial driver supports this mode of operation and the USART RX DMA can be defined to operate as follows:

    tInterfaceParameters.ucDMAConfig = (UART_RX_DMA | UART_RX_DMA_HALF_BUFFER);

This will set up each receive block to received a length equal to half of the receive buffer length. The receive buffer length should thus be defined to be twice the frame length. Each time the frame length has been received to the input buffer, the driver will wake the owner application task, which can then read the contents. In the meantime the second half of the buffer is being used for reception of the next frame so that there are generally no critical time requirements for the application to read the first frame buffer.

The reception DMA process is analogue to the transmission process. Instead of using the RXRDY flag, which is used in character interrupt mode to signal each arrived character, this is used by the peripheral DMA controller to initiate each DMA transfer. While the DMA block transfer is still in progress the ENDRX flag is 0. As soon as the DMA transfer count reaches 0, when the last character in the rx block has been written by DMA to the receive buffer, the ENDRX flag is set and its interrupt is used to update the receive buffer details and signal that the application can retrieve the received data from the input buffer.

The uTasker simulator has also be updated to handle the USART transmit and receive operation in DMA mode so that the operation can be comfortably tested on the PC.