Go Down

Topic: The VideoBlaster Hi Resolution TVout platform (Read 11176 times) previous topic - next topic

janost

Nov 15, 2013, 12:08 pm Last Edit: Nov 15, 2013, 12:24 pm by janost Reason: 1
The VideoBlaster was born from another project that needed a better than TVout display.

It requires only 2 resistors for sync and video and outputs 40x25 or 22x23 text on composite PAL or NTSC.
It can simultaneously display 40x25 text and graphics plotting with a resolution of 80x50 dots.

By defining your own 8x8 characterdefinitions it displays a resolution of 320x200 or 176x184.
Perfect for games and retro projects.

It only uses 1500bytes PROGMEM + chardefs and 1100bytes RAM so there is plenty free to use for your application.

The USART TX-pin is used for video so you lose serial while the sketch is running but all uploads still works incircuit.

The optional color section is a simple trick for generating the 3.58MHz NTSC color frequency.
It uses the timer2 frequency output on pin3 HP filtered to its 13th harmonic.
Its not tested yet so still in development.


fungus

a) Can we have the latest source code to try it at home?

b) Do you think it's possible to set a color per video line?

No, I don't answer questions sent in private messages (but I do accept thank-you notes...)

janost

#2
Nov 15, 2013, 12:41 pm Last Edit: Nov 15, 2013, 01:02 pm by janost Reason: 1
Yes, I'll put the sourcecode up.

The colorsignal is generated by setting timer2 to divide by 29.
8000000/29 = 275862, 275862 x 13 = 3586206.

By temporarly changing the divide on a single cycle changes its phase compared to the burst.

275862 / 15750 = 17.5 changes/line.
We can modulate the clocksignal output by setting pin3 as input or output but to change phase?

It is going to need another pin for higher phasechange resolution.

fungus


We can modulate the clocksignal output by setting pin3 as input or output but to change phase?


Start the timer at different places in the horizontal blank?
No, I don't answer questions sent in private messages (but I do accept thank-you notes...)

janost



We can modulate the clocksignal output by setting pin3 as input or output but to change phase?


Start the timer at different places in the horizontal blank?



Yes, its all relative to the signal in the colorburst.

janost

Some ideas what need to be done for NTSC color.


janost


b) Do you think it's possible to set a color per video line?


I think it is very doable.

janost

Now I know where the tearing and artifacts comes from.
It turns out the LCD-screen only has a vertical resolution of 240lines and that is an absolute physical.

I run it with over 250 visible lines and that creates line artifacts.

fungus


Now I know where the tearing and artifacts comes from.
It turns out the LCD-screen only has a vertical resolution of 240lines and that is an absolute physical.

I run it with over 250 visible lines and that creates line artifacts.


You're saying it can't accept an NTSC signal?
No, I don't answer questions sent in private messages (but I do accept thank-you notes...)

janost



Now I know where the tearing and artifacts comes from.
It turns out the LCD-screen only has a vertical resolution of 240lines and that is an absolute physical.

I run it with over 250 visible lines and that creates line artifacts.


You're saying it can't accept an NTSC signal?



Yes, it can but I'm running PAL with 288 visible lines.
Some lines drop out and some lines are doubled.

janost

#10
Nov 20, 2013, 05:50 pm Last Edit: Nov 20, 2013, 06:28 pm by janost Reason: 1
I have looked at adding a scart and a VGA port today.
With scart I can do 24x24 text in 16colors and the same with VGA.

Tiled 192x192, that is retro arcaderesolution.
It's a bit easier to get going than composite color.

To make color to work I need to make the pixel output gate the colorbits on D4-D7.
Either with diodes or with a 74LS08 Quad AND gate.

I'll include all 4 modes in the code.

janost

#11
Nov 20, 2013, 06:38 pm Last Edit: Nov 20, 2013, 06:55 pm by janost Reason: 1
Here is the code for 40x25 textmode B/W Composite output.
It contains some leftover junk so not all of it is required.

