I have had some success with 640x480 1bpp. This version is using SPI and DMA - this has the advantage that now the CPU can carry on working most of the time while the screen is being drawn. Therefore it is much faster than the 320x240x8bpp code. The downside is that the video output is on the SPI connector (MOSI - middle pin of lower row - look at http://arduino.cc/forum/index.php/topic,132130.0.html if you can't find it). Connect MOSI through a 100R resistor to VGA R,G and B. VSync is on pin 42 and HSync is on pin 43.
There is slight shimmering in this version which I hope to be able to correct. Also the timings are quite a way out (pixel clock is 10% too fast) hopefully most LCDs will be able to stretch the picture enough. If anyone does try it and it does/doesn't work please tell me.
If you make any demos with this please use the putPixel/getPixel functions if they are fast enough, as I might yet change the underlying format of the framebuffer.
/* Arduino Due VGA-Out 640x480 v0.4 by stimmer
http://arduino.cc/forum/index.php/topic,130742.0.html */
int bins[256];
void __attribute__((aligned(64))) doLine(byte *p){
asm volatile (
"isb \n\t"
"dsb \n\t"
"movw r1,#0x4254 \n\t"
"movt r1,#0x4009 \n\t"
"ldr r0,[r1] \n\t"
"subs r0,#35 \n\t"
"lsls r0,r0,#1 \n\t"
"orr r0,#1 \n\t"
"add r0,pc \n\t"
"isb \n\t"
".align 5 \n\t"
"bx r0 \n\t"
".rept 200 \n\t"
"nop \n\t"
".endr \n\t"
//this is debugging code, but because the timimg is so sensitive I have to leave it in
"ldr r0,[r1] \n\t"
"subs r0,#128 \n\t"
"ldr r2,[%[bins],r0,lsl #2] \n\t"
"adds r2,#1 \n\t"
"str r2,[%[bins],r0,lsl #2] \n\t"
"movw r1,#0x4104 \n\t"
"movt r1,#0x400C \n\t"
"str %[bytes],[r1] \n\t"
"movw r1,#0x4110 \n\t"
"movt r1,#0x400C \n\t"
"movw r0,80 \n\t"
"movt r0,#0x0000 \n\t"
"str r0,[r1] \n\t"
"movw r1,#0x4028 \n\t"
"movt r1,#0x400C \n\t"
"mov r0,1<<5 \n\t"
"str r0,[r1] \n\t"
"movw r1,#0x0e04 \n\t"
"movt r1,#0x400e \n\t"
"mov r0,1<<26 \n\t"
".rept 26\n\t nop\n\t .endr\n\t"
"str r0,[r1] \n\t"
:[bytes]"+r"(p)
:[bins]"r"(bins)
:"r0","r1","r2"
);
}
void __attribute__((aligned(64))) DMAC_Handler()
{
REG_SPI0_TDR=0;
asm volatile("nop\n\t nop\n\t nop\n\t");
REG_PIOA_PER = 1<<26;
uint32_t dummy=REG_DMAC_EBCISR;
}
inline void digitalWriteDirect(int pin, boolean val){
if(val) g_APinDescription[pin].pPort -> PIO_SODR = g_APinDescription[pin].ulPin;
else g_APinDescription[pin].pPort -> PIO_CODR = g_APinDescription[pin].ulPin;
}
volatile short line;
byte fb[480][80] __attribute__((aligned(256)));
void __attribute__((aligned(64))) PWM_Handler()
{
long dummy=REG_PWM_ISR1;
if(line < 480){
byte * p=fb[line];
doLine(p);
}
if(line==490) digitalWriteDirect(42,1); //or digitalWriteDirect(42,0); to invert vsync
if(line==492) digitalWriteDirect(42,0); //or digitalWriteDirect(42,1);
line++; if(line == 525){
line=0;
}
}
void setup(){
pinMode(42,OUTPUT); pinMode(43,OUTPUT); // vsync=42 hsync=43
// video output is on SPI MOSI pin (bottom middle on SAM3 3x2 SPI connector)
REG_PIOA_PDR =1<<20;
REG_PIOA_ABSR|=1<<20;
REG_PMC_PCER1= 1<<4;
REG_PWM_WPCR= 0x50574dfc;
REG_PWM_CLK= 0x00010001;
REG_PWM_DIS= 1<<2;
REG_PWM_CMR2=0x0; // REG_PWM_CMR2=0x200; //to invert hsync polarity
REG_PWM_CPRD2=2668;
REG_PWM_CDTY2=2348;
REG_PWM_SCM=0;
REG_PWM_IER1=1<<2;
REG_PWM_ENA= 1<<2;
NVIC_EnableIRQ(PWM_IRQn);
REG_PMC_PCER1= 1<<7;
REG_DMAC_WPMR=DMAC_WPMR_WPKEY(0x444d4143);
REG_DMAC_EN=1;
REG_DMAC_GCFG=0x00;
REG_DMAC_EBCIER=1<<5;
REG_DMAC_DADDR5=(uint32_t)®_SPI0_TDR;
REG_DMAC_DSCR5=0;
REG_DMAC_CTRLB5=0x20310000;
REG_DMAC_CFG5= 0x21012210;
NVIC_EnableIRQ(DMAC_IRQn);
REG_PIOA_PDR = (1<<25)|(1<<27)|(1<<28);
REG_PIOA_PER = 1<<26;
REG_PIOA_ABSR&=~((1<<25)|(1<<27)|(1<<28));
REG_PMC_PCER0= 1<<24;
REG_SPI0_WPMR=0x53504900;
REG_SPI0_CR=0x1;
REG_SPI0_MR=0x00000011;
SPI0->SPI_CSR[0]=0x00000300;
}
inline void putPixel(int x,int y,byte c=1){
if((x<0)||(x>=640)||(y<0)||(y>=480))return;
byte mask=1<<((~x)&7);
if(c) fb[y][x>>3]|= mask;
else fb[y][x>>3]&=~mask;
}
inline int getPixel(int x,int y){
if((x<0)||(x>=640)||(y<0)||(y>=480))return -1;
byte mask=1<<((~x)&7);
return (fb[y][x>>3] & mask)?1:0;
}
inline void clearBuffer(byte c=0){
memset(fb,c?255:0,sizeof(fb));
}
void loop(){
float c[3][2]={{random(640),random(480)},{random(640),random(480)},{random(640),random(480)}};
static int j=1;
if(random(10)==0){clearBuffer(j);j=1-j;}
for(int x=0;x<640;x+=2){putPixel(x,0);putPixel(x,479);}
for(int y=0;y<480;y+=2){putPixel(0,y);putPixel(639,y);}
float x=c[0][0],y=c[0][1];
for(int t=0;t<40000;t++){
int i=random(0,3);
x=(x+c[i][0])/2;
y=(y+c[i][1])/2;
putPixel(x,y,j);
}
}