1. arduino sketch
28 color gimp palette and palette generator.
index image to avr pin bitmap converter.
  2. basic arduino sketch for a 28 color vga synthesizer

    this arduino sketch displays a 32x32 pixel image. two potentiometers can been hooked up to analog inputs 0 and 1 for adjusting/corrupting the hsync/vsync. a potentiometer on analog input 2 scrolls the image vertically and adjacent memory. images can be uploaded via serial.

    // copy-it-right
    
    #define VSYNC 1 << 0
    #define HSYNC 1 << 1
    
    // high voltage (bright) RGB
    #define HR     1 << 2
    #define HG     1 << 3
    #define HB     1 << 4
    
    // low voltage (dim) RGB
    #define LR     1 << 5
    #define LG     1 << 6
    #define LB     1 << 7
    
    
    #define NOM1 asm("nop");
    #define NOM10 asm("nop\t\nnop\t\nnop\t\nnop\t\nnop\t\nnop\t\nnop\t\nnop\t\nnop\t\nnop");
    
    
    int lnc = 0;
    int lna = 0;
    int lnt = 479;
    
    int imgb, imgc = 0, imgf = 0;
    
    unsigned short int lni = 0;
    unsigned char img[1792];
    
    
    void hsync()
    {
      NOM10;
      PORTB &= ~HSYNC;
      NOM10; NOM10; NOM10; NOM10; NOM10; NOM10;
      PORTB |= HSYNC;
      NOM10; NOM10; NOM10;
    }
    
    
    inline void pxl(int x) 
    {
      PORTD = img[lni + x];
      NOM1; NOM1; NOM1; NOM1; NOM1; NOM1;
    }
    
    
    ISR(TIMER1_COMPA_vect)
    {
      // vsync
      if (lnc == -35) PORTB &= ~VSYNC;
      if (lnc == -37) PORTB |= VSYNC;
    
      hsync();
    
      if (lnc > -1) {
        // drawing a 30x30 image for now
    
        lni = (lnc + lna) >> 4 << 5;
    
        // 382 cycles
        pxl( 0); pxl( 1); pxl( 2); pxl( 3); pxl( 4); pxl( 5); pxl( 6); pxl( 7);
        pxl( 8); pxl( 9); pxl(10); pxl(11); pxl(12); pxl(13); pxl(14); pxl(15);
        pxl(16); pxl(17); pxl(18); pxl(19); pxl(20); pxl(21); pxl(22); pxl(23);
        pxl(24); pxl(25); pxl(26); pxl(27); pxl(28); pxl(29); pxl(30); pxl(31);
    
        // 2 cycles
        PORTD = 0;
      }
    
      lnc++;
      if (lnc > lnt) {
        lnc = -45;
      }
    }
    
    
    void setup()
    {
      // pins
      DDRD = HR | HG | HB | LR | LG | LB;
      DDRB = VSYNC | HSYNC;
      PORTB = VSYNC | HSYNC;
    
      // timer
      TIMSK0 &= !(1 << TOIE0);
      cli();
      TCCR1A = 0;
      TCCR1B = 1 << WGM22 | 1 << CS10;
      OCR1A = 508;
      TIMSK1 = 1 << OCIE1A;
      sei();
      
      Serial.begin(9600);
    }
    
    
    void read_img_data()
    {
      if (Serial.available() > 0) {
        if (Serial.read() == B11111100) {
          noInterrupts();
          lnt = 479;
          while (imgc < 1792) {
            imgb = Serial.read();
            if (imgb > -1) {
              img[imgc] = (unsigned char) imgb;
              imgf = 0;
              imgc++;
            } else {
              imgf++;
              if (imgf > 4096) {
                interrupts();
                return;
              }
            }
          }
          interrupts();
        }
      }
    }
    
    
    void loop()
    {
      read_img_data();
      OCR1A = analogRead(0);  // 5K potentiometer
      lnt = analogRead(1) * 2;  // 5K potentiometer
      lna = analogRead(2);  // 1K or 5K potentiometer
    }
    
  3. indexed image to avr pin bitmap

    this python script converts an indexed image to the avr pin bitmap equivalent. uses a special gimp palette that maps indexed colors to the pin bitmap. i.e. for the 28 color gimp palette, a bright red indexed pixel will be converted to the byte 00100100.

    usage: img2avr.py palette.gpl image.png > image.out

    img2avr.py

    # copy-it-right
    
    import sys
    
    from PIL import Image
    
    
    def parse_palette(data):
        palette = []
        after_header = False
        for line in data:
            if line.startswith('#'):
                after_header = True
                continue
            if after_header:
                palette.append(int(line.split()[-1], 2))
        return palette
    
    
    def main():
        color_pin_map = parse_palette(open(sys.argv[1]))
        image = Image.open(sys.argv[2])
    
        assert image.mode == 'P', 'image must be indexed'
    
        sys.stdout.write(chr(int('11111100', 2)))
    
        for i, px in enumerate(image.getdata()):
            sys.stdout.write(chr(color_pin_map[px]))
    
    
    if __name__ == '__main__':
        main()
    
  4. 28 color gimp palette generator

    this python script generates a gimp palette which you can use to convert rgb images to an indexed image which can be converted for use on the avr.

    # copy-it-right
    
    def main():
        colors = set()
    
        print 'GIMP Palette'
        print 'Name: avr-vga'
        print 'Columns: 0'
        print '#'
    
        for n in range(0, 256):
            b = bin(n)[2:].rjust(8, '0')[:-2] + '00'
            colors.add(b)
    
        colors = list(colors)
        colors.sort()
        colors.reverse()
        color_map = {}
    
        for c in colors:
    
            r = 0
            g = 0
            b = 0
    
            if int(c[0]):
                b += 127.5
            if int(c[1]):
                g += 127.5
            if int(c[2]):
                r += 127.5
            if int(c[3]):
                b += 127.5
            if int(c[4]):
                g += 127.5
            if int(c[5]):
                r += 127.5
    
            color_map[(r, g, b)] = c
    
        colors = color_map.items()
        colors.sort(key=lambda i: i[0])
    
        for (r, g, b), c in colors:
            print ' %3i %3i %3i\t%s' % (r, g, b, c)
    
    
    if __name__ == '__main__':
        main()
    
  5. 28 color gimp palette

    GIMP Palette
    Name: avr-vga
    Columns: 0
    #
       0   0   0	00000000
       0   0 127	00010000
       0   0 255	10010000
       0 127   0	00001000
       0 127 127	00011000
       0 127 255	10011000
       0 255   0	01001000
       0 255 127	01011000
       0 255 255	11011000
     127   0   0	00000100
     127   0 127	00010100
     127   0 255	10010100
     127 127   0	00001100
     127 127 127	00011100
     127 127 255	10011100
     127 255   0	01001100
     127 255 127	01011100
     127 255 255	11011100
     255   0   0	00100100
     255   0 127	00110100
     255   0 255	10110100
     255 127   0	00101100
     255 127 127	00111100
     255 127 255	10111100
     255 255   0	01101100
     255 255 127	01111100
     255 255 255	11111100
    

Powered by Tumblr; designed by Adam Lloyd.