From: Doug Szumski Date: Tue, 5 Aug 2014 10:49:30 +0000 (+0100) Subject: examples: Added SSD1306 example board X-Git-Tag: v1.3~78^2 X-Git-Url: https://git.htl-mechatronik.at/public/?a=commitdiff_plain;h=318d3ab8ea77206a97a46c740716d083cc5e149e;p=sx%2Fsimavr.git examples: Added SSD1306 example board atmega32_ssd1306.c Example avr firmware ssd1306.* SSD1306 avr driver images.* simavr logo used in example firmware ssd1306demo.c simavr demo for ssd1306 part --- diff --git a/examples/board_ssd1306/Makefile b/examples/board_ssd1306/Makefile new file mode 100644 index 0000000..985f1ea --- /dev/null +++ b/examples/board_ssd1306/Makefile @@ -0,0 +1,55 @@ +# +# Copyright 2008-2011 Michel Pollet +# +# This file is part of simavr. +# +# simavr is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# simavr is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with simavr. If not, see . + +target= ssd1306demo +firm_src = ${wildcard at*${board}.c} +firmware = ${firm_src:.c=.axf} +simavr = ../../ + +IPATH = . +IPATH += ../parts +IPATH += ${simavr}/include +IPATH += ${simavr}/simavr/sim +IPATH += ${simavr}/simavr/sim +IPATH += ${simavr}/simavr/sim + +VPATH = . +VPATH += ../parts + +LDFLAGS += -lpthread + +include ../Makefile.opengl + +all: obj atmega32_ssd1306.axf ${target} + +atmega32_ssd1306.axf: atmega32_ssd1306.c ssd1306.c images.c + +include ${simavr}/Makefile.common + +board = ${OBJ}/${target}.elf + +${board} : ${OBJ}/ac_input.o +${board} : ${OBJ}/ssd1306_virt.o +${board} : ${OBJ}/ssd1306_glut.o +${board} : ${OBJ}/${target}.o + +${target}: ${board} + @echo $@ done + +clean: clean-${OBJ} + rm -rf *.hex *.a *.axf ${target} *.vcd .*.swo .*.swp .*.swm .*.swn diff --git a/examples/board_ssd1306/README b/examples/board_ssd1306/README new file mode 100644 index 0000000..5a3096d --- /dev/null +++ b/examples/board_ssd1306/README @@ -0,0 +1,10 @@ +board_ssd1306 + +(C) 2014 Doug Szumski + +This sample code demonstrates the use of the SSD1306 OLED driver. It +runs identically in real life. + +The part has been tested using only the supplied driver. + +In the future it could be extended to allow parallel addressing and I2C mode. \ No newline at end of file diff --git a/examples/board_ssd1306/atmega32_ssd1306.c b/examples/board_ssd1306/atmega32_ssd1306.c new file mode 100644 index 0000000..bf9cc25 --- /dev/null +++ b/examples/board_ssd1306/atmega32_ssd1306.c @@ -0,0 +1,170 @@ +/* + atmega32_ssd1306.c + + Copyright 2014 Doug Szumski + + This file is part of simavr. + + simavr is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + simavr is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with simavr. If not, see . + */ + +#include +#include +#include + +#undef F_CPU +#define F_CPU 7380000 + +#include "avr_mcu_section.h" +AVR_MCU(F_CPU, "atmega32"); + +#include "ssd1306.h" +#include "images.h" + +#define DEFAULT_DELAY 10000 + +void +spi_init (void) +{ + DDRB |= (1 << PB4) | (1 << PB5) | (1 << PB7) | (1 << PB3) | (1 << PB1); + SPCR |= (1 << SPE) | (1 << MSTR); + // Double the speed + SPSR |= (1 << SPI2X); +} + +void +demo_set_contrast (void) +{ + for (uint16_t contrast = 0; contrast <= 255; contrast++) + { + PORTB ^= (1 << PB0); + ssd1306_set_contrast (contrast); + _delay_ms (DEFAULT_DELAY/200); + } +} + +void +demo_show_image (void) +{ + ssd1306_write_image_fb (logo); + ssd1306_display_fb (); + _delay_ms (DEFAULT_DELAY); +} + +/* Draw some dots by writing directly to the VRAM */ +void +demo_set_byte_direct (void) +{ + ssd1306_clear_screen (); + uint8_t x = 0; + for (uint8_t page = 0; page < SSD1306_PIXEL_PAGES; ++page) + { + for (x = 0; x < SSD1306_X_PIXELS; x += 2) + { + ssd1306_write_byte (x, page, 0xAA); + } + } + _delay_ms (DEFAULT_DELAY); +} + +/* Draw some stripes by setting individual pixels on the frame buffer */ +void +demo_set_pixels (void) +{ + ssd1306_clear_fb (); + uint8_t x = 0; + for (uint8_t y = 0; y < SSD1306_Y_PIXELS; ++y) + { + for (x = 0; x < SSD1306_X_PIXELS; x += 2) + { + ssd1306_set_pixel_fb (x, y, PIXEL_STATE_ON); + } + } + ssd1306_display_fb (); + _delay_ms (DEFAULT_DELAY); +} + +void +demo_clear_screen (void) +{ + // Turn all pixels on + memset (ssd1306_frame_buffer_g, 0xFF, SSD1306_PIXEL_BYTES); + ssd1306_display_fb (); + _delay_ms (DEFAULT_DELAY); + + // Clear screen + ssd1306_clear_screen (); + _delay_ms (DEFAULT_DELAY); +} + +void +demo_set_power_state (void) +{ + ssd1306_set_power_state (POWER_STATE_SLEEP); + _delay_ms (DEFAULT_DELAY); + ssd1306_set_power_state (POWER_STATE_ON); + _delay_ms (DEFAULT_DELAY); +} + +void +demo_rotate_display (void) +{ + for (uint8_t i = DISP_ORIENT_NORMAL; + i <= DISP_ORIENT_UPSIDE_DOWN_MIRRORED; ++i) + { + ssd1306_set_display_orientation (i); + ssd1306_write_image_fb (logo); + ssd1306_display_fb (); + _delay_ms (DEFAULT_DELAY); + } +} + +void +demo_invert_image () +{ + ssd1306_set_display_orientation (DISP_ORIENT_NORMAL); + for (uint8_t i = DISPLAY_MODE_NORMAL; i <= DISPLAY_MODE_INVERTED; ++i) + { + ssd1306_set_display_mode (i); + ssd1306_write_image_fb (logo); + ssd1306_display_fb (); + // Check inverted contrast works + demo_set_contrast (); + } +} + +int +main () +{ + spi_init (); + + /* + * Demonstrate the virtual part functionality. Runs approx 10 times + * faster on an i7-3740QM CPU @ 2.70GHz than in real life. + */ + for (;;) + { + ssd1306_init_display (); + + demo_show_image (); + demo_set_power_state (); + demo_set_contrast (); + demo_set_byte_direct (); + demo_set_pixels (); + demo_clear_screen (); + demo_rotate_display (); + demo_invert_image (); + } + +} diff --git a/examples/board_ssd1306/images.c b/examples/board_ssd1306/images.c new file mode 100644 index 0000000..354f62c --- /dev/null +++ b/examples/board_ssd1306/images.c @@ -0,0 +1,61 @@ +/* + images.c + + Copyright 2014 Doug Szumski + + This file is part of simavr. + + simavr is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + simavr is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with simavr. If not, see . + */ + +#include "images.h" + +/* 128x64 run length encoded simavr logo */ +const uint8_t logo[] PROGMEM = +{ + 0x0, 0x0, 0xff, 0x0, 0x0, 0x7, 0xfe, 0xfe, 0x4, 0xe, 0x6, 0x6, 0x8, 0xe, 0xfe, + 0xfe, 0x3, 0xfc, 0x0, 0x0, 0x5, 0x54, 0xfe, 0xfe, 0x2, 0x0, 0x0, + 0x3, 0xfe, 0xfe, 0x2, 0xff, 0x6, 0x1e, 0x7e, 0xfc, 0xe0, 0xc0, + 0x0, 0x80, 0xc0, 0xf0, 0x7c, 0x3e, 0xe, 0x5e, 0xff, 0xfe, 0xfe, + 0x2, 0xff, 0xfe, 0xfe, 0x2, 0x0, 0x0, 0x6, 0xfe, 0xfe, 0x3, 0x6, + 0x6, 0xa, 0x2e, 0xfe, 0xfe, 0x3, 0x0, 0x0, 0x2, 0xfe, 0xff, + 0xba, 0x0, 0x0, 0x7, 0xf4, 0xff, 0xff, 0x5, 0xfe, 0x0, 0x0, 0x2, + 0xfe, 0xff, 0xff, 0x2, 0xf, 0x7, 0x7, 0xa, 0xff, 0xff, 0x3, 0x0, + 0x0, 0xf, 0x7f, 0x7f, 0x4, 0x70, 0x60, 0x60, 0x8, 0xe0, 0xe0, + 0x2, 0xe1, 0xe1, 0x2, 0xc0, 0x0, 0x0, 0x2, 0x80, 0x80, 0x3, + 0xe5, 0xff, 0xff, 0x2, 0x0, 0x0, 0x3, 0xff, 0xff, 0x3, 0x0, 0x0, + 0x3, 0x1, 0x7, 0x1f, 0x1f, 0x2, 0xf, 0x7, 0x1, 0x0, 0x0, 0x3, + 0x55, 0xff, 0xff, 0x6, 0x0, 0x0, 0x2, 0x80, 0x80, 0x3, 0xc0, + 0xff, 0xff, 0x3, 0xf0, 0x60, 0x60, 0x8, 0xf0, 0xfd, 0xff, 0xff, + 0x3, 0x0, 0x0, 0x2, 0xff, 0xff, 0x2, 0xbb, 0x0, 0x0, 0x7, 0xf7, + 0xff, 0xff, 0x6, 0x0, 0x0, 0x2, 0xff, 0xff, 0x3, 0xf0, 0xf0, + 0x2, 0xe0, 0xe0, 0x3, 0x60, 0x60, 0x4, 0x70, 0xf0, 0xff, 0xff, + 0x3, 0xf8, 0xe0, 0xe0, 0x3, 0x0, 0x0, 0xb, 0xf0, 0xf8, 0xf8, + 0x5, 0xe0, 0x0, 0x0, 0x7, 0xff, 0xff, 0x4, 0x0, 0x0, 0x2, 0xff, + 0xff, 0x6, 0x0, 0x0, 0x3, 0xff, 0xff, 0x3, 0x0, 0x0, 0x3, 0x40, + 0xf8, 0xf8, 0x5, 0xf0, 0x0, 0x0, 0x3, 0xb5, 0xff, 0xff, 0x6, + 0x0, 0x0, 0x2, 0xff, 0xff, 0x7, 0x0, 0x0, 0xa, 0x77, 0xff, 0xff, + 0x3, 0x0, 0x0, 0x2, 0x7, 0x1f, 0x3f, 0xf8, 0xe0, 0xc0, 0x0, 0x0, + 0x4, 0xf7, 0xff, 0xff, 0x4, 0x7f, 0x3f, 0x0, 0x0, 0x2, 0xff, + 0xff, 0x7, 0x0, 0x0, 0x6, 0x1, 0xff, 0xff, 0x7, 0x0, 0x0, 0xb, + 0x7, 0xf, 0xf, 0x6, 0xe, 0xe, 0x7, 0xf, 0xf, 0x3, 0x7, 0x0, 0x0, + 0x2, 0xf, 0xf, 0x6, 0x0, 0x0, 0x3, 0xf, 0xf, 0x2, 0x7, 0x0, 0x0, + 0x3, 0x3, 0xf, 0xf, 0x6, 0x0, 0x0, 0x3, 0x2, 0xf, 0xf, 0x6, 0x0, + 0x0, 0x2, 0x7, 0xf, 0xf, 0x5, 0x7, 0x0, 0x0, 0xa, 0x3, 0xf, 0xf, + 0x3, 0x0, 0x0, 0x6, 0x3, 0x7, 0xf, 0xe, 0xe, 0x2, 0xf, 0x7, 0x3, + 0x3, 0x2, 0x1, 0x0, 0x0, 0x5, 0x7, 0xf, 0xf, 0x5, 0x7, 0x0, 0x0, + 0x7, 0x7, 0xf, 0xf, 0x5, 0x7, 0x0, 0x0, 0xff, 0x0, 0x0, 0x6 +}; + + diff --git a/examples/board_ssd1306/images.h b/examples/board_ssd1306/images.h new file mode 100644 index 0000000..3534ade --- /dev/null +++ b/examples/board_ssd1306/images.h @@ -0,0 +1,30 @@ +/* + images.h + + Copyright 2014 Doug Szumski + + This file is part of simavr. + + simavr is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + simavr is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with simavr. If not, see . + */ + +#ifndef IMAGES_H_ +#define IMAGES_H_ + +#include +#include + +extern const uint8_t logo[] PROGMEM; + +#endif /* IMAGES_H_ */ diff --git a/examples/board_ssd1306/ssd1306.c b/examples/board_ssd1306/ssd1306.c new file mode 100644 index 0000000..801a8cb --- /dev/null +++ b/examples/board_ssd1306/ssd1306.c @@ -0,0 +1,270 @@ +/* + ssd1306.c + + SSD1306 display driver (SPI mode) + + Copyright 2014 Doug Szumski + + Inspired by the work of Gabriel Anzziani. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + */ + +#include + +#include +#include +#include + +#include "ssd1306.h" + +uint8_t ssd1306_frame_buffer_g[SSD1306_PIXEL_PAGES][SSD1306_X_PIXELS]; + +void +ssd1306_reset_display (void) +{ + PORTB |= (1 << SSD1306_RESET_PIN); + _delay_us (3); + PORTB &= ~(1 << SSD1306_RESET_PIN); + _delay_us (3); + PORTB |= (1 << SSD1306_RESET_PIN); +} + +static inline void +ssd1306_tx_spi_byte(const uint8_t byte) +{ + SPDR = byte; + // Wait for transmission to complete + while (!(SPSR & (1 << SPIF))); +} + +void +ssd1306_write_data (const uint8_t byte) +{ + PORTB |= (1 << SSD1306_DATA_INST); + PORTB &= ~(1 << SSD1306_CHIP_SELECT); + ssd1306_tx_spi_byte(byte); + PORTB |= (1 << SSD1306_CHIP_SELECT); +} + +void +ssd1306_write_instruction (const uint8_t byte) +{ + PORTB &= ~((1 << SSD1306_DATA_INST) | (1 << SSD1306_CHIP_SELECT)); + ssd1306_tx_spi_byte(byte); + PORTB |= (1 << SSD1306_CHIP_SELECT); +} + +/* Initialise display mostly as per p64 of the datasheet */ +void +ssd1306_init_display (void) +{ + ssd1306_reset_display (); + + ssd1306_set_power_state (POWER_STATE_SLEEP); + + ssd1306_write_instruction (SSD1306_SET_MULTIPLEX_RATIO); + ssd1306_write_instruction (0x3F); + + ssd1306_write_instruction (SSD1306_SET_VERTICAL_OFFSET); + ssd1306_write_instruction (0x00); + + ssd1306_write_instruction (SSD1306_SET_DISP_START_LINE); + + ssd1306_set_display_orientation(DISP_ORIENT_NORMAL); + + ssd1306_write_instruction (SSD1306_SET_WIRING_SCHEME); + ssd1306_write_instruction (0x12); + + ssd1306_set_contrast (SSD1306_DEFAULT_CONTRAST); + + ssd1306_write_instruction (SSD1306_RESUME_TO_RAM_CONTENT); + + ssd1306_set_display_mode (DISPLAY_MODE_NORMAL); + + // Horizontal memory addressing mode + ssd1306_write_instruction (SSD1306_MEM_ADDRESSING); + ssd1306_write_instruction (0x00); + + ssd1306_write_instruction (SSD1306_SET_DISP_CLOCK); + ssd1306_write_instruction (0x80); + + ssd1306_write_instruction (SSD1306_CHARGE_PUMP_REGULATOR); + ssd1306_write_instruction (SSD1306_CHARGE_PUMP_ON); + + ssd1306_set_power_state (POWER_STATE_ON); +} + +void +ssd1306_set_display_orientation (const disp_orient_t disp_orient) +{ + switch (disp_orient) + { + case DISP_ORIENT_NORMAL: + ssd1306_write_instruction (SSD1306_SET_SEG_REMAP_0); + ssd1306_write_instruction (SSD1306_SET_COM_SCAN_NORMAL); + break; + case DISP_ORIENT_NORMAL_MIRRORED: + // The display is mirrored from the upper edge + ssd1306_write_instruction (SSD1306_SET_SEG_REMAP_0); + ssd1306_write_instruction (SSD1306_SET_COM_SCAN_INVERTED); + break; + case DISP_ORIENT_UPSIDE_DOWN: + ssd1306_write_instruction (SSD1306_SET_SEG_REMAP_127); + ssd1306_write_instruction (SSD1306_SET_COM_SCAN_INVERTED); + break; + case DISP_ORIENT_UPSIDE_DOWN_MIRRORED: + // The upside down display is mirrored from the upper edge + ssd1306_write_instruction (SSD1306_SET_SEG_REMAP_127); + ssd1306_write_instruction (SSD1306_SET_COM_SCAN_NORMAL); + break; + default: + break; + } +} + +/* Move the cursor to the start */ +static void +ssd1306_reset_cursor (void) +{ + ssd1306_write_instruction (SSD1306_SET_PAGE_START_ADDR); + ssd1306_write_instruction (SSD1306_SET_COL_HI_NIBBLE); + ssd1306_write_instruction (SSD1306_SET_COL_LO_NIBBLE); +} + +void +ssd1306_set_contrast (const uint8_t contrast) +{ + ssd1306_write_instruction (SSD1306_SET_CONTRAST); + ssd1306_write_instruction (contrast); +} + +void +ssd1306_set_display_mode(const display_mode_t display_mode) +{ + switch (display_mode) { + case DISPLAY_MODE_NORMAL: + ssd1306_write_instruction (SSD1306_DISP_NORMAL); + break; + case DISPLAY_MODE_INVERTED: + ssd1306_write_instruction (SSD1306_DISP_INVERTED); + break; + default: + ssd1306_write_instruction (SSD1306_DISP_NORMAL); + break; + } +} + +void +ssd1306_set_power_state (const power_state_t power_state) +{ + switch (power_state) + { + case POWER_STATE_ON: + ssd1306_write_instruction (SSD1306_DISP_ON); + break; + case POWER_STATE_SLEEP: + ssd1306_write_instruction (SSD1306_DISP_SLEEP); + break; + default: + break; + } +} + +void +ssd1306_write_byte (const uint8_t x, const uint8_t page, const uint8_t byte) +{ + ssd1306_write_instruction (SSD1306_SET_PAGE_START_ADDR | page); + ssd1306_write_instruction (SSD1306_SET_COL_LO_NIBBLE | (x & 0xF)); + ssd1306_write_instruction (SSD1306_SET_COL_HI_NIBBLE | (x >> 4)); + ssd1306_write_data(byte); +} + +void +ssd1306_clear_screen (void) +{ + ssd1306_reset_cursor (); + + for (uint16_t byte = 0; byte < SSD1306_PIXEL_BYTES; byte++) + { + ssd1306_write_data (0x00); + } +} + +/* Transfer display buffer to LCD */ +void +ssd1306_display_fb (void) +{ + ssd1306_reset_cursor (); + + for (uint8_t page = 0; page < SSD1306_PIXEL_PAGES; page++) + { + for (uint8_t column = 0; column < SSD1306_X_PIXELS; column++) + { + ssd1306_write_data (ssd1306_frame_buffer_g[page][column]); + } + } +} + +void +ssd1306_clear_fb (void) +{ + memset(ssd1306_frame_buffer_g, 0, SSD1306_PIXEL_BYTES); +} + +void +ssd1306_set_pixel_fb (const uint8_t x, const uint8_t y, const pixel_state_t pixel_state) +{ + switch (pixel_state) + { + case PIXEL_STATE_ON: + ssd1306_frame_buffer_g[y / SSD1306_PIXEL_PAGES][x] |= (1 << y % SSD1306_PIXEL_PAGES); + break; + case PIXEL_STATE_OFF: + ssd1306_frame_buffer_g[y / SSD1306_PIXEL_PAGES][x] &= ~(1 << y % SSD1306_PIXEL_PAGES); + break; + default: + break; + } +} + +/* Writes a run length encoded image to the display buffer */ +void +ssd1306_write_image_fb (const uint8_t * image) +{ + uint8_t image_byte = 0, next_image_byte, write_byte_count = 0; + + for (uint8_t page = 0; page < SSD1306_PIXEL_PAGES; page++) + { + for (uint8_t column = 0; column < SSD1306_X_PIXELS; column++) + { + if (!write_byte_count) + { + image_byte = pgm_read_byte_near (image++); + next_image_byte = pgm_read_byte_near (image++); + if (image_byte == next_image_byte) + { + write_byte_count = pgm_read_byte_near (image++); + } + else + { + write_byte_count = 1; + image--; + } + } + write_byte_count--; + ssd1306_frame_buffer_g[page][column] = image_byte; + } + } +} diff --git a/examples/board_ssd1306/ssd1306.h b/examples/board_ssd1306/ssd1306.h new file mode 100644 index 0000000..7860fa4 --- /dev/null +++ b/examples/board_ssd1306/ssd1306.h @@ -0,0 +1,139 @@ +/* + ssd1306.h + + SSD1306 display driver (SPI mode) + + Copyright 2014 Doug Szumski + + Inspired by the work of Gabriel Anzziani. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + */ + +#ifndef SSD1306_H +#define SSD1306_H + +#include + +// SPI pin config +#define SSD1306_RESET_PIN PB3 +#define SSD1306_DATA_INST PB1 +#define SSD1306_CHIP_SELECT PB4 + +#define SSD1306_X_PIXELS 128 +#define SSD1306_Y_PIXELS 64 +#define SSD1306_PIXEL_PAGES (SSD1306_Y_PIXELS / 8) +#define SSD1306_PIXEL_BYTES (SSD1306_X_PIXELS * SSD1306_PIXEL_PAGES) + + +// Default settings +#define SSD1306_DEFAULT_CONTRAST 0x7F + +// Fundamental commands +#define SSD1306_CHARGE_PUMP_REGULATOR 0x8D +#define SSD1306_CHARGE_PUMP_ON 0x14 +#define SSD1306_SET_CONTRAST 0x81 #define SSD1306_RESUME_TO_RAM_CONTENT 0xA4 +#define SSD1306_IGNORE_RAM_CONTENT 0xA5 +#define SSD1306_DISP_NORMAL 0xA6 +#define SSD1306_DISP_INVERTED 0xA7 +#define SSD1306_DISP_SLEEP 0xAE +#define SSD1306_DISP_ON 0xAF + +// Scroll commands +#define SSD1306_SCROLL_RIGHT 0x26 +#define SSD1306_SCROLL_LEFT 0x27 +#define SSD1306_SCROLL_VERTICAL_RIGHT 0x29 +#define SSD1306_SCROLL_VERTICAL_LEFT 0x2A +#define SSD1306_SCROLL_OFF 0x2E +#define SSD1306_SCROLL_ON 0x2F +#define SSD1306_VERT_SCROLL_AREA 0xA3 + +// Address setting commands +#define SSD1306_SET_COL_LO_NIBBLE 0x00 +#define SSD1306_SET_COL_HI_NIBBLE 0x10 +#define SSD1306_MEM_ADDRESSING 0x20 +#define SSD1306_SET_COL_ADDR 0x21 +#define SSD1306_SET_PAGE_ADDR 0x22 +#define SSD1306_SET_PAGE_START_ADDR 0xB0 + +// Hardware configuration +#define SSD1306_SET_DISP_START_LINE 0x40 +#define SSD1306_SET_SEG_REMAP_0 0xA0 #define SSD1306_SET_SEG_REMAP_127 0xA1 +#define SSD1306_SET_MULTIPLEX_RATIO 0xA8 +#define SSD1306_SET_COM_SCAN_NORMAL 0xC0 +#define SSD1306_SET_COM_SCAN_INVERTED 0xC8 +#define SSD1306_SET_VERTICAL_OFFSET 0xD3 +#define SSD1306_SET_WIRING_SCHEME 0xDA +#define SSD1306_SET_DISP_CLOCK 0xD5 +#define SSD1306_SET_PRECHARGE_PERIOD 0xD9 +#define SSD1306_SET_VCOM_DESELECT_LEVEL 0xDB +#define SSD1306_NOP 0xE3 + +typedef enum +{ + DISPLAY_MODE_NORMAL, DISPLAY_MODE_INVERTED +} display_mode_t; + +typedef enum +{ + POWER_STATE_SLEEP, POWER_STATE_ON +} power_state_t; + +typedef enum +{ + PIXEL_STATE_OFF, PIXEL_STATE_ON +} pixel_state_t; + +typedef enum +{ + DISP_ORIENT_NORMAL, + DISP_ORIENT_NORMAL_MIRRORED, + DISP_ORIENT_UPSIDE_DOWN, + DISP_ORIENT_UPSIDE_DOWN_MIRRORED +} disp_orient_t; + +extern uint8_t ssd1306_frame_buffer_g[SSD1306_PIXEL_PAGES][SSD1306_X_PIXELS]; + +void +ssd1306_write_data (const uint8_t); +void +ssd1306_write_instruction (const uint8_t); +void +ssd1306_reset_display (void); +void +ssd1306_init_display (void); +void +ssd1306_set_display_orientation (const disp_orient_t disp_orient); +void +ssd1306_set_contrast (const uint8_t contrast); +void +ssd1306_set_power_state (const power_state_t power_state); +void +ssd1306_set_display_mode (const display_mode_t display_mode); +void +ssd1306_write_byte (const uint8_t x, const uint8_t page, const uint8_t byte); +void +ssd1306_clear_screen (void); + +/* Frame buffer operations */ +void +ssd1306_display_fb (void); +void +ssd1306_set_pixel_fb (const uint8_t x, const uint8_t y, const pixel_state_t pixel_state); +void +ssd1306_clear_fb (void); +void +ssd1306_write_image_fb (const uint8_t * image); + +#endif diff --git a/examples/board_ssd1306/ssd1306demo.c b/examples/board_ssd1306/ssd1306demo.c new file mode 100644 index 0000000..fb729c5 --- /dev/null +++ b/examples/board_ssd1306/ssd1306demo.c @@ -0,0 +1,177 @@ +/* + charlcd.c + + Copyright Luki + Copyright 2011 Michel Pollet + Copyright 2014 Doug Szumski + + This file is part of simavr. + + simavr is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + simavr is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with simavr. If not, see . + */ + +#include +#include +#include + +#include "sim_avr.h" +#include "avr_ioport.h" +#include "sim_elf.h" +#include "sim_gdb.h" +#include "sim_vcd_file.h" + +#if __APPLE__ +#include +#else +#include +#endif + +#include + +#include "ac_input.h" +#include "ssd1306_glut.h" + +int window_identifier; + +avr_t * avr = NULL; +avr_vcd_t vcd_file; +ac_input_t ac_input; +ssd1306_t ssd1306; + +static void * +avr_run_thread (void * ignore) +{ + while (1) + { + avr_run (avr); + } + return NULL; +} + +/* Called on a key press */ +void +keyCB (unsigned char key, int x, int y) +{ + switch (key) + { + case 'q': + exit (0); + break; + } +} + +/* Function called whenever redisplay needed */ +void +displayCB (void) +{ + glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + // Select modelview matrix + glMatrixMode (GL_MODELVIEW); + glPushMatrix (); + // Start with an identity matrix + glLoadIdentity (); + ssd1306_gl_draw (&ssd1306); + glPopMatrix (); + glutSwapBuffers (); +} + +// gl timer. if the lcd is dirty, refresh display +void +timerCB (int i) +{ + // restart timer + glutTimerFunc (1000 / 64, timerCB, 0); + glutPostRedisplay (); +} + +int +initGL (int w, int h, float pix_size) +{ + w *= pix_size; + h *= pix_size; + + // Double buffered, RGB disp mode. + glutInitDisplayMode (GLUT_RGB | GLUT_DOUBLE); + glutInitWindowSize (w * 4, h * 4); + window_identifier = glutCreateWindow ("SSD1306 128x64 OLED"); + + // Set up projection matrix + glMatrixMode (GL_PROJECTION); + // Start with an identity matrix + glLoadIdentity (); + glOrtho (0, w, 0, h, 0, 10); + glScalef (1, -1, 1); + glTranslatef (0, -1 * h, 0); + + // Set window's display callback + glutDisplayFunc (displayCB); + // Set window's key callback + glutKeyboardFunc (keyCB); + + glutTimerFunc (1000 / 24, timerCB, 0); + + ssd1306_gl_init (pix_size, SSD1306_GL_WHITE); + + return 1; +} + +int +main (int argc, char *argv[]) +{ + elf_firmware_t f; + const char * fname = "atmega32_ssd1306.axf"; + char path[256]; + sprintf (path, "%s/%s", dirname (argv[0]), fname); + printf ("Firmware pathname is %s\n", path); + elf_read_firmware (fname, &f); + + printf ("firmware %s f=%d mmcu=%s\n", fname, (int) f.frequency, f.mmcu); + + avr = avr_make_mcu_by_name (f.mmcu); + if (!avr) + { + fprintf (stderr, "%s: AVR '%s' not known\n", argv[0], f.mmcu); + exit (1); + } + + avr_init (avr); + avr_load_firmware (avr, &f); + ac_input_init (avr, &ac_input); + + ssd1306_init (avr, &ssd1306, 128, 64); + + // SSD1306 wired to the SPI bus, with the following additional pins: + ssd1306_wiring_t wiring = + { + .chip_select.port = 'B', + .chip_select.pin = 4, + .data_instruction.port = 'B', + .data_instruction.pin = 1, + .reset.port = 'B', + .reset.pin = 3, + }; + + ssd1306_connect (&ssd1306, &wiring); + + printf ("SSD1306 display demo\n Press 'q' to quit\n"); + + // Initialize GLUT system + glutInit (&argc, argv); + initGL (ssd1306.columns, ssd1306.rows, 0.5); + + pthread_t run; + pthread_create (&run, NULL, avr_run_thread, NULL); + + glutMainLoop (); +}