Hardware components | ||||||
| × | 1 |
The circuit
More VideoBlasting
So why didn't the TVout library reach any higher resolution than 160x100?
The answer is simple.
They did not use any hardware onchip to push the pixels out.
If you use the SPI to push the pixel you will gain an immediate 1:1 in pixelspeed
The SPI push out data at the CPU clock / 2.
That is the maximum speed that the chip is capable of.
On a 16MHz chip, that is an impressive 8mbps.
That is really fast, 8000000/sec databits!
On a TV you have around 64uS time to draw a single line (around taking NTSC/PAL in account)
That meens you have hardware to push out 512pixels in that interval.
The no good SPI
So why not use SPI for the pixel pushing?
There is one flaw in the ATmega SPI hardware.
It shifts out 8pixels and delays for one pixel before working on our next 8pixels.
Why?
It is an SPI interface and has to conform to that protocol and that states that there should be a high 9bit after a transfer.
Not good for us. Not at all
We need 8bits, one byte, back to back drawing our videoline.
There is a solution to this.
The USART.
Yes I know its the serial communication via USB to your computer.
But it it has a huge advantage.
It can run at the same speed as the SPI interface but no 9th bit.
That's right. Unlike the SPI port it doesn't do the extra bit.
This is exactly what we need.
The VideoBlaster resistor mixer
The resistor mixer adds the sync and pixeldata to a composite videosignal.
If looking at the NTSC video signal, the 1K resistor is adding 0.3v level sync pulses and the 470ohm resistor is the 0.7v pixel or video data.
When summing it becomes the 1vp-p CBVS signal (Composite Blanking and Video Sync) or composite video.
It is the same circuit that all TVout sketches use but we connect the video resistor to the TX pin instead of a digitalpin.
It works on all ATmegas and Arduinoboards even if its connected to a computer.
You loose the serial debugging but not the serial uploading.
But you gain a videooutput and that can display your serial text instead of sending it to the computer.
And the pixelshifter runs at Fcpu/2 and that meens 512pixels/line at Fcpu 16MHz.
To be able to generate the NTSC Chromasignal Fcpu needs to be 14.318MHz
If not exactly that it will still show the image but it will be in B/W.
The Color VideoBlaster Code
AVR VideoBlaster
I've been on the net for a while and so have all of you.
Ever since I started with the Arduino and after that, the ATmega chip, I was always fascinated of doing video on the chip.
The chip is fully capable of doing video with its 16MIPS processing power. But B/W video isn't very funny. At least not to me.
TVout is one of the things that many people come across.
That gives you B/W composite video graphics on a TV screen.
In a 160x100 maximum resolution.
That is actually a very good resolution for a TV display.
But still in Black&White
What I did was to take the TVout 2 steps further.
I made the resolution 320x200 and in color.
Yes, I broke the imaginary border.
You read it right the first time.
That is 40x25 characters in text and a dazzling 320x200 in graphics.
And its all in color.
(Yes that is 40x25 textmode on any Uno/Nano but only in B/W)
High resolution color on a single ATmega chip.
I'll show you the real circuit and the code.
The VideoBlaster Resistor Mixer
The NTSC Video Signal
The 1284 schematics
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#define PS2_KC_BKSP 0x80
#define PS2_KC_UP 0x81
#define PS2_KC_DOWN 0x82
#define PS2_KC_LEFT 0x83
#define PS2_KC_RIGHT 0x84
#define PS2_KC_PGDN 0x85
#define PS2_KC_PGUP 0x86
#define PS2_KC_END 0x87
#define PS2_KC_HOME 0x88
#define PS2_KC_INS 0x89
#define PS2_KC_DEL 0x8A
#define PS2_KC_ESC 0x8B
#define PS2_KC_CLON 0x8C // caps_lock on
#define PS2_KC_CLOFF 0x8D // caps_lock off
const byte MSPIM_SCK = 0;
byte PROGMEM charROM [1024] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7E, 0x81, 0xA5, 0x81, 0xBD, 0x99, 0x81, 0x7E,
0x7E, 0xFF, 0xDB, 0xFF, 0xC3, 0xE7, 0xFF, 0x7E,
0x6C, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00,
0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00,
0x38, 0x7C, 0x38, 0xFE, 0xFE, 0x7C, 0x38, 0x7C,
0x10, 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x7C,
0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00,
0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF,
0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00,
0xFF, 0xC3, 0x99, 0xBD, 0xBD, 0x99, 0xC3, 0xFF,
0x0F, 0x07, 0x0F, 0x7D, 0xCC, 0xCC, 0xCC, 0x78,
0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18,
0x3F, 0x33, 0x3F, 0x30, 0x30, 0x70, 0xF0, 0xE0,
0x7F, 0x63, 0x7F, 0x63, 0x63, 0x67, 0xE6, 0xC0,
0x99, 0x5A, 0x3C, 0xE7, 0xE7, 0x3C, 0x5A, 0x99,
0x80, 0xE0, 0xF8, 0xFE, 0xF8, 0xE0, 0x80, 0x00,
0x02, 0x0E, 0x3E, 0xFE, 0x3E, 0x0E, 0x02, 0x00,
0x18, 0x3C, 0x7E, 0x18, 0x18, 0x7E, 0x3C, 0x18,
0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
0x7F, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x1B, 0x00,
0x3E, 0x63, 0x38, 0x6C, 0x6C, 0x38, 0xCC, 0x78,
0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x7E, 0x00,
0x18, 0x3C, 0x7E, 0x18, 0x7E, 0x3C, 0x18, 0xFF,
0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00,
0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00,
0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00,
0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00,
0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xFE, 0x00, 0x00,
0x00, 0x24, 0x66, 0xFF, 0x66, 0x24, 0x00, 0x00,
0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00,
0x6C, 0x6C, 0xFE, 0x6C, 0xFE, 0x6C, 0x6C, 0x00,
0x30, 0x7C, 0xC0, 0x78, 0x0C, 0xF8, 0x30, 0x00,
0x00, 0xC6, 0xCC, 0x18, 0x30, 0x66, 0xC6, 0x00,
0x38, 0x6C, 0x38, 0x76, 0xDC, 0xCC, 0x76, 0x00,
0x60, 0x60, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00,
0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00,
0x00, 0x30, 0x30, 0xFC, 0x30, 0x30, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00,
0x7C, 0xC6, 0xCE, 0xDE, 0xF6, 0xE6, 0x7C, 0x00,
0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xFC, 0x00,
0x78, 0xCC, 0x0C, 0x38, 0x60, 0xCC, 0xFC, 0x00,
0x78, 0xCC, 0x0C, 0x38, 0x0C, 0xCC, 0x78, 0x00,
0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x1E, 0x00,
0xFC, 0xC0, 0xF8, 0x0C, 0x0C, 0xCC, 0x78, 0x00,
0x38, 0x60, 0xC0, 0xF8, 0xCC, 0xCC, 0x78, 0x00,
0xFC, 0xCC, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x00,
0x78, 0xCC, 0xCC, 0x78, 0xCC, 0xCC, 0x78, 0x00,
0x78, 0xCC, 0xCC, 0x7C, 0x0C, 0x18, 0x70, 0x00,
0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
0x18, 0x30, 0x60, 0xC0, 0x60, 0x30, 0x18, 0x00,
0x00, 0x00, 0xFC, 0x00, 0x00, 0xFC, 0x00, 0x00,
0x60, 0x30, 0x18, 0x0C, 0x18, 0x30, 0x60, 0x00,
0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00,
0x7C, 0xC6, 0xDE, 0xDE, 0xDE, 0xC0, 0x78, 0x00,
0x30, 0x78, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0x00,
0xFC, 0x66, 0x66, 0x7C, 0x66, 0x66, 0xFC, 0x00,
0x3C, 0x66, 0xC0, 0xC0, 0xC0, 0x66, 0x3C, 0x00,
0xF8, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0xF8, 0x00,
0xFE, 0x62, 0x68, 0x78, 0x68, 0x62, 0xFE, 0x00,
0xFE, 0x62, 0x68, 0x78, 0x68, 0x60, 0xF0, 0x00,
0x3C, 0x66, 0xC0, 0xC0, 0xCE, 0x66, 0x3E, 0x00,
0xCC, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0xCC, 0x00,
0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
0x1E, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, 0x00,
0xE6, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0xE6, 0x00,
0xF0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00,
0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00,
0xC6, 0xE6, 0xF6, 0xDE, 0xCE, 0xC6, 0xC6, 0x00,
0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x00,
0xFC, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00,
0x78, 0xCC, 0xCC, 0xCC, 0xDC, 0x78, 0x1C, 0x00,
0xFC, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0xE6, 0x00,
0x78, 0xCC, 0xE0, 0x70, 0x1C, 0xCC, 0x78, 0x00,
0xFC, 0xB4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xFC, 0x00,
0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00,
0xC6, 0xC6, 0xC6, 0xD6, 0xFE, 0xEE, 0xC6, 0x00,
0xC6, 0xC6, 0x6C, 0x38, 0x38, 0x6C, 0xC6, 0x00,
0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x30, 0x78, 0x00,
0xFE, 0xC6, 0x8C, 0x18, 0x32, 0x66, 0xFE, 0x00,
0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x02, 0x00,
0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00,
0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0xDC, 0x00,
0x00, 0x00, 0x78, 0xCC, 0xC0, 0xCC, 0x78, 0x00,
0x1C, 0x0C, 0x0C, 0x7C, 0xCC, 0xCC, 0x76, 0x00,
0x00, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00,
0x38, 0x6C, 0x60, 0xF0, 0x60, 0x60, 0xF0, 0x00,
0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8,
0xE0, 0x60, 0x6C, 0x76, 0x66, 0x66, 0xE6, 0x00,
0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
0x0C, 0x00, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78,
0xE0, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0xE6, 0x00,
0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
0x00, 0x00, 0xCC, 0xFE, 0xFE, 0xD6, 0xC6, 0x00,
0x00, 0x00, 0xF8, 0xCC, 0xCC, 0xCC, 0xCC, 0x00,
0x00, 0x00, 0x78, 0xCC, 0xCC, 0xCC, 0x78, 0x00,
0x00, 0x00, 0xDC, 0x66, 0x66, 0x7C, 0x60, 0xF0,
0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0x1E,
0x00, 0x00, 0xDC, 0x76, 0x66, 0x60, 0xF0, 0x00,
0x00, 0x00, 0x7C, 0xC0, 0x78, 0x0C, 0xF8, 0x00,
0x10, 0x30, 0x7C, 0x30, 0x30, 0x34, 0x18, 0x00,
0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00,
0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00,
0x00, 0x00, 0xC6, 0xD6, 0xFE, 0xFE, 0x6C, 0x00,
0x00, 0x00, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0x00,
0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8,
0x00, 0x00, 0xFC, 0x98, 0x30, 0x64, 0xFC, 0x00,
0x1C, 0x30, 0x30, 0xE0, 0x30, 0x30, 0x1C, 0x00,
0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
0xE0, 0x30, 0x30, 0x1C, 0x30, 0x30, 0xE0, 0x00,
0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0x00,
};
unsigned int scanline=0;
unsigned int videoptr=0;
volatile byte VBE=0;
byte xpos=0;
byte ypos=0;
byte txtback=0;
byte txtfore=255;
boolean ps2Keyboard_shift; // indicates shift key is pressed
boolean ps2Keyboard_ctrl; // indicates the ctrl key is pressed
boolean ps2Keyboard_alt; // indicates the alt key is pressed
boolean ps2Keyboard_extend; // remembers a keyboard extended char received
boolean ps2Keyboard_release; // distinguishes key presses from releases
boolean ps2Keyboard_caps_lock; // remembers shift lock has been pressed
char videomem[8000];
void setup() {
//Setup for NTSC with 14.318MHz Fcpu clock
UBRR0 = 0; // must be zero before enabling the transmitter
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; // 7.16MHz pixel clock
pinMode(15, OUTPUT); //Set PD7 as output for Sync
pinMode(8, OUTPUT); //Set PD0 as output for video
cli();
//set timer0 interrupt at 15699Hz
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 15699hz increments
OCR0A = 113;// = (16*10^6) / (15699*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();
//------------ PS/2 Keyboard setup ----------------------------
// Enable receiver
UCSR1B = 16 | 8;
/* Set frame format: 1data, 1parity, 1stop bit */
UCSR1C = 64 | 6;
ps2Keyboard_shift = false;
ps2Keyboard_ctrl = false;
ps2Keyboard_alt = false;
ps2Keyboard_extend = false;
ps2Keyboard_release = false;
ps2Keyboard_caps_lock = false;
//----------------------------------------------------------------------------------------------
for (int x=0; x <8000; x++){
videomem[x]=B01010101;
}
}
void TVdelay(unsigned int millisec) {
unsigned long cnt=millisec*100L;
for (unsigned long x=0; x < cnt; x++){
while (VBE==1) sleep_cpu();
}
}
void loop() {
TVdelay(100); //Dont use delay() to make delays, but TVdelay(millis) to do delays, there is no delay function.
printstring("\x80\x87\fBambino BIOS v1.01\n\n\n"); //clear the screen with BGcolor black and FGcolor white.
printstring("VideoBlaster v1.05\n");
while(-1) {
while (VBE==1) sleep_cpu();
//If VBE=1 the CPU have to sleep for the video to be smooth.
//put anything you like in this loop but make sure it returns before the next frame is painted.
// Use printstring(string) to write an entier string to chrout.
// Use chrout(char ascii) to write a singel char to the terminal screen. chr x80 - x87 sets BG and FG attributes.
// Use chrin() to read a singel char from the keyboard.
// use pset(x,y) to set a single dot on the 320x200 screen.
// Use point(x,y,c) to set a color dot on the 320x200 screen (c is color 0-3).
// All the other functions are used by the Bambino BIOS and wont remain the same in the future.
// Dont touch the variables scanline and videoptr, they are not volatile on purpose because of speed reasons.
}
}
ISR(TIMER0_COMPA_vect){//timer0 interrupt
asm("nop\n");
byte p=40;
UCSR0C = 192;
UCSR0B = _BV(TXEN0);
PORTD = 0;
if ((scanline>2)&&(scanline<40)||(scanline>239)) {
UCSR0B = 0;
asm("nop\n");
asm("nop\n");
asm("nop\n"); // Dont touch any of these NOPs
asm("nop\n"); // They are all here for timing.
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
PORTD =128;
VBE=0;
}
if (scanline<3) {
UCSR0B = 0;
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
PORTD =0;
videoptr=0;
}
if ((scanline>39)&&(scanline<240)) {
UDR0 = 0x00; //Load first byte
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
asm("nop\n");
//asm("nop\n");
PORTD =128;
VBE=1;
//asm("nop\n");
//asm("nop\n");
//Color burst
UDR0 = B00001010;
UDR0 = B10101010;
while ((UCSR0A & _BV (UDRE0)) == 0)
{}
UDR0 = B10101000;
while ((UCSR0A & _BV (UDRE0)) == 0)
{}
UDR0 = B00000000;
while ((UCSR0A & _BV (UDRE0)) == 0)
{}
//Back porch
UCSR0C = 193; //This is the phasechange to the colorburst. If you put 192 here instead, you will get blue/green as colors.
UDR0 = B00000000;
while ((UCSR0A & _BV (UDRE0)) == 0)
{}
UDR0 = B00000000;
while ((UCSR0A & _BV (UDRE0)) == 0)
{}
//UDR0 = B00000000;
//UCSR0C = 193;
UDR0 = 0;
while (p--) {
while ((UCSR0A & _BV (UDRE0)) == 0)
{}
UDR0 = videomem[videoptr++];
}
}
UCSR0B = 0;
scanline++;
if (scanline>261) scanline=0;
}
void pset(unsigned int x,unsigned y) {
unsigned int pixelbyte=videoptr+(y*40)+(x>>3);
videomem[pixelbyte]=videomem[pixelbyte] | (128>>(x&7));
}
void point(unsigned int x,unsigned y,byte color) {
x=x&510;
color=((color<<6)&192)>>(x&7);
unsigned int pixelbyte=videoptr+(y*40)+(x>>3);
byte mask=255-(192>>(x&7));
videomem[pixelbyte]=videomem[pixelbyte] & mask | color;
}
void screenclr(byte bgcolor) {
bgcolor=bgcolor&3;
bgcolor=bgcolor | (bgcolor<<2);
bgcolor=bgcolor | (bgcolor<<4);
for (int x=0; x <8000; x++){
videomem[x]=bgcolor;
}
xpos=0;
ypos=0;
}
void drawchar(byte x,byte y,byte ascii) {
if ((x<40)&&(y<25)) {
for (byte i=0; i < 8; i++) {
byte mask=(255-pgm_read_byte(&charROM[(ascii*8)+i]))&txtback;
videomem[(y*320)+x+(i*40)]=(pgm_read_byte(&charROM[(ascii*8)+i])&txtfore)|mask;
}
}
}
void chrout(char ascii) {
switch (ascii) {
case 13:
xpos=0;
ypos++;
if (ypos>24) {
scrollscr();
xpos=0;
ypos=24;
}
break;
case 10:
xpos=0;
ypos++;
if (ypos>24) {
scrollscr();
xpos=0;
ypos=24;
}
break;
case 12:
screenclr(txtback&3);
xpos=0;
ypos=0;
break;
case 0x80:
settxtBGcolor(0);
break;
case 0x81:
settxtBGcolor(1);
break;
case 0x82:
settxtBGcolor(2);
break;
case 0x83:
settxtBGcolor(3);
break;
case 0x84:
settxtFGcolor(0);
break;
case 0x85:
settxtFGcolor(1);
break;
case 0x86:
settxtFGcolor(2);
break;
case 0x87:
settxtFGcolor(3);
break;
default:
drawchar(xpos,ypos,ascii);
xpos++;
if (xpos>39) {
xpos=0;
ypos++;
if (ypos>24) {
scrollscr();
xpos=0;
ypos=24;
}
}
}
}
void scrollscr() {
for (unsigned int i=320; i < 8000; i++) {
videomem[i-320]=videomem[i];
}
for (unsigned int i=7680; i < 8000; i++) {
videomem[i]=0;
}
}
void settxtBGcolor(byte color) {
color=color&3;
color=color | (color<<2);
color=color | (color<<4);
txtback=color;
}
void settxtFGcolor(byte color) {
color=color&3;
color=color | (color<<2);
color=color | (color<<4);
txtfore=color;
}
void printstring(char string[]) {
byte i=0;
while(string[i]) {
chrout(string[i++]);
}
}
char chrin() {
byte result=0;
byte realkey=0;
if (UCSR1A&128) {
result=UDR1;
switch (result) {
case 0xF0: { // key release char
ps2Keyboard_release = true;
ps2Keyboard_extend = false;
result=0;
break;
}
case 0xFA: { // command acknowlegde byte
break;
}
case 0xE0: { // extended char set
ps2Keyboard_extend = true;
break;
}
case 0x12: // left shift
case 0x59: { // right shift
ps2Keyboard_shift = ps2Keyboard_release? false : true;
ps2Keyboard_release = false;
result=0;
break;
}
case 0x11: { // alt key (right alt is extended 0x11)
ps2Keyboard_alt = ps2Keyboard_release? false : true;
ps2Keyboard_release = false;
result=0;
break;
}
case 0x14: { // ctrl key (right ctrl is extended 0x14)
ps2Keyboard_ctrl = ps2Keyboard_release? false : true;
ps2Keyboard_release = false;
break;
}
case 0x58: { // caps lock key
if (!ps2Keyboard_release) {
ps2Keyboard_caps_lock = ps2Keyboard_caps_lock? false : true;
}
else {
ps2Keyboard_release = false;
}
result=0;
break;
}
default: { // a real key
if (ps2Keyboard_release) { // although ignore if its just released
ps2Keyboard_release = false;
result=0;
}
else { // real keys go into CharBuffer
realkey=result;
}
}
}
switch (result) {
case 0x1C: result = 'a'; break;
case 0x32: result = 'b'; break;
case 0x21: result = 'c'; break;
case 0x23: result = 'd'; break;
case 0x24: result = 'e'; break;
case 0x2B: result = 'f'; break;
case 0x34: result = 'g'; break;
case 0x33: result = 'h'; break;
case 0x43: result = 'i'; break;
case 0x3B: result = 'j'; break;
case 0x42: result = 'k'; break;
case 0x4B: result = 'l'; break;
case 0x3A: result = 'm'; break;
case 0x31: result = 'n'; break;
case 0x44: result = 'o'; break;
case 0x4D: result = 'p'; break;
case 0x15: result = 'q'; break;
case 0x2D: result = 'r'; break;
case 0x1B: result = 's'; break;
case 0x2C: result = 't'; break;
case 0x3C: result = 'u'; break;
case 0x2A: result = 'v'; break;
case 0x1D: result = 'w'; break;
case 0x22: result = 'x'; break;
case 0x35: result = 'y'; break;
case 0x1A: result = 'z'; break;
// note that caps lock only used on a-z
case 0x41: result = ps2Keyboard_shift? ';' : ','; break;
case 0x49: result = ps2Keyboard_shift? ':' : '.'; break;
case 0x4A: result = ps2Keyboard_shift? '?' : '/'; break;
case 0x54: result = ps2Keyboard_shift? '{' : '['; break;
case 0x5B: result = ps2Keyboard_shift? '}' : ']'; break;
case 0x4E: result = ps2Keyboard_shift? '_' : '-'; break;
case 0x55: result = ps2Keyboard_shift? '+' : '='; break;
case 0x29: result = ' '; break;
case 0x45: result = ps2Keyboard_shift? '=' : '0'; break;
case 0x16: result = ps2Keyboard_shift? '!' : '1'; break;
case 0x1E: result = ps2Keyboard_shift? 0x22 : '2'; break;
case 0x26: result = ps2Keyboard_shift? '#' : '3'; break;
case 0x25: result = ps2Keyboard_shift? '$' : '4'; break;
case 0x2E: result = ps2Keyboard_shift? '%' : '5'; break;
case 0x36: result = ps2Keyboard_shift? '&' : '6'; break;
case 0x3D: result = ps2Keyboard_shift? '/' : '7'; break;
case 0x3E: result = ps2Keyboard_shift? '(' : '8'; break;
case 0x46: result = ps2Keyboard_shift? ')' : '9'; break;
case 0x0D: result = '\t'; break;
case 0x5A: result = 13; break;
case 0x66: result = PS2_KC_BKSP; break;
case 0x69: result = ps2Keyboard_extend? PS2_KC_END : '1'; break;
case 0x6B: result = ps2Keyboard_extend? PS2_KC_LEFT : '4'; break;
case 0x6C: result = ps2Keyboard_extend? PS2_KC_HOME : '7'; break;
case 0x70: result = ps2Keyboard_extend? PS2_KC_INS : '0'; break;
case 0x71: result = ps2Keyboard_extend? PS2_KC_DEL : '.'; break;
case 0x72: result = ps2Keyboard_extend? PS2_KC_DOWN : '2'; break;
case 0x73: result = '5'; break;
case 0x74: result = ps2Keyboard_extend? PS2_KC_RIGHT : '6'; break;
case 0x75: result = ps2Keyboard_extend? PS2_KC_UP : '8'; break;
case 0x76: result = PS2_KC_ESC; break;
case 0x79: result = '+'; break;
case 0x7A: result = ps2Keyboard_extend? PS2_KC_PGDN : '3'; break;
case 0x7B: result = '-'; break;
case 0x7C: result = '*'; break;
case 0x7D: result = ps2Keyboard_extend? PS2_KC_PGUP : '9'; break;
} // end switch(result)
}
if (((result>='a') && (result<='z')) &&
((ps2Keyboard_shift && !ps2Keyboard_caps_lock) ||
(!ps2Keyboard_shift && ps2Keyboard_caps_lock))) {
result = result + ('A'-'a');
}
return result;
}
Comments