Difference between revisions of "Non-blocking DMA"

From WikiPrizm
Jump to navigationJump to search
(Refactor into stripe function. Spell check on comments.)
 
Line 2: Line 2:
 
It is based on an assembly function found in Simon's documentation. I rewrote it in C.
 
It is based on an assembly function found in Simon's documentation. I rewrote it in C.
 
  <nowiki>
 
  <nowiki>
#define LCD_GRAM 0x202
+
#include <fxcg/display.h>
 +
#define LCD_GRAM 0x202
 
#define LCD_BASE 0xB4000000
 
#define LCD_BASE 0xB4000000
#define VRAM_ADDR 0xA8000000
+
#define VRAM_ADDR 0xA8000000
 
#define SYNCO() __asm__ volatile("SYNCO\n\t":::"memory");
 
#define SYNCO() __asm__ volatile("SYNCO\n\t":::"memory");
 
// Module Stop Register 0
 
// Module Stop Register 0
#define MSTPCR0 (volatile unsigned *)0xA4150030
+
#define MSTPCR0 (volatile unsigned*)0xA4150030
 
// DMA0 operation register
 
// DMA0 operation register
 
#define DMA0_DMAOR (volatile unsigned short*)0xFE008060
 
#define DMA0_DMAOR (volatile unsigned short*)0xFE008060
#define DMA0_SAR_0 (volatile unsigned *)0xFE008020
+
#define DMA0_SAR_0 (volatile unsigned*)0xFE008020
#define DMA0_DAR_0 (volatile unsigned *)0xFE008024
+
#define DMA0_DAR_0 (volatile unsigned*)0xFE008024
#define DMA0_TCR_0 (volatile unsigned *)0xFE008028
+
#define DMA0_TCR_0 (volatile unsigned*)0xFE008028
#define DMA0_CHCR_0 (volatile unsigned *)0xFE00802C
+
#define DMA0_CHCR_0 (volatile unsigned*)0xFE00802C
 
void DmaWaitNext(void){
 
void DmaWaitNext(void){
 
while(1){
 
while(1){
if((*DMA0_DMAOR)&4)//Address error has occured stop looping
+
if((*DMA0_DMAOR)&4)//Address error has occurred stop looping
 
break;
 
break;
 
if((*DMA0_CHCR_0)&2)//Transfer is done
 
if((*DMA0_CHCR_0)&2)//Transfer is done
Line 25: Line 26:
 
*DMA0_DMAOR=0;
 
*DMA0_DMAOR=0;
 
}
 
}
 
+
void DoDMAlcdNonblockStrip(unsigned y1,unsigned y2){
void DoDMAlcdNonblock(void){
 
 
Bdisp_WriteDDRegister3_bit7(1);
 
Bdisp_WriteDDRegister3_bit7(1);
Bdisp_DefineDMARange(6,389,0,215);
+
Bdisp_DefineDMARange(6,389,y1,y2);
 
Bdisp_DDRegisterSelect(LCD_GRAM);
 
Bdisp_DDRegisterSelect(LCD_GRAM);
  
Line 34: Line 34:
 
*DMA0_CHCR_0&=~1;//Disable DMA on channel 0
 
*DMA0_CHCR_0&=~1;//Disable DMA on channel 0
 
*DMA0_DMAOR=0;//Disable all DMA
 
*DMA0_DMAOR=0;//Disable all DMA
*DMA0_SAR_0=VRAM_ADDR&0x1FFFFFFF;//Source address is VRAM
+
*DMA0_SAR_0=(VRAM_ADDR+(y1*384*2))&0x1FFFFFFF;//Source address is VRAM
*DMA0_DAR_0=LCD_BASE&0x1FFFFFFF;//Desination is LCD
+
*DMA0_DAR_0=LCD_BASE&0x1FFFFFFF;//Destination is LCD
*DMA0_TCR_0=(216*384)/16;//Transfer count bytes/32
+
*DMA0_TCR_0=((y2-y1+1)*384)/16;//Transfer count bytes/32
 
*DMA0_CHCR_0=0x00101400;
 
*DMA0_CHCR_0=0x00101400;
 
*DMA0_DMAOR|=1;//Enable DMA on all channels
 
*DMA0_DMAOR|=1;//Enable DMA on all channels
 
*DMA0_DMAOR&=~6;//Clear flags
 
*DMA0_DMAOR&=~6;//Clear flags
 
*DMA0_CHCR_0|=1;//Enable channel0 DMA
 
*DMA0_CHCR_0|=1;//Enable channel0 DMA
 +
}
 +
void DoDMAlcdNonblock(void){
 +
DoDMAlcdNonblockStrip(0,215);
 
}
 
}
 
</nowiki>
 
</nowiki>

Latest revision as of 14:49, 7 December 2014

This function allows you to perform calculations while drawing to the screen. This should increase frame rate, for certain applications. It is based on an assembly function found in Simon's documentation. I rewrote it in C.

#include <fxcg/display.h>
#define LCD_GRAM	0x202
#define LCD_BASE	0xB4000000
#define VRAM_ADDR	0xA8000000
#define SYNCO() __asm__ volatile("SYNCO\n\t":::"memory");
// Module Stop Register 0
#define MSTPCR0		(volatile unsigned*)0xA4150030
// DMA0 operation register
#define DMA0_DMAOR	(volatile unsigned short*)0xFE008060
#define DMA0_SAR_0	(volatile unsigned*)0xFE008020
#define DMA0_DAR_0	(volatile unsigned*)0xFE008024
#define DMA0_TCR_0	(volatile unsigned*)0xFE008028
#define DMA0_CHCR_0	(volatile unsigned*)0xFE00802C
void DmaWaitNext(void){
	while(1){
		if((*DMA0_DMAOR)&4)//Address error has occurred stop looping
			break;
		if((*DMA0_CHCR_0)&2)//Transfer is done
			break;
	}
	SYNCO();
	*DMA0_CHCR_0&=~1;
	*DMA0_DMAOR=0;
}
void DoDMAlcdNonblockStrip(unsigned y1,unsigned y2){
	Bdisp_WriteDDRegister3_bit7(1);
	Bdisp_DefineDMARange(6,389,y1,y2);
	Bdisp_DDRegisterSelect(LCD_GRAM);

	*MSTPCR0&=~(1<<21);//Clear bit 21
	*DMA0_CHCR_0&=~1;//Disable DMA on channel 0
	*DMA0_DMAOR=0;//Disable all DMA
	*DMA0_SAR_0=(VRAM_ADDR+(y1*384*2))&0x1FFFFFFF;//Source address is VRAM
	*DMA0_DAR_0=LCD_BASE&0x1FFFFFFF;//Destination is LCD
	*DMA0_TCR_0=((y2-y1+1)*384)/16;//Transfer count bytes/32
	*DMA0_CHCR_0=0x00101400;
	*DMA0_DMAOR|=1;//Enable DMA on all channels
	*DMA0_DMAOR&=~6;//Clear flags
	*DMA0_CHCR_0|=1;//Enable channel0 DMA
}
void DoDMAlcdNonblock(void){
	DoDMAlcdNonblockStrip(0,215);
}

As you can see, there are two functions. Call DoDMAlcdNonblock() to start a transfer and DmaWaitNext() before doing another transfer.