Pages: [1] 2 3 4   Go Down
Author Topic: VGA output  (Read 22905 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
God Member
*****
Karma: 32
Posts: 507
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

After working out how to do a timer interrupt I've had a go at making a VGA framebuffer. It is rather low-res at present(160x240) and fuzzy but I hope to be able to improve that. It has 8-bit colour (RRRGGGBB).

I cannot get Eagle to run right now so will have to describe the schematic in text:
Due pin 2 -> VGA pin 13 (HSync)
Due pin 3 -> VGA pin 14 (VSync)

Due pin 25 -> 820R resistor -> VGA pin 3 (blue)
Due pin 26 -> 390R resistor -> VGA pin 3 (blue)

Due pin 27 -> 2k2 resistor -> VGA pin 2 (green)
Due pin 28 -> 1k resistor -> VGA pin 2 (green)
Due pin 14 -> 470R resistor -> VGA pin 2 (green)

Due pin 15 -> 2k2 resistor -> VGA pin 1 (red)
Due pin 29 -> 1k resistor -> VGA pin 1 (red)
Due pin 11 -> 470R resistor -> VGA pin 1(red)

Due pin GND -> VGA pins 5,6,7,8,10

Code:
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[240][160];

void TC0_Handler()
{
    long dummy=REG_TC0_SR0;
                           
    if(line < 480){
        int i,j=line>>1;
        for(i=0;i<160;i++) REG_PIOD_ODSR = fb[j][i];
        REG_PIOD_ODSR = 0;
    }     
    if(line==490) digitalWriteDirect(3,1);
    if(line==492) digitalWriteDirect(3,0);
   
    line++; if(line == 525) line=0;
}

void setup(){
  for(int i=0;i<160;i++)for(int j=0;j<240;j++)fb[j][i]=j+i;
 
  pinMode(3,OUTPUT);  pinMode(2,OUTPUT);                      // vsync=3 hsync=2
  pinMode(25,OUTPUT); pinMode(26,OUTPUT);                     // blue  (26=msb,25=lsb)
  pinMode(27,OUTPUT); pinMode(28,OUTPUT); pinMode(14,OUTPUT); // green (14=msb,28,27=lsb)
  pinMode(15,OUTPUT); pinMode(29,OUTPUT); pinMode(11,OUTPUT); // red   (11=msb,29,15=lsb)

  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_RC0  = 1334;
  REG_TC0_RA0  = 1174; 
  REG_TC0_CCR0 = 0b101;   
  REG_TC0_IER0 = 0b00010000;
  REG_TC0_IDR0 = 0b11101111;
  NVIC_EnableIRQ(TC0_IRQn);
}

#include <complex>
using namespace std;

const byte cmap[]={0b00000000,0b11100000,0b11100100,0b11101000,0b11101100,0b11110000,0b11110100,0b11111000,0b11111100,
                   0b11011100,0b10111100,0b10011100,0b01111100,0b01011100,0b00111100,0b00011100,0b00011101,0b00011110,
                   0b00011111,0b00011011,0b00010111,0b00010011,0b00001111,0b00001011,0b00000111,0b00000011,0b00100011,
                   0b01000011,0b01100011,0b10000011,0b10100011,0b11000011,0b11100011,0b11100010,0b11100001,0b11100000,0b00000000};
void loop(){
  for(int i=0;i<160;i++){
    for(int j=0;j<240;j++){     
      complex<float> z(0,0),c(i/320.0,(j+240.0)/640.0);
      int n;
      for(n=1;n<sizeof(cmap);n++){
        z=z*z+c;
        if(norm(z)>4.0)break;
      }
      fb[j][i]=cmap[sizeof(cmap)-n];
    }
  }
  for(;;);
}


* vgaout.jpg (126.83 KB, 640x603 - viewed 282 times.)
Logged


Offline Offline
God Member
*****
Karma: 32
Posts: 507
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I unrolled a loop and now it is 320x240 smiley-cool The resolution could go higher but 320x240x8 is 77Kbytes of RAM already.

Code:
/* Arduino Due VGA-Out v0.2 by stimmer
http://arduino.cc/forum/index.php/topic,130742.0.html */

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[240][320];

#define do20(x) x x x x x x x x x x x x x x x x x x x x
#define do80(x)  do20(x) do20(x) do20(x) do20(x)
#define do320(x) do80(x) do80(x) do80(x) do80(x)
#define MNOP(x) asm volatile (" .rept " #x "\n\t nop \n\t .endr \n\t")

void TC0_Handler()
{
    long dummy=REG_TC0_SR0;
                          
    if(line < 480){        
        byte * p=fb[line>>1];
        MNOP(160);
        do320(REG_PIOD_ODSR = *p++;MNOP(2);)
        REG_PIOD_ODSR = 0;
    }      
    if(line==490) digitalWriteDirect(3,1); //or digitalWriteDirect(3,0); to invert vsync
    if(line==492) digitalWriteDirect(3,0); //or digitalWriteDirect(3,1); to invert vsync
    
    line++; if(line == 525) line=0;
}

void setup(){
  for(int i=0;i<320;i++)for(int j=0;j<240;j++)fb[j][i]=j+i;
  
  pinMode(3,OUTPUT);  pinMode(2,OUTPUT);                      // vsync=3 hsync=2
  pinMode(25,OUTPUT); pinMode(26,OUTPUT);                     // blue  (26=msb,25=lsb)
  pinMode(27,OUTPUT); pinMode(28,OUTPUT); pinMode(14,OUTPUT); // green (14=msb,28,27=lsb)
  pinMode(15,OUTPUT); pinMode(29,OUTPUT); pinMode(11,OUTPUT); // red   (11=msb,29,15=lsb)

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

#include <complex>
using namespace std;

const byte cmap[]={0b00000000,0b11100000,0b11100100,0b11101000,0b11101100,0b11110000,0b11110100,0b11111000,0b11111100,
                   0b11011100,0b10111100,0b10011100,0b01111100,0b01011100,0b00111100,0b00011100,0b00011101,0b00011110,
                   0b00011111,0b00011011,0b00010111,0b00010011,0b00001111,0b00001011,0b00000111,0b00000011,0b00100011,
                   0b01000011,0b01100011,0b10000011,0b10100011,0b11000011,0b11100011,0b11100010,0b11100001,0b11100000,0b00000000};
void loop(){
  for(int i=0;i<320;i++){
    for(int j=0;j<240;j++){     
      complex<float> z(0,0),c((i+180.0)/1280.0,(j+640.0)/1280.0);
      int n;
      for(n=1;n<sizeof(cmap);n++){
        z=z*z+c;
        if(norm(z)>4.0)break;
      }
      fb[j][i]=cmap[sizeof(cmap)-n];
    }
  }
  for(;;);
}


* vgaout2.jpg (130.71 KB, 640x413 - viewed 167 times.)
« Last Edit: November 04, 2012, 09:41:21 pm by stimmer » Logged


Forum Administrator
Milano, Italy
Offline Offline
Sr. Member
*****
Karma: 23
Posts: 292
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

 smiley-surprise

stimmer, you've got some serious skills here!
nice work!

C
Logged

C.

Quebec, Canada
Offline Offline
Newbie
*
Karma: 0
Posts: 39
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

it is possible to only display black and white and get a better resolution?
Logged

Offline Offline
God Member
*****
Karma: 32
Posts: 507
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

640x480 black and white only should be possible. It might even be possible with 2 bit greyscale.

There's a chance 800x600 black and white might work. Anything more than that takes too much memory.
Logged


Quebec, Canada
Offline Offline
Newbie
*
Karma: 0
Posts: 39
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

that would be nice 640x480! but just one bit!
« Last Edit: November 06, 2012, 06:34:45 pm by micnossub » Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 1
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

This project can work with arduino uno?
Thanks.
Logged

Ayer, Massachusetts, USA
Offline Offline
Edison Member
*
Karma: 54
Posts: 1857
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

This project can work with arduino uno?
Thanks.
No, the UNO only has enough memory for something like a 120x96 black and white image.

If that is fine, there are two shields that use the TVout library that are supposed to make the job easier:

I have the Video Experimenter, but it is on my to-do pile, and I haven't tried it out yet
Logged

Brazil
Offline Offline
God Member
*****
Karma: 3
Posts: 616
Wusik Dot Com
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Superb!
Logged


Czech
Offline Offline
Jr. Member
**
Karma: 2
Posts: 57
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

This is very usefull for me - thanks

Is possible post source code for 640x480 or 800x600 black/white ?

Many thanks

Kamil
Logged


Offline Offline
Edison Member
*
Karma: 30
Posts: 2493
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

How long before we see a GPU or a graphics card from 1995 get modified to work with due/uno and a VGA monitor? smiley
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 47
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

why 95?
Someone have done it with stm32 based boards: http://hackaday.com/2012/10/08/stm32-driving-a-pcie-video-card/
and Gameduino produces vga(I think) using an FPGA adapterboard.

and, btw, the Propeller, with its 8 "core's" produces vga for games and such, if one could interface more memory on the Due (wish that could be possible on the next SAM based card) one could have kinda ok graphics.
« Last Edit: November 12, 2012, 02:03:42 pm by neslekkim » Logged

Czech
Offline Offline
Jr. Member
**
Karma: 2
Posts: 57
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Simple Game of Life example :-)

Code:
#define GRID_X 100
#define GRID_Y 92

#define MAX_GENERATIONS 250

uint8_t grid[2][GRID_X][GRID_Y];
uint8_t current_grid = 0;
uint8_t generations = 0;

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[240][320];

#define do20(x) x x x x x x x x x x x x x x x x x x x x
#define do80(x)  do20(x) do20(x) do20(x) do20(x)
#define do320(x) do80(x) do80(x) do80(x) do80(x)
#define MNOP(x) asm volatile (" .rept " #x "\n\t nop \n\t .endr \n\t")

void TC0_Handler()
{
    long dummy=REG_TC0_SR0;
                           
    if(line < 480){       
        byte * p=fb[line>>1];
        MNOP(160);
        do320(REG_PIOD_ODSR = *p++;MNOP(2);)
        REG_PIOD_ODSR = 0;
    }     
    if(line==490) digitalWriteDirect(3,1); //or digitalWriteDirect(3,0); to invert vsync
    if(line==492) digitalWriteDirect(3,0); //or digitalWriteDirect(3,1); to invert vsync
   
    line++; if(line == 525) line=0;
}

void setup(){
 
  pinMode(3,OUTPUT);  pinMode(2,OUTPUT);                      // vsync=3 hsync=2
  pinMode(25,OUTPUT); pinMode(26,OUTPUT);                     // blue  (26=msb,25=lsb)
  pinMode(27,OUTPUT); pinMode(28,OUTPUT); pinMode(14,OUTPUT); // green (14=msb,28,27=lsb)
  pinMode(15,OUTPUT); pinMode(29,OUTPUT); pinMode(11,OUTPUT); // red   (11=msb,29,15=lsb)

  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);
 
  initGrid();
  drawGrid();
}


