Non-blocking DMA

From WikiPrizm
Revision as of 02:43, 21 April 2021 by ProgrammerNerd (talk | contribs)
Jump to navigationJump to search

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){
		if((*DMA0_DMAOR)&4)//Address error has occurred stop looping
		if((*DMA0_CHCR_0)&2)//Transfer is done
void DoDMAlcdNonblockStrip(unsigned y1,unsigned y2){

	*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_DMAOR|=1;//Enable DMA on all channels
	*DMA0_DMAOR&=~6;//Clear flags
	*DMA0_CHCR_0|=1;//Enable channel0 DMA
void DoDMAlcdNonblock(void){

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

Note that as a caveat DMA access is shared with the CPU. For more information see: