Go Down

Topic: VGA output (Read 24890 times) previous topic - next topic

SVGA Quadrup Two Orbit Fractal :-)

Code: [Select]

/* Quadrup Two Orbit Fractal v1.1 by JLS 2012 */

/* Arduino Due SVGA-Out 800x600 v0.3 by stimmer
http://arduino.cc/forum/index.php/topic,130742.0.html
Please do not attempt to understand this code :-) */

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,#40 \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 90 \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,#0x40DC \n\t"
        //"movt r1,#0x400C \n\t"
        //"str %[bytes],[r1] \n\t"
        "movw r1,#0x40E8 \n\t"
        "movt r1,#0x400C \n\t"
        "movw r0,26 \n\t"
        "movt r0,#0x1203 \n\t"
        "str r0,[r1] \n\t"
        "movw r1,#0x4028 \n\t"
        "movt r1,#0x400C \n\t"
        "mov r0,1<<4 \n\t"
        "str r0,[r1] \n\t"
        "movw r1,#0x0e04 \n\t"
        "movt r1,#0x400e \n\t"
        "mov r0,1<<26 \n\t"
        ".rept 12\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_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;
uint16_t fb[600][52] __attribute__((aligned(256)));

void __attribute__((aligned(64))) PWM_Handler()
{
    long dummy=REG_PWM_ISR1;
                 
    if(line < 600){       
        //byte * p=fb[line];
        doLine(0);
    }     
    if(line==601) digitalWriteDirect(42,1); //or digitalWriteDirect(42,0); to invert vsync
    if(line==605) digitalWriteDirect(42,0); //or digitalWriteDirect(42,1);
   
    line++; if(line == 628){
      REG_DMAC_SADDR4=(uint32_t)fb;
      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=2218;
  REG_PWM_CDTY2=1949;
  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<<4;
  REG_DMAC_DADDR4=(uint32_t)&REG_SPI0_TDR; 
  REG_DMAC_DSCR4=0;
  REG_DMAC_CTRLB4=0x20310000;
  REG_DMAC_CFG4=  0x01412210;
   
  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]=0x00000280;
 
  Serial.begin(9600);
}

inline void putPixel(int x,int y,byte c=1){
  if((x<0)||(x>=800)||(y<0)||(y>=600))return;
  uint16_t mask=1<<((~x)&15);
  if(c) fb[y][x>>4]|= mask;
  else  fb[y][x>>4]&=~mask;
}

inline int getPixel(int x,int y){
  if((x<0)||(x>=800)||(y<0)||(y>=600))return -1;
  uint16_t mask=1<<((~x)&15);
  return (fb[y][x>>4] & mask)?1:0;
}

#define sgn(x) (((x)>0)?1:((x)<0)?-1:0)
void drawLine(int x0, int y0, int x1, int y1,int c){
   int dx=abs(x1-x0), dy=abs(y1-y0),sx=sgn(x1-x0),sy=sgn(y1-y0);
   int err=dx-dy;
   do{ putPixel(x0,y0,c<2?c:!getPixel(x0,y0));
       int e2=2*err;
       if (e2 > -dy){err-=dy;x0+=sx;}
       if (e2 <  dx){err+=dx;y0+=sy;}
   }   while ((x0!=x1)||(y0!=y1));
}

    float a = 34;
    float b = 0.9;
    float c = 5;
    float x = 1;
    float y = 0;
   
    int xx,yy;
   
    int cnt = 0;
    int col = 1;

void loop(){ 
         
    double oldx = x;
    double oldy = y;
   
    x = oldy-(oldx/abs(oldx))*sin(log(abs(b*oldx-c)))*atan(abs((pow(c*oldx-b,2))));
    y = a-oldx;
   
    xx = 285+7*x;
    yy = 210+5.5*y;
   
    if (cnt == 1000) {
col = rand()%2;
cnt = 0; }

    cnt++;
   
    if ((xx>=0)&(xx<=799)&(yy>=0)&(yy<=599)) putPixel(xx,yy,col);
}
http://jlswbs.blogspot.com

#31
Dec 09, 2012, 04:05 pm Last Edit: Dec 10, 2012, 10:05 pm by JLS1 Reason: 1
SVGA New Strange Attractor :-)

Update !

Code: [Select]

/* New Strange Attractor v1.1 by JLS 2012 */

/* Arduino Due SVGA-Out 800x600 v0.3 by stimmer
http://arduino.cc/forum/index.php/topic,130742.0.html
Please do not attempt to understand this code :-) */

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,#40 \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 90 \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,#0x40DC \n\t"
        //"movt r1,#0x400C \n\t"
        //"str %[bytes],[r1] \n\t"
        "movw r1,#0x40E8 \n\t"
        "movt r1,#0x400C \n\t"
        "movw r0,26 \n\t"
        "movt r0,#0x1203 \n\t"
        "str r0,[r1] \n\t"
        "movw r1,#0x4028 \n\t"
        "movt r1,#0x400C \n\t"
        "mov r0,1<<4 \n\t"
        "str r0,[r1] \n\t"
        "movw r1,#0x0e04 \n\t"
        "movt r1,#0x400e \n\t"
        "mov r0,1<<26 \n\t"
        ".rept 12\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_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;
uint16_t fb[600][52] __attribute__((aligned(256)));

void __attribute__((aligned(64))) PWM_Handler()
{
    long dummy=REG_PWM_ISR1;
                 
    if(line < 600){       
        //byte * p=fb[line];
        doLine(0);
    }     
    if(line==601) digitalWriteDirect(42,1); //or digitalWriteDirect(42,0); to invert vsync
    if(line==605) digitalWriteDirect(42,0); //or digitalWriteDirect(42,1);
   
    line++; if(line == 628){
      REG_DMAC_SADDR4=(uint32_t)fb;
      line=0;
    }
}

   float x = 1;
   float y = 1;
   float a,b,c,d;
   
   int xx,yy;
   
void rndval(){
   randomSeed(analogRead(8));
   a = 2+(random(500)/100);
   randomSeed(analogRead(9));
   b = 2+(random(500)/100);
   randomSeed(analogRead(10));
   c = 2+(random(500)/100);
   randomSeed(analogRead(11));
   d = 2+(random(500)/100);
}

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=2218;
  REG_PWM_CDTY2=1949;
  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<<4;
  REG_DMAC_DADDR4=(uint32_t)&REG_SPI0_TDR; 
  REG_DMAC_DSCR4=0;
  REG_DMAC_CTRLB4=0x20310000;
  REG_DMAC_CFG4=  0x01412210;
   
  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]=0x00000280;
}

inline void putPixel(int x,int y,byte c=1){
  if((x<0)||(x>=800)||(y<0)||(y>=600))return;
  uint16_t mask=1<<((~x)&15);
  if(c) fb[y][x>>4]|= mask;
  else  fb[y][x>>4]&=~mask;
}

void cls(){
  for(int bb=0;bb<599;bb++){
  for(int aa=0;aa<799;aa++)putPixel(aa,bb,0);
  }
}

void loop(){
 
    rndval();
    cls();
 
    for (int i=0; i <= 30000; i++){
         
    double oldx = x;
    double oldy = y;
   
    x = sin(-a*oldy)-cos(b*oldx);
    y = sin(c*oldx)-cos(d*oldy);
   
    xx = 400+140*x;
    yy = 300+140*y;
   
    if ((xx>=0)&(xx<=799)&(yy>=0)&(yy<=599)) putPixel(xx,yy,1);
   
    }
}
http://jlswbs.blogspot.com

SVGA Novel 4D chaotic attractor :-)

Code: [Select]

/* Novel 4D Chaotic Attractor v1.0 by JLS 2012 */

/* Arduino Due SVGA-Out 800x600 v0.3 by stimmer
http://arduino.cc/forum/index.php/topic,130742.0.html
Please do not attempt to understand this code :-) */

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,#40 \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 90 \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,#0x40DC \n\t"
        //"movt r1,#0x400C \n\t"
        //"str %[bytes],[r1] \n\t"
        "movw r1,#0x40E8 \n\t"
        "movt r1,#0x400C \n\t"
        "movw r0,26 \n\t"
        "movt r0,#0x1203 \n\t"
        "str r0,[r1] \n\t"
        "movw r1,#0x4028 \n\t"
        "movt r1,#0x400C \n\t"
        "mov r0,1<<4 \n\t"
        "str r0,[r1] \n\t"
        "movw r1,#0x0e04 \n\t"
        "movt r1,#0x400e \n\t"
        "mov r0,1<<26 \n\t"
        ".rept 12\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_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;
