Dual-channel DMA transfer
An FIQ handler for two channels uses a sequence of nine instructions to handle a normal data transfer.
The example shown below handles two channels. The code is an FIQ handler. It uses the
banked FIQ registers to maintain state between interrupts. It is best situated at location
In the example code:
Points to the base address of the I/O device from which data is read.
Is the offset from the base address to a register indicating which of two ports caused the interrupt.
Is a bit mask indicating if the first port caused the interrupt. Otherwise it is assumed that the second port caused the interrupt.
Are offsets to the two data registers to be read. Reading a data register clears the interrupt for the corresponding port.
Points to the memory location to which data from the first port is being transferred.
Points to the memory location to which data from the second port is being transferred.
Point to the last address to transfer to. This is
R11for the first port,
R12for the second.
The entire sequence to handle a normal transfer takes nine instructions. Insert code after the conditional return to signal that the transfer is complete.
LDR sp, [R8, #IOStat] ; Load status register to find which ; port caused the interrupt. TST sp, #IOPort1Active LDREQ sp, [R8, #IOPort1] ; Load port 1 data. LDRNE sp, [R8, #IOPort2] ; Load port 2 data. STREQ sp, [R9], #4 ; Store to buffer 1. STRNE sp, [R10], #4 ; Store to buffer 2. CMP R9, R11 ; Reached the end? CMPLE R10, R12 ; On either channel? SUBSNE pc, lr, #4 ; Return ; Insert transfer complete code here.
Byte transfers can be made by replacing the load instructions with load byte instructions. Transfers from memory to an I/O device are made by swapping the addressing modes between the conditional load instructions and the conditional store instructions.