You can put your own calls in the loop() function but they cannot be blocking, i.e they have to return Before the next 200 lines are painted by the interrupt.

Code: [Select]

#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>

//CBM Textset1 ROM
const unsigned char charROM [8] [128] PROGMEM = { 0x1C , ... , 0xFF }; //Contains the PETSCII Font for characters 0-127

//const unsigned charROM [8] [128] PROGMEM = { 0x00 , ... , 0xFF }; // Contains the Block char font 2x3 blocks for the pset function.

char gameMAP[16] = { 0x20 , 0x20 , 0x4E , 0x20 , 0x20 , 0x4E , 0x20 , 0x20 , 0x4E , 0x20 , 0x20 , 0x20 , 0x45 , 0x45 , 0x45 , 0x4E };



const byte MSPIM_SCK = 4;
const byte MSPIM_SS = 5;

unsigned int scanline=0;
unsigned int videoptr=0;
byte row;
byte charcode;
byte border=0x00;
char videomem[1040];
unsigned int h=0;
unsigned int w=0;

void setup() {
 pinMode (MSPIM_SS, OUTPUT);   // SS
 // must be zero before enabling the transmitter
 UBRR0 = 0;
 UCSR0A = _BV (TXC0);  // any old transmit now complete
 pinMode (MSPIM_SCK, OUTPUT);   // set XCK pin as output to enable master mode
 UCSR0C = _BV (UMSEL00) | _BV (UMSEL01);  // Master SPI mode
 UCSR0B = _BV (TXEN0);  // transmit enable
 // must be done last, see page 206
 UBRR0 = 0;  // 4 Mhz clock rate
 pinMode(2, OUTPUT); //Set D2 as output for Sync
 cli();
 //set timer0 interrupt at 15625Hz
 TCCR0A = 0;// set entire TCCR0A register to 0
 TCCR0B = 0;// same for TCCR0B
 TCNT0  = 0;//initialize counter value to 0
 // set compare match register for 15625hz increments
 OCR0A = 133;// = (16*10^6) / (15625*8) - 1 (must be <256)
 //PAL OCR0A = 134;// = (16*10^6) / (15625*8) - 1 (must be <256)
 
 // turn on CTC mode
 TCCR0A |= (1 << WGM01);
 // Set CS01 and CS00 bits for 9 prescaler
 TCCR0B |= (1 << CS01) | (0 << CS00);  
 // enable timer compare interrupt
 TIMSK0 |= (1 << OCIE0A);
 set_sleep_mode (SLEEP_MODE_IDLE);
 sei();
 for (int x=0; x <40; x++) {
   videomem[x]=32;
 }
 for (int x=40; x <1040; x++){
    videomem[x]=pgm_read_byte(gameMAP+(x&3)+(((x/40)&3)<<2));
 }


}

void TVdelay(unsigned int millisec) {
 unsigned long cnt=millisec*500L;
 for (unsigned long x=0; x < cnt; x++){
 asm("nop\n\t");
 }
}


void drawgrid(unsigned int hh,unsigned int ww) {
 for (int x=40; x <1040; x++){
    videomem[x]=gameMAP[((x+hh)&3)+((((x/40)+ww)&3)<<2)];
 }  
}  




void loop() {
if ((scanline>55)&&(scanline<263)) sleep_mode ();
drawgrid(h++,w--);
TVdelay(100);
}  
 
ISR(TIMER0_COMPA_vect){//timer0 interrupt
 byte c=3;
 byte p=40;
 // NTSC if ((scanline>3)&&(scanline<40)||(scanline>239)) {
   if ((scanline>3)&&(scanline<56)||(scanline>263)) {
   UCSR0B = _BV(TXEN0);
   PORTD = 0; //Hsync
   UDR0 = 0x00; //Load first byte
   while (c--); {  
    // wait for transmitter ready
    while ((UCSR0A & _BV (UDRE0)) == 0)
     {}
   // send pixelbyte
   UDR0 = 0x00;
   }
   while ((UCSR0A & _BV (UDRE0)) == 0)
     {}  
   if (border==0) UCSR0B = 0;
   PORTD =4;      
 }

if (scanline<4) {
   c=3;
   UCSR0B = _BV(TXEN0);
   PORTD = 0; //Vsync
   UDR0 = 0x00;
   while (c--); {
   while ((UCSR0A & _BV (UDRE0)) == 0)
     {}
   UDR0 = 0x00;
   }
   PORTD =0;
   UCSR0B = 0;
   videoptr=0;
   row=0;    
 }  
 
 //NTSC if ((scanline>39)&&(scanline<240)) {
 if ((scanline>55)&&(scanline<263)) {
   asm("nop\n");
   asm("nop\n");
   asm("nop\n");

   UCSR0B = _BV(TXEN0);
   PORTD = 0; //Hsync
   UDR0 = 0x00; //Load first byte
   c=3;
   while (c--) {
    // wait for transmitter ready
    while ((UCSR0A & _BV (UDRE0)) == 0)
     {}
   // send pixelbyte
   UDR0 = 0x00;
   }
 
   while ((UCSR0A & _BV (UDRE0)) == 0)
     {}
    //send colorburst
    UDR0 = B1011010;
    PORTD =0;
    while ((UCSR0A & _BV (UDRE0)) == 0)
     {}

   const register byte * linePtr = &charROM [ row & 0x07 ] [0];
   register byte * messagePtr = (byte *) & videomem [videoptr] ;
    PORTD =4;

   UCSR0B = _BV(TXEN0);
   
   c=3;
   while (c--) {
   //for (byte x=0; x < 3; x++){
    // wait for transmitter ready
    while ((UCSR0A & _BV (UDRE0)) == 0)
     {}
    // send pixelbyte
    UDR0 = 0x00;
   }
   c=7;
   while (c--) {
    // wait for transmitter ready
    while ((UCSR0A & _BV (UDRE0)) == 0)
     {}
   // send pixelbyte
   UDR0 = 0;
   }
   
   UDR0 = pgm_read_byte (linePtr + 32);
 
   while (p--) {  
   UDR0 = pgm_read_byte (linePtr + (* messagePtr++));
   }
 
   while ((UCSR0A & _BV (UDRE0)) == 0)
     {}
   UDR0 = border; //Front porch
   
   if (border==0) UCSR0B = 0;
   
   row++;
   videoptr=(row>>3)*40;
 }
 
 scanline++;
 if (scanline>311) scanline=0;
}

void pset(byte x, byte y ,byte color) {  //This makes a plot routine in 80x100 when using the block font
 unsigned int c_add=(x>>1)+(y>>2)*40;
 char block=(1<<(x&1))<<((y&3)*2);
 if (color!=0) {
  videomem[c_add+40]=videomem[c_add+40]|block;
 }
 else {
  videomem[c_add+40]=videomem[c_add+40]&(255-block);
 }  
}  

janost

This is the best one can do (thanks, Nick) using only C.

I have looked into Assembler but its tough.
Inline assembly in the Arduino IDE is junk, it kills creativity.

I need to find a way to include pure AVR assembler into my functions.

Hi, I get this error -
const unsigned char charROM [8] [128] PROGMEM = { 0x1C , ... , 0xFF }; //Contains the PETSCII Font for characters 0-127

Expected primary-expression before '...' token

Thanks. Dave.

janost


Hi, I get this error -
const unsigned char charROM [8] [128] PROGMEM = { 0x1C , ... , 0xFF }; //Contains the PETSCII Font for characters 0-127

Expected primary-expression before '...' token

Thanks. Dave.


Because I cant include the copyrighted CBM ROM Font.

That line needs to contain 1024 bytedefinitions.

Go Up