Arduino SSD1306 LED
A more simple version of Instructables example. For me, the most interesting part is the speeds to fill 1 byte ad fill 128 bytes in the same page are almost the same.
// SSD1306
// https://www.adafruit.com/datasheets/SSD1306.pdf
// 5v
#define PIN_DATA_COMMAND (11)
#define PIN_RESET (13)
#define PIN_SCL (10)
#define PIN_SDA (9)
void led_send(bool is_data, uint8_t data) {
if (is_data) {
digitalWrite(PIN_DATA_COMMAND, HIGH);
} else {
digitalWrite(PIN_DATA_COMMAND, LOW);
}
for (int i = 0; i < 8; ++i) {
digitalWrite(PIN_SCL, LOW);
if (data & 0x80) {
digitalWrite(PIN_SDA, 1);
} else {
digitalWrite(PIN_SDA, 0);
}
digitalWrite(PIN_SCL, HIGH);
data <<= 1;
}
}
void led_send_data(uint8_t data) {
led_send(true, data);
}
void led_send_command(uint8_t command) {
led_send(false, command);
}
void led_init() {
digitalWrite(PIN_SCL, HIGH);
digitalWrite(PIN_RESET, LOW);
delay(50);
digitalWrite(PIN_RESET, HIGH);
digitalWrite(PIN_SCL, LOW);
// display off (sleep mode)
led_send_command(0xae);
// segment remap (?)
led_send_command(0xa1);
// VCOMH deselect level (?)
led_send_command(0xdb);
led_send_command(0x40);
// pre-charge period
// http://en.wikipedia.org/wiki/Pre-charge
led_send_command(0xd9);
led_send_command(0xf1);
// COM pins hardware configuration (?)
led_send_command(0xda);
led_send_command(0x12);
// memory addressing mode
// 0x00 : horizontal
// 0x01 : vertical
// 0x02 : page
led_send_command(0x20);
led_send_command(0x02);
// enable charge pump, dc/dc converter
// http://en.wikipedia.org/wiki/Charge_pump
led_send_command(0x8d);
led_send_command(0x14);
// display start line? (0x40 | (0 ~ 63))
led_send_command(0x40 | 0);
// display offset (vertical shift), 0 ~ 63
led_send_command(0xd3);
led_send_command(0x00);
// multiplex ratio
// http://en.wikipedia.org/wiki/Multiplexed_display
led_send_command(0xa8);
led_send_command(0x3f);
// display clock divide ratio / oscillator frequency
led_send_command(0xd5);
led_send_command(0x80);
// contrast
// double byte, 2nd byte means contrast. Constrast increases as it increses.
led_send_command(0x81);
led_send_command(0x00);
// entire display off
// 0xa4 : pixels are on based on datas in RAM
// 0xa5 : all pixels are on
led_send_command(0xa4);
// normal display
// 0xa6 : bit 0 -> pixel off, bit 1 -> pixel on
// 0xa7 : bit 1 -> pixel off, bit 0 -> pixel on
led_send_command(0xa6);
// display on (normal mode)
led_send_command(0xaf);
}
void led_fill(const uint8_t* map) {
uint8_t y;
for (y = 0; y < 8; ++y) {
led_send_command(0xb0 + y);
led_send_command(0x01);
led_send_command(0x10);
for (int x = 0; x < 128; ++x) {
led_send_data(*map++);
}
}
}
uint8_t led_set_pixel(uint8_t* map, int x, int y, uint8_t c) {
// to page
map += 128 * (y / 8);
y %= 8;
// to row
map += x;
// set col
*map &= ~(1 << y);
*map |= (c << y);
return *map;
}
uint8_t display_map[1024];
uint8_t pixel = 0;
void setup() {
pinMode(PIN_SCL,OUTPUT);
pinMode(PIN_SDA,OUTPUT);
pinMode(PIN_RESET,OUTPUT);
pinMode(PIN_DATA_COMMAND,OUTPUT);
led_init();
led_fill(display_map);
}
void loop() {
pixel ^= 1;
for (int y = 0 ; y < 64; ++y) {
for (int x = 0; x < 128; ++x) {
led_send_command(0xb0 + y / 8);
led_send_command(0x00 + x % 16);
led_send_command(0x10 + x / 16);
led_send_data(led_set_pixel(display_map, x, y, pixel));
delay(100);
}
}
}