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
}
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()
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()
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.