void loop(){
 
  runGrid();
 drawGrid();
 generations++;
 if (generations > MAX_GENERATIONS) {
 generations = 0;
 initGrid();
 }

}

void initGrid()
{
 int i, j;
 int t;

 current_grid = 0;
 for (i = 0; i < GRID_X; i++) {
 for (j = 0; j < GRID_Y; j++) {

 if (rand()%2) {
 grid[0][i][j] = 2;
 } else {
 grid[0][i][j] = 0;
 }
 }
 }
}

void runGrid()
{
 uint8_t x, y;
 int count;
 uint8_t value = 0;
 uint8_t new_grid;

 new_grid = 1 - current_grid;
 for (y = 0; y < GRID_Y; y++) {
 for (x = 0; x < GRID_X; x++) {
 count = count_neighbours(x, y);
 if (count < 2 || count > 3) { value = 0; }
 else if (count == 3) { value = 3; }
 else { value = grid[current_grid][x][y]; }
 grid[new_grid][x][y] = value;
 }
 }
 current_grid = new_grid;
}

int count_neighbours(int x, int y)
{
 int i, j;
 int sx;
 int result = 0;

 x--;
 y--;
 for (i = 0; i < 3; i++) {
 if (y < 0 || y > (GRID_Y - 1)) { continue; }
 for (j = 0; j < 3; j++) {
 if (x < 0 || x > (GRID_X - 1)) { continue; }
 if (i==1 && j == 1) { x++; continue; }
 if (grid[current_grid][x][y]) { result++; }
 x++;
 }
 y++;
 x -= 3;
 }
 return result;
}

