Jan Ostman
Published

AVR VideoBlaster

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

Full instructions provided15,200
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
34 projects • 166 followers
I'm an embeddeds wizard that can turn any pile of electronic junk to something really great. Mc Gyver style.
Contact

Comments

Please log in or sign up to comment.