uint16_t fb[600][52] __attribute__((aligned(256)));

void __attribute__((aligned(64))) PWM_Handler()
{
    long dummy=REG_PWM_ISR1;
                 
    if(line < 600){       
        //byte * p=fb[line];
        doLine(0);
    }     
    if(line==601) digitalWriteDirect(42,1); //or digitalWriteDirect(42,0); to invert vsync
    if(line==605) digitalWriteDirect(42,0); //or digitalWriteDirect(42,1);
   
    line++; if(line == 628){
      REG_DMAC_SADDR4=(uint32_t)fb;
      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=2218;
  REG_PWM_CDTY2=1949;
  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<<4;
  REG_DMAC_DADDR4=(uint32_t)&REG_SPI0_TDR; 
  REG_DMAC_DSCR4=0;
  REG_DMAC_CTRLB4=0x20310000;
  REG_DMAC_CFG4=  0x01412210;
   
  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]=0x00000280;
}

inline void putPixel(int x,int y,byte c=1){
  if((x<0)||(x>=800)||(y<0)||(y>=600))return;
  uint16_t mask=1<<((~x)&15);
  if(c) fb[y][x>>4]|= mask;
  else  fb[y][x>>4]&=~mask;
}

    float x = 2;
    float y = 1;
    float z = 1;
    float u = 2;
   
    float oldx,oldy,oldz,oldu;

    float dt = 0.0005;

    float a = 10;
    float b = 12;
    float c = 50;
    float d = 2;
    float e = 4;
       
    int xx,yy;
       
    int cnt = 0;
    int col = 1;

void loop(){
 
    oldx = x;
    oldy = y;
    oldz = z;
    oldu = u;
       
       
    x = oldx + dt * (oldy*oldz-a*oldx);
    y = oldy + dt * (b*oldy-oldx*oldz);
    z = oldz + dt * (oldx*oldy-c*oldz+d*oldu);
    u = oldu + dt * (oldx*oldz-e*oldu);
   
    xx = 400+1.5*x;
    yy = 300+1.3*y;
   
     if (cnt == 1000) {
col = rand()%2;
cnt = 0; }

    cnt++;
   
    if ((xx>=0)&(xx<=799)&(yy>=0)&(yy<=599)) putPixel(xx,yy,col);
   
}
http://jlswbs.blogspot.com

stimmer

Thanks for the demos, though I won't be able to try the latest ones for another day or two: I've taken my VGA circuit off the breadboard, in preparation for turning it into a mini-shield :) I've attached an image of my first design below.

After that my intention is to start on a library. I still don't know whether to have colour and 1-bit monochrome as two separate libraries or to just have one big library for everything.
Due VGA library - http://arduino.cc/forum/index.php/topic,150517.0.html

bensom

I played with this a bit, reduced the color screen to 320x200 so it has some memory left for other things, like BASIC. Got to say: love it!

stimmer

Wow, that looks like an amazing project! 8)

Must be 20 years at least since I last saw line numbers  XD
Due VGA library - http://arduino.cc/forum/index.php/topic,150517.0.html

andycat

amazing work people, keep it up - my inner nerd is swooning - i want more details on embedded basic and fractals and vga shields!! ;-D

BKnight760

#37
Jan 24, 2013, 05:17 am Last Edit: Jan 24, 2013, 05:20 am by BKnight760 Reason: 1
I'm working on some code based off stimmer's modified code (320x240x8), but it seems that the Serial communication no longer works after setting up the timers.

In the setup() method, I started the Serial at 9600, and then did println() thoughout the setup() method, and found this block of code causes it to stop working.

What is it about this code that disables the serial output?  

Code: [Select]
 REG_PIOD_OWER= 0xff;
 REG_PMC_PCER0= 1<<27;  
 REG_PIOB_PDR = 1<<25;
 REG_PIOB_ABSR= 1<<25;
 REG_TC0_WPMR = 0x54494D00;
 REG_TC0_CMR0 = 0b00000000000010011100010000000000;
 //  REG_TC0_CMR0 = 0b00000000000001101100010000000000; // this inverts hsync
 REG_TC0_RC0  = 1334;
 REG_TC0_RA0  = 1174;  
 REG_TC0_CCR0 = 0b101;    
 REG_TC0_IER0 = 0b00010000;
 REG_TC0_IDR0 = 0b11101111;
 NVIC_EnableIRQ(TC0_IRQn);



Is there anything we can do to have this still work and have serial communication available?


--edit--

I did some further debug and found that it works all the way up to the point of calling:

Code: [Select]
NVIC_EnableIRQ(TC0_IRQn);

stimmer

(My monitor is broken, so this project is on hiatus  :0 )

Which version of the code are you using? Specifically what is in the interrupt handler code? The interrupt code is (necessarily) quite long, which can cause trouble with other peripherals using interrupts such as serial. However, the later versions of the project will work properly with Serial at 9600, I know because I used it when debugging the code.
Due VGA library - http://arduino.cc/forum/index.php/topic,150517.0.html

bensom

I used the REG_PWM version, that works with serial!

Code: [Select]

void PWM_Handler()
{
  long dummy=REG_PWM_ISR1;
.
.
}
void setupVGA()
{
  pinMode(42,OUTPUT);   pinMode(43,OUTPUT);                     // vsync=42 hsync=43
  pinMode(34,OUTPUT);   pinMode(35,OUTPUT);                     // blue  (35=msb,34=lsb)
  pinMode(36,OUTPUT);   pinMode(37,OUTPUT);   pinMode(38,OUTPUT); // green (38=msb,37,36=lsb)
  pinMode(39,OUTPUT);   pinMode(40,OUTPUT);   pinMode(41,OUTPUT); // red   (41=msb,40,39=lsb)
  REG_PIOC_OWER= 0x3fc;
  REG_PMC_PCER0= 1<<27;

  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);
}




stimmer

I have a new monitor, so this project is restarted  ]:D :D :smiley-mr-green:

I've been working on turning the code into a library, which makes it a lot easier to use. It's about as simple to use as the old TVout library was on the Uno. And I've added some simple text and graphics functions, as well as print library support (so you can use print and println for easy text output). The mini-shield design I posted about above works quite well, but the circuit is simple enough to be built on a breadboard too, just 13 resistors.

I am hoping to make a proper release of the library code in the next week or so. But until then here's a sneak preview of what you can expect.

Code example:
Code: [Select]

#include <VGA.h>

void setup() {
  VGA.begin(320,240,VGA_COLOUR);
}

void loop() { 
  VGA.setInk(random(256));
  VGA.setPaper(random(256));
  VGA.print(" Hello Arduino ");
}


Due VGA library - http://arduino.cc/forum/index.php/topic,150517.0.html

Great info many thanks :-)

Kamil
http://jlswbs.blogspot.com

BKnight760

I reworked my code based off the REG_PWM version and am no longer having issues with the Serial connection.

My code is able to load a bitmap graphic off the SD card, read the bitmap and DIB headers and resize any image to the desired 2D-array size.  It has to down-sample from 24-bit color to 8-bit color, but still looks pretty good with only 256 color choices.

Currently, I'm loading a background image to fit the 320x240x8 framebuffer.

Then I load 2 smaller images to do some bit-blit.  I'm using images that are 24x32 pixels (also down-sized and down-sampled from larger images). 

Code: [Select]
void readBitmap(char* filePath, byte** pictureBuffer,int bufferWidth,int bufferHeight)
{

  SdFile myFile;
  boolean openedFile = myFile.open(filePath,O_RDWR);
  if (openedFile)
  {

    unsigned int FileSize=0;
    unsigned int Offset=0;


    Serial.print("Reading ");
    Serial.print(filePath);
    Serial.println(" bitmap header...");
    //Read Bitmap header
    for (int i=0;i<14;i++)
    {
      byte myByte=myFile.read();
      Serial.print("Byte ");
      Serial.print(i);
      Serial.print(": 0x");
      if (myByte<16)
      {
        //Pad with a leading zero, if needed.
        Serial.print("0");
      }
      Serial.println(myByte,HEX);

      //Bytes 2 through 5 are the file size
      if((i>=2) && (i<=5))
      {
        FileSize=FileSize+(((int)myByte)<<(8*(i-2)));
        Serial.print("FileSize: ");
        Serial.println(FileSize);
      }

      //Bytes 10 through 13 are the offset to the pixel data.
      if((i>=10) && (i<=14))
      {
        Offset=Offset+(((int)myByte)<<(8*(i-10)));
        Serial.print("Offset: ");
        Serial.println(Offset);
      }
    }

    Serial.print("Done reading ");
    Serial.print(filePath);
    Serial.println(" bitmap header.");


    Serial.print("Reading ");
    Serial.print(filePath);
    Serial.println(" DIB header...");

    unsigned int Width=0;
    unsigned int Height=0;
    unsigned int BitsPerPixel=0;
    //Read the DIB header
    for (int i=0;i<40;i++)
    {
      byte myByte=myFile.read();
      Serial.print("Byte ");
      Serial.print(i);
      Serial.print(": 0x");
      if (myByte<16)
      {
        //Pad with a leading zero, if needed.
        Serial.print("0");
      }
      Serial.println(myByte,HEX);


      //Bytes 4 through 7 are bitmap width in pixels
      if((i>=4) && (i<=7))
      {
        Width=Width+(((int)myByte)<<(8*(i-4)));
        Serial.print("Width: ");
        Serial.println(Width);
      }

      //Bytes 8 through 11 are bitmap height in pixels
      if((i>=8) && (i<=11))
      {
        Height=Height+(((int)myByte)<<(8*(i-8)));
        Serial.print("Height: ");
        Serial.println(Height);
      }

      //Bytes 14 through 15 are bitmap bits per pixel
      if((i>=14) && (i<=15))
      {
        BitsPerPixel=BitsPerPixel+(((int)myByte)<<(8*(i-14)));
        Serial.print("BitsPerPixel: ");
        Serial.println(BitsPerPixel);
      }


    }


    int BytesPerPixel=((FileSize-Offset)/Width)/Height;
    Serial.print("BytesPerPixel=");
    Serial.println(BytesPerPixel);


    Serial.print("Done reading ");
    Serial.print(filePath);
    Serial.println(" DIB header...");

    Serial.print("Loading ");
    Serial.print(filePath);
    Serial.println(" bitmap pixels...");
    myFile.seekSet(Offset+1);

    byte buf[Width*BytesPerPixel];

    for(int y=0;y<Height;y++)
    {
      //Serial.print("Loading Row: ");
      //Serial.print(y,DEC);
      //Serial.print(" / ");
      //Serial.println(Height,DEC);

      //Serial.print("Pointer to FB[y][0] = ");
      //Serial.println((int)&FrameBuffer[y][0],HEX);


      //Serial.print("Loading Pixel: ");
      //Serial.print(x,DEC);
      //Serial.print(" / ");
      //Serial.println(Width,DEC);


      //Read the entire row of pixels all at once.
      //This is a major performance upgrade.
      myFile.read(buf,sizeof(buf));

      //Convert the 3-bytes-per-pixel data into 1-byte-per-pixel format.
      for (int x=0;x<Width;x++){
        byte red=buf[x*3];
        byte green=buf[(x*3)+1];
        byte blue=buf[(x*3)+2];


        //Serial.print("Red = ");
        //Serial.println(red);

        byte redBits = (byte)map(red,0,255,0,7);
        //Serial.print("RedBits = ");
        //Serial.println(redBits);
        byte greenBits = (byte)map(green,0,255,0,7);
        byte blueBits = (byte)map(blue,0,255,0,3);

        pictureBuffer[(bufferHeight-1)-(int)(((double)y*(double)bufferHeight)/(double)Height)][(int)(((double)x*(double)bufferWidth)/(double)Width)]=(redBits<<5)+(greenBits<<2)+(blueBits);
      }

      //The Bitmap file format pads every row to a 4-byte (word)
      //boundary.  Calculate the padding, and skip it.
      int BytesInLastWord=((Width*BytesPerPixel)%4);
      int BytesOfPadding=0;
      if (BytesInLastWord>0)
      {
        BytesOfPadding=4-BytesInLastWord;
      }
      //Serial.print("Row should have ");
      //Serial.print(BytesOfPadding);
      //Serial.println(" bytes of padding.");

      for (int i=0;i<BytesOfPadding;i++)
      {
        //Skip the padding byte.
        myFile.read();
      }
    }
    myFile.close(); 

    /*
    for (int y=0;y<Height;y++)
     {
     for (int x=0;x<Width;x++)
     {
     if (FrameBuffer[y][x]<16)
     {
     //Pad the output with a leading zero.
     Serial.print("0");
     }
     Serial.print(FrameBuffer[y][x],HEX);
     Serial.print(",");
     }
     Serial.println();
     }
     */


  }
  else
  {
    Serial.print("Error opening file ");
    Serial.print(filePath);
    Serial.println(" for read.");
  }

  Serial.print("Done loading ");
  Serial.print(filePath);
  Serial.println(" bitmap pixels.");

}//End readBitmap method


I bit-blit the images using the following simple steps:

Code: [Select]
void loop(void) {

  if (millis()-starttime>100)
  {
    //Initialize our timer   
    starttime=millis();


    if (spriteDeployed==true)
    {
      //Erase the sprite by putting the background back.
      for (int y=0;y<32;y++)
      {
        for (int x=0;x<24;x++)
        {
          FrameBuffer[locationY+y][locationX+x]=background[y][x];
        }
      }
      spriteDeployed=false;
    }

    locationX=locationX+random(-5,6);
    if (locationX>320-24)
    {
      locationX=320-24;
    }
    if (locationX<0)
    {
      locationX=0;
    }

    locationY=locationY+random(-5,6);
    if (locationY>240-32)
    {
      locationY=240-32;
    }
    if (locationY<0)
    {
      locationY=0;
    }


    //Get the background for the new location
    for (int y=0;y<32;y++)
    {
      for (int x=0;x<24;x++)
      {
        background[y][x]=FrameBuffer[locationY+y][locationX+x];
      }
    }

    //Put Bit-Blit the sprite on the screen
    for (int y=0;y<32;y++)
    {
      for (int x=0;x<24;x++)
      {
        //The "And" (&=) operation allows for white background to be
        //transparent, and the black object to overwrite the background.
        FrameBuffer[locationY+y][locationX+x]&=Sprite[y][x];
       
        //The "Or" (|=) operation allows the whte background to remain
        //transparent, while overlaying the color object on the black area.
        FrameBuffer[locationY+y][locationX+x]|=SpriteMask[y][x];
      }
    }
    spriteDeployed=true;
  }

}//End loop


This all works, except there's a slight flicker to the display.  It's not bad, but bugs your eyes a little.  The pixels seem to shift slightly left and right as the screen refreshes.  It seems that the h-sync or v-sync timings must be off just slightly every once in a while.  Is that possible with the interrupts?  I'm trying to decide what to do to fix the image stability.  Any thoughts?

stimmer

Basically yes, the shimmering problem was caused by the interrupt not firing with exactly the same period each time, so each line is a random number of ticks late. What the mysterious piece of inline assembler at the start of the interrupt is trying to do is to synchronize the CPU with the timer. But it is not a good solution.

In the VGA library I tried a different solution. It uses two interrupts each line - the first puts the processor to sleep, so then when the second one fires it should be precisely on time. The display is much more steady (in most cases, rock steady). This broke the Serial support, but in the last few days I think I have made a breakthrough and got it working again. The other advantage to the VGA library is that it now uses DMA for the colour mode which is about 4x faster since the processor can continue to execute code while the screen is being displayed, plus the pixels are all the same width :)

Unfortunately I don't have standalone code of this approach as I had already turned the code into a library by then.
Due VGA library - http://arduino.cc/forum/index.php/topic,150517.0.html

Graynomad

@bensom
I see you have some BASIC source code displayed there, does that mean you have a BASIC interpreter running?

Does anybody have plans to port a BASIC interpreter?

______
Rob
Rob Gray aka the GRAYnomad www.robgray.com

Go Up