mr. city's arduino section
Project 1: Output VGA Signals to a CRT Monitor
This is code for the Arduino microcontroller that will display vertical lines on a VGA screen at a resolution of approximately 376x282 @ 60 Hz. You will probably need a CRT monitor to get this to work correctly; it doesn't work on my LCD monitor. (If you can figure out the timings that'll work on an LCD, be my guest!)
The schematic is shown at left. Click on it in order to see it in full size. As you can see, Arduino pins 13, 12, 7, 4, and 2 are connected to a female D-SUB connector, but not before going through some resistors first. 13 & 12 (sync) go out to one 220-ohm resistor each, and 7, 4, & 2 (the colors) each go to their own voltage divider with R1 = 1200 ohms and R2 = 180 ohms.
Addenda/Notes:
Here are a few places I got guidance from on my quest to write this firmware:
#include <avr/interrupt.h> // horizontal line counter (negative is during vertical blanking) int hzCount = -10; unsigned short int OCR1AMEM = 0; // ============== // Pinout: #define HSYNC 0b00100000; // 13: HSYNC (Port B5) #define VSYNC 0b00010000; // 12: VSYNC (Port B4) #define BLACK 0b00000000; // Black #define BLUE 0b10000000; // 7: Blue (Port D7) #define GREEN 0b00010000; // 4: Green (Port D4) #define RED 0b00000100; // 2: Red (Port D2) #define CYAN 0b10010000; // Cyan #define YELLOW 0b00010100; // Yellow #define MAGENTA 0b10000100; // Magenta #define WHITE 0b10010100; // White // Others go to GND // ======= // hurry up & wait #define NOM asm("nop"); #define NOM5 asm("nop\nnop\nnop\nnop\nnop"); #define NOM10 asm("nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop"); #define NOM20 asm("nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop"); void hLine(void) { PORTB = PORTB ^ HSYNC; // invert HSYNC - negative polarity NOM; NOM; NOM; NOM; NOM; NOM; NOM; delayMicroseconds(3); // wait for "sync length" time PORTB = PORTB ^ HSYNC; // invert HSYNC again NOM; NOM; NOM; NOM; NOM; NOM; NOM; delayMicroseconds(4); // wait for back porch time // draw a line on-screen 4 pixels wide (the "eq" operation + 3 nops) PORTD = RED; NOM; NOM; NOM; PORTD = BLACK; NOM; NOM; NOM; PORTD = GREEN; NOM; NOM; NOM; PORTD = BLACK; NOM; NOM; NOM; PORTD = BLUE; NOM; NOM; NOM; PORTD = BLACK; NOM; NOM; NOM; PORTD = CYAN; NOM; NOM; NOM; PORTD = BLACK; NOM; NOM; NOM; PORTD = MAGENTA; NOM; NOM; NOM; PORTD = BLACK; NOM; NOM; NOM; PORTD = YELLOW; NOM; NOM; NOM; PORTD = BLACK; NOM; NOM; NOM; PORTD = WHITE; NOM; NOM; NOM; PORTD = BLACK; NOM; NOM; NOM; // three pixels at a time PORTD = RED; NOM; NOM; PORTD = BLACK; NOM; NOM; PORTD = GREEN; NOM; NOM; PORTD = BLACK; NOM; NOM; PORTD = BLUE; NOM; NOM; PORTD = BLACK; NOM; NOM; PORTD = CYAN; NOM; NOM; PORTD = BLACK; NOM; NOM; PORTD = MAGENTA; NOM; NOM; PORTD = BLACK; NOM; NOM; PORTD = YELLOW; NOM; NOM; PORTD = BLACK; NOM; NOM; PORTD = WHITE; NOM; NOM; PORTD = BLACK; NOM; NOM; // two pixels at a time PORTD = RED; NOM; PORTD = BLACK; NOM; PORTD = GREEN; NOM; PORTD = BLACK; NOM; PORTD = BLUE; NOM; PORTD = BLACK; NOM; PORTD = CYAN; NOM; PORTD = BLACK; NOM; PORTD = MAGENTA; NOM; PORTD = BLACK; NOM; PORTD = YELLOW; NOM; PORTD = BLACK; NOM; PORTD = WHITE; NOM; PORTD = BLACK; NOM; // one pixel at a time, with black spaces PORTD = RED; PORTD = BLACK; PORTD = GREEN; PORTD = BLACK; PORTD = BLUE; PORTD = BLACK; PORTD = CYAN; PORTD = BLACK; PORTD = MAGENTA; PORTD = BLACK; PORTD = YELLOW; PORTD = BLACK; PORTD = WHITE; PORTD = BLACK; // one pixel at a time, no black PORTD = RED; PORTD = GREEN; PORTD = BLUE; PORTD = CYAN; PORTD = MAGENTA; PORTD = YELLOW; PORTD = WHITE; PORTD = BLACK; } ISR(TIMER1_COMPA_vect) { // do vsync with positive polarity if (hzCount == -10 || hzCount == -6) PORTB = PORTB ^ VSYNC // do hsync when the time is right if (hzCount > -1 || hzCount < 282) hLine(); hzCount++; if (hzCount > 285) hzCount = -10; } void setup(void) { // pins pinMode(2, OUTPUT); pinMode(7, OUTPUT); pinMode(4, OUTPUT); pinMode(12, OUTPUT); pinMode(13, OUTPUT); digitalWrite(13, LOW); // start HSYNC low digitalWrite(12, HIGH); // start VSYNC high digitalWrite(7, LOW); // start blue low digitalWrite(4, LOW); // start green low digitalWrite(2, LOW); // start red low // hsync timer, see ATmega328 datasheet for more details // TIMSK0: Timer/Counter1 Interrupt Mask Register // TOIE0 = 1: when set, enables the Timer/Counter1 Overflow interrupt // This enables everything already set EXCEPT for TOIE0 TIMSK0 &= !(1 << TOIE0); // temporarily disable interrupts cli(); // Timer/Counter Control Registers // Timer/Counter1 Control Register A // Ignore any functionality provided by this Register TCCR1A = 0; // Timer/Counter1 Control Register B // WGM22 = 8: Set timer to CTC mode with TOP = OCR1A (WGM12 may also work?) // CS10 = 1: Do not prescale the clock TCCR1B = 1 << WGM12 | 1 << CS10; // Sets the TOP (highest) value the Counter will count to // F_ocr1a = 16MHz / (2 * prescale * OCR1A); F = 1/192 MHz: usu. 0x5FF; F = 1/57 MHz; usu. 1C7 OCR1A = 0x01C8; // TIMSK1: Timer/Counter1 Interrupt Mask Register // OCIE1A = 2: when set, enables the Timer1 Output Compare A Match interrupt TIMSK1 = 1 << OCIE1A; // re-enable interrupts sei(); }void loop() { //twiddle thumbs }
Project 2: Writing the Arduino Bootloader using an Arduino Uno
This simple workup was derived from this tutorial from Sparkfun. The only difference is I eschewed the command-line stuff they talk about and instead opted for a simple GUI approach provided by the Arduino SDK. The end goal here is to write the Arduino bootloader to a chip on a Duemilanove using an Arduino Uno SMD edition as the ISP. (Whether or not it's the SMD version shouldn't make a difference.)
One other note is I'm often driven to do things that aren't always obvious with the stuff I have. I didn't have the header sockets necessary to bridge the Arduino Uno output pins to the ICSP headers on the Duemilanove board. However, considering my age, I have an inordinate amount of old computer parts dating from the late 1980s to about 2000, and since a lot of this old stuff happens to have the same pin size as many of the DIY kits like Arduino, I leveraged an old "game port" (15-pin 2-row D-SUB connector) I had lying around to use as a bus for the ICSP signals. One end is the 15-pin female jack, and the other end looks like an old IDE cable, but skinnier (as it should be; less pins!). I used regular prototype wire to tenuously connect the 15-pin jack to the Uno's output pins. The Sparkfun tutorial describes the exact pinout you need to use. I'll go over the basic formula here for using the Arduino SDK to initiate the burning:
Note that you can probably flip around the instructions for your board arrangement. For instance, you can treat the word "Uno" as the device you intend to use as the programmer.
Project 3: TOP SECRET! Currently in progress. More to come once it's ready, commercially available, or whatever.