void drawGrid()
{
 uint8_t  x,  y;
 uint8_t cx, cy;
 uint8_t grid_next_colour = 0;
 cx = 0;
 cy = 0;
 for (y = 0; y < GRID_Y; y++) {
 cx = 0;
 for (x = 0; x < GRID_X; x++) {
 if (grid[1-current_grid][x][y] != grid[current_grid][x][y]) {
  if(grid[current_grid][x][y]) {
    fb[cy][cx]=rand()%255;
 }
    else {
    fb[cy][cx]=0;
 }

 }
 cx += 2;
 }
 cy += 2;
}
}
Logged


Offline Offline
God Member
*****
Karma: 32
Posts: 507
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Simple Game of Life example :-)

Nice work  smiley-grin (I accidentally left it running all night, it's still going strong!)

Here's a quick status update for the VGA output project. Basically to get any further with this I need to learn ARM inline assembler, which is what I've been doing. With the code above the output is shimmering slightly and if you look closely some of the pixels are bigger than others. I do have code which solves the wide pixels problem and reduces the shimmering, however it is unreliable (sometimes it doesn't compile, sometimes it compiles but doesn't work, sometimes it works perfectly). I guess I have a little more to learn.

I haven't started on 640x480 1bpp yet but I still think it is viable. I don't know about 800x600 (the pixel rate would be 40Mpixels/sec) but there might be a way...

Finally when reading the datasheet I noticed that the SAM3X has some DMA controllers. I am strongly tempted to evaluate whether I can use them rather than the inline assembler. This is even more to learn (I've never used DMA before) but if it does work it would be a much better solution. It would use much less CPU for one thing  smiley-mr-green
« Last Edit: November 14, 2012, 05:48:30 am by stimmer » Logged


Czech
Offline Offline
Jr. Member
**
Karma: 2
Posts: 57
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Simple Wolfram 1D Cellular Automata example :-)

Code:
/* Wolfram Cellular Automata 1D v1.0 */

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[240][320];

#define do20(x) x x x x x x x x x x x x x x x x x x x x
#define do80(x)  do20(x) do20(x) do20(x) do20(x)
#define do320(x) do80(x) do80(x) do80(x) do80(x)
#define MNOP(x) asm volatile (" .rept " #x "\n\t nop \n\t .endr \n\t")

void TC0_Handler()
{
    long dummy=REG_TC0_SR0;
                           
    if(line < 480){       
        byte * p=fb[line>>1];
        MNOP(160);
        do320(REG_PIOD_ODSR = *p++;MNOP(2);)
        REG_PIOD_ODSR = 0;
    }     
    if(line==490) digitalWriteDirect(3,1); //or digitalWriteDirect(3,0); to invert vsync
    if(line==492) digitalWriteDirect(3,0); //or digitalWriteDirect(3,1); to invert vsync
   
    line++; if(line == 525) line=0;
}

void setup(){
 
  pinMode(3,OUTPUT);  pinMode(2,OUTPUT);                      // vsync=3 hsync=2
  pinMode(25,OUTPUT); pinMode(26,OUTPUT);                     // blue  (26=msb,25=lsb)
  pinMode(27,OUTPUT); pinMode(28,OUTPUT); pinMode(14,OUTPUT); // green (14=msb,28,27=lsb)
  pinMode(15,OUTPUT); pinMode(29,OUTPUT); pinMode(11,OUTPUT); // red   (11=msb,29,15=lsb)

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

void loop(){
 
  int iteration = 240;
  int lenght = 320;
  int row = 0;
  int state[lenght];
  int newstate[lenght];
  int i,j,k;
  int rules[8] = {
  int (rand()%2),
  int (rand()%2),
  int (rand()%2),
  int (rand()%2),
  int (rand()%2),
  int (rand()%2),
  int (rand()%2),
  int (rand()%2)};

  for (i=0;i<lenght;i++) state[i]= int (rand()%2);

   for (i=0;i<iteration;i++) {

      for (j=0;j<lenght;j++)
         newstate[j] = 0;

      for (j=0;j<lenght;j++) {
         k = 4*state[(j-1+lenght)%lenght] + 2*state[j] + state[(j+1)%lenght];
         newstate[j] = rules[k];
      }

      for (j=0;j<lenght;j++)
        state[j] = newstate[j];
        DisplayState(state,lenght,row);
        row = row + 1;
   }
}

void DisplayState(int s[],int len, int row)
{
   int i;

   for (i=0;i<len;i++) {
      if (s[i] == 1){
       fb[row][i]=255;
       }       
      else{
       fb[row][i]=0;
        }
      }
}
Logged


Pages: [1] 2 3 4   Go Up
Jump to: