Jan Ostman
Published

AVR VideoBlaster

How about NTSC color video on a single chip with just 2 resistors?

Full instructions provided14,667
AVR VideoBlaster

Things used in this project

Hardware components

Microchip Atmega 1284P
×1

Story

Read more

Code

the_color_videoblaster_code.

C/C++
the_color_videoblaster_code.
#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;
}

Credits

Jan Ostman

Jan Ostman

34 projects • 159 followers
I'm an embeddeds wizard that can turn any pile of electronic junk to something really great. Mc Gyver style.

Comments