This section explains how to set up HSDMA, using an example program that transfers data to PWM (16-bit timer) for audio output.
●
DMA transfer to 16-bit timer
The example program shown below uses HSDMA channel 3 and 16-bit timer 5 as a trigger to transfer data from RAM to 16-bit timer 1.
Initial settings
|
;; PWM output timer
#define PRESC16_1 0x40148 ; 16bit Timer 1, Prescaler
#define TMCTRL16_1 0x4818e ; 16bit Timer 1
#define COMPARE_A16_1 0x48188
#define COMPARE_B16_1 0x4818a
#define TIMER16_1_IMASK 0x40272
#define P2_FUNCTION_SELECT 0x402d8 ; Function select output port
;; trigger timer
#define SPK_INTR_LEVEL_0 0x04
#define PRESC16_5 0x4014c ; 16bit Timer 5, Prescaler
#define TMCTRL16_5 0x481ae ; 16bit Timer 5
#define COMPARE_A16_5 0x481a8
#define COMPARE_B16_5 0x481aa
#define TIMER16_5_IMASK 0x40274
#define TIMER16_5_IFLAG 0x40284
#define TIMER16_5_ILEVEL 0x40268 ; Upper 4-bits
;; HSDMA
#define HSDMA_IMASK 0x40271
#define HSDMA_IFLAG 0x40281
#define HSDMA3_IFLAG_CLR 0x08
#define HSDMA_01_ILEVEL 0x40263
#define HSDMA_23_ILEVEL 0x40264
#define HSDMA_23_TRIGGER 0x40299
#define HSDMA3_ENABLE 0x4825c
#define HSDMA3_TFLAG 0x4825e
#define HSDMA3_TRANSFER 0x48250
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
#define PRESC16_3 0x0004014a ; 16bit Timer 3, Prescaler
#define TMCTRL16_3 0x0004819e ; 16bit Timer 3
#define COMPARE_A16_3 0x00048198
#define COMPARE_B16_3 0x0004819a
#define TIMER16_3_IMASK 0x00040273
#define TIMER16_3_IFLAG 0x00040283
#define TIMER16_3_ILEVEL 0x00040267 ; Upper 4-bits |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; void SpkOpen_0(BYTE *SpkParams, int ReloadValue)
;;; dose not destroy r12 - r15
;;;
SpkOpen_0:
; init HSDMA triger timer
ld.w %r5,0x00 (1)
xld.b [TMCTRL16_5],%r5 ; Timer Stop xld.b [PRESC16_5],%r5 ; Prescaler Stop xld.w %r4,TIMER16_5_IMASK
bclr [%r4],7 ; disable comparison A intr.
bclr [%r4],6 ; disable comparison B intr.
xld.w %r5,0xf0
xld.b [TIMER16_5_IFLAG],%r5 ; clear comparison A B factor flags xld.h [COMPARE_B16_5],%r13 ; set compare B value (ReloadValue)
; init HSDMA
ld.w %r5,0 (2)
xld.h [HSDMA3_ENABLE],%r5 ; HSDMA Ch3 disable (stop) ld.w %r5,HSDMA3_IFLAG_CLR
xld.b [HSDMA_IFLAG],%r5 ; clear DMA Ch3 interrupt flag clear xbset [HSDMA_IMASK],3 ; enable DMA Ch3 end interrupt xld.w %r4,HSDMA_23_ILEVEL
ld.b %r5,[%r4]
and %r5,0x0f ; mask lower 4bit
ld.w %r6,0x4 ; HSDMA Ch3 interrupt level = 4 sll %r6,0x04 ; level is upper 4bit
or %r5,%r6
ld.b [%r4],%r5 ; set interrupt level
ld.w %r5,8 (3)
sll %r5,4
xld.b [HSDMA_23_TRIGGER],%r5 ; HSDMA trigger is 16bit timer ; Ch.5 compare B
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; int SpkNext(BYTE *SpkParams)
;;; interrupt routine
;;; dose not destroy r9,r10 r12 - r15
;;; In DMA version, change to control register
;;; r9 : (*Length)
;;; r10 : Length
;;; r12 : SpkParams
;;;
SpkNext:
xcall QueueRead ; QueueRead dose not destroy r12 - r15 cmp %r10,0x00 ; r9:*Length, r10:Length, r11:*Buffer jreq RetSpkNext ; if (Failed) QueueEmpty
| ; Write HSDMA register
xld.w %r4,HSDMA3_TRANSFER ; start of dma transfer register (4) ld.w %r6,%r10
xoor %r6,%r6,0x80000000
ld.w [%r4]+,%r6 ; Length and address mode dual ld.w %r7,%r11 ; source address (buffer pointer) xoor %r7,%r7,0x70000000 ; addr increment, harf word transfer ld.w [%r4]+,%r7 ; for 10bit PWM
xld.w %r8,COMPARE_A16_1 ; 16bit timer compareA register ld.w [%r4]+,%r8 ; dest address, single
; Enable HSDMA ld.w %r5,1
ld.h [%r4],%r5 ; HSDMA enable (start) HSDMA3_ENABLE RetSpkNext:
ret
(1) Initializing the HSDMA triggering timer
In this example, 16-bit timer 5 is used as a trigger for HSDMA. Temporarily suspend timer 5 operations and turn off the prescaler clock output for timer 5.
; init HSDMA triger timer ld.w %r5,0x00
xld.b [TMCTRL16_5],%r5 ; Timer Stop xld.b [PRESC16_5],%r5 ; Prescaler Stop
With the interrupt controller, disable the timer 5 interrupt and clear the interrupt factor flag.
xld.w %r4,TIMER16_5_IMASK
bclr [%r4],7 ; disable comparison A intr.
bclr [%r4],6 ; disable comparison B intr.
xld.w %r5,0xf0
xld.b [TIMER16_5_IFLAG],%r5 ; clear comparison A B factor flags
Set the HSDMA cycle data (e.g. 8k times per second) passed via R13 from the calling routine in the compare B register.
xld.h [COMPARE_B16_5],%r13 ; set compare B value (ReloadValue) (2) Initializing HSDMA interrupt
Always confirm that HSDMA is disabled before setting HSDMA. If set while operating, the register may be read or written to incorrectly.
; init HSDMA ld.w %r5,0
xld.h [HSDMA3_ENABLE],%r5 ; HSDMA Ch3 disable (stop)
With the interrupt controller, clear the the HSDMA channel 3 interrupt factor flag and enable the interrupt.
ld.w %r5,HSDMA3_IFLAG_CLR
xld.b [HSDMA_IFLAG],%r5 ; clear DMA Ch3 interrupt flag clear xbset [HSDMA_IMASK],3 ; enable DMA Ch3 end interrupt Set the interrupt level to 4.
xld.w %r4,HSDMA_23_ILEVEL ld.b %r5,[%r4]
and %r5,0x0f ; mask lower 4bit
ld.w %r6,0x4 ; HSDMA Ch3 interrupt level = 4 sll %r6,0x04 ; level is upper 4bit
or %r5,%r6
ld.b [%r4],%r5 ; set interrupt level (3) Setting HSDMA trigger
Set 16-bit timer 5 for the HSDMA channel 3 trigger.
ld.w %r5,8 sll %r5,4
xld.b [HSDMA_23_TRIGGER],%r5 ; HSDMA trigger is 16bit timer ; Ch.5 compare B
(4) Setting HSDMA transfer conditions
Set the DMA transfer count (data count) passed via R10 from the calling routine. Set transfer mode to dual-address transfer.
; Write HSDMA register
xld.w %r4,HSDMA3_TRANSFER ; start of dma transfer register ld.w %r6,%r10
xoor %r6,%r6,0x80000000
ld.w [%r4]+,%r6 ; Length and address mode dual
Set the transfer source address, increment mode, and 16-bit data size. The transfer source address is the start address of the buffer (RAM) in which PWM data has been prepared.
ld.w %r7,%r11 ; source address (buffer pointer) xoor %r7,%r7,0x70000000 ; addr increment, harf word transfer ld.w [%r4]+,%r7 ; for 10bit PWM
Set the compare A register for PWM 16-bit timer as the transfer destination. Select single transfer mode, in which one data unit is transferred by one DMA operation.
xld.w %r8,COMPARE_A16_1 ; 16bit timer compareA register ld.w [%r4]+,%r8 ; dest address, single
Enable HSDMA.
; Enable HSDMA ld.w %r5,1
ld.h [%r4],%r5 ; HSDMA enable (start) HSDMA3_ENABLE
DMA transfer is now executed as many times as set at the frequency of the compare B cycle set in 16-bit timer 5.
Interrupt processing at the end of DMA transfer
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; SpkIntr0
;;; HSDMA transfer end interrupt
;;;
SpkIntr0:
pushn %r15 (1)
ld.w %r0,%ahr ld.w %r1,%alr pushn %r1
xld.w %r12,SPK_PARAMS_0 ; SpkParams
xld.w %r13,HSDMA_IFLAG ; IFlagReg (2) xld.w %r14,HSDMA3_IFLAG_CLR ; IFlag clear data
ld.b [%r13],%r14 ; clear DMA Ch3 interrupt flag ld.w %r15,[%sp+0x12] ; OldPSR (3) xcall QueueNext
popn %r1 (1)
ld.w %alr,%r1 ld.w %ahr,%r0 popn %r15 reti
Register the start address (SpkIntr0) of this handling routine as the vector for HSDMA channel 3.
Process the interrupt generated each time a number of HSDMA transfers set is completed.
(1) Saving and restoring registers
At the beginning and end of interrupt processing, save and restore all of R0–R15, AHR and ALR.
pushn %r15 ld.w %r0,%ahr ld.w %r1,%alr pushn %r1 | popn %r1 ld.w %alr,%r1 ld.w %ahr,%r0 popn %r15 reti
(2) Resetting the interrupt factor flag Clear the interrupt factor flag.
xld.w %r13,HSDMA_IFLAG ; IFlagReg
xld.w %r14,HSDMA3_IFLAG_CLR ; IFlag clear data
ld.b [%r13],%r14 ; clear DMA Ch3 interrupt flag clear (3) Processing for the subsequent transfer
Disable HSDMA and restore transfer conditions before starting the next data transfer.
ld.w %r15,[%sp+0x12] ; OldPSR xcall QueueNext