Skip to content

Instantly share code, notes, and snippets.

@bellinitte
Last active October 6, 2021 18:36
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bellinitte/197142555ce78ee82c816c79941f351a to your computer and use it in GitHub Desktop.
Save bellinitte/197142555ce78ee82c816c79941f351a to your computer and use it in GitHub Desktop.
Displaying an image on a Nokia 5510 LCD controlled by an ATmega328P
#define F_CPU 16000000UL
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include "image.c"
#define LCD_RST PC1
#define LCD_SCE PC2
#define LCD_DC PC3
#define LCD_DIN PC4
#define LCD_CLK PC5
volatile uint16_t image_pos = (uint16_t) image;
void lcd_write(uint8_t val, uint8_t as_data) {
PORTC &= ~_BV(LCD_SCE);
if (as_data) {
PORTC |= _BV(LCD_DC);
} else {
PORTC &= ~_BV(LCD_DC);
}
for (uint8_t i = 0; i < 8; i += 1) {
if ((val >> (7-i)) & 0x01) {
PORTC |= _BV(LCD_DIN);
} else {
PORTC &= ~_BV(LCD_DIN);
}
PORTC |= _BV(LCD_CLK);
PORTC &= ~_BV(LCD_CLK);
}
PORTC |= _BV(LCD_SCE);
}
void lcd_write_cmd(uint8_t val) {
lcd_write(val, 0);
}
void lcd_write_data(uint8_t val) {
lcd_write(val, 1);
}
void lcd_init() {
DDRC |= _BV(LCD_SCE);
DDRC |= _BV(LCD_RST);
DDRC |= _BV(LCD_DC);
DDRC |= _BV(LCD_DIN);
DDRC |= _BV(LCD_CLK);
PORTC |= _BV(LCD_RST);
PORTC |= _BV(LCD_SCE);
_delay_ms(10);
PORTC &= ~_BV(LCD_RST);
_delay_ms(70);
PORTC |= _BV(LCD_RST);
PORTC &= ~_BV(LCD_SCE);
lcd_write_cmd(0x21);
lcd_write_cmd(_BV(4) | 0); // Bias system (0-7)
lcd_write_cmd(_BV(2) | 0); // Temperature coefficient (0-3)
lcd_write_cmd(_BV(7) | 50); // V_OP (0-127)
lcd_write_cmd(0x20);
lcd_write_cmd(_BV(3) | _BV(2)); // D = 1, E = 0
}
void lcd_render() {
lcd_write_cmd(0x80); // X = 0
lcd_write_cmd(0x40); // Y = 0
for (int i = 0; i < 504; ++i) {
lcd_write_data(pgm_read_byte(image_pos));
++image_pos;
}
}
int main(void) {
lcd_init();
lcd_render();
while (1) {}
}
#!/usr/bin/env bash
set -ex
python3 preprocess.py image.png > image.c
avr-gcc -mmcu=atmega328p -Wall -Os -o main.elf main.c
avrdude -p m328p -c usbasp -e -V -U flash:w:main.elf
import sys
from PIL import Image
image = Image.open(sys.argv[1])
assert image.size == (84, 48), "image size is not 84x48"
def binarize(pixel):
r, g, b, a = pixel
assert a == 255, "image has a transparent pixel"
assert (r, g, b) == (0, 0, 0) or (r, g, b) == (255, 255, 255), "image is not a binary image"
return r // 255
pixels = list(map(binarize, image.getdata()))
frame_buffer = [0] * 504
def set_buffer(x, y, pixel):
global frame_buffer
p = x + y // 8 * 84
if pixel:
frame_buffer[p] |= 2 ** (y % 8)
else:
frame_buffer[p] &= ~(2 ** (y % 8))
for x in range(84):
for y in range(48):
i = y * 84 + x
set_buffer(83 - x, 47 - y, not pixels[i]) # Rotate 180 degrees and invert the color
print("const uint8_t image[504] PROGMEM = {")
for byte in frame_buffer:
print(f" 0x{byte:02x},")
print("};")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment