| |||
| Home > Handling Processor Exceptions > Dual-channel DMA transfer | |||
The Example 40 example here
is similar to the Example 39 example,
except that there are two channels being handled. The code is an
FIQ handler. It uses the banked FIQ registers to maintain state
between interrupts. It is best situated at location 0x1C.
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 R11 for
the first port, R12 for the second.
The entire sequence to handle a normal transfer takes nine instructions. Code situated after the conditional return is used to signal that the transfer is complete.
Example 40. FIQ handler
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.