--- /dev/null
+#
+# Copyright 2008-2011 Michel Pollet <buserror@gmail.com>
+#
+# 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 <http://www.gnu.org/licenses/>.
+
+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
--- /dev/null
+board_ssd1306
+
+(C) 2014 Doug Szumski <d.s.szumski@gmail.com>
+
+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
--- /dev/null
+/*
+ atmega32_ssd1306.c
+
+ Copyright 2014 Doug Szumski <d.s.szumski@gmail.com>
+
+ 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <avr/io.h>
+#include <util/delay.h>
+
+#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 ();
+ }
+
+}
--- /dev/null
+/*
+ images.c
+
+ Copyright 2014 Doug Szumski <d.s.szumski@gmail.com>
+
+ 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 <http://www.gnu.org/licenses/>.
+ */
+
+#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
+};
+
+
--- /dev/null
+/*
+ images.h
+
+ Copyright 2014 Doug Szumski <d.s.szumski@gmail.com>
+
+ 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef IMAGES_H_
+#define IMAGES_H_
+
+#include <stdint.h>
+#include <avr/pgmspace.h>
+
+extern const uint8_t logo[] PROGMEM;
+
+#endif /* IMAGES_H_ */
--- /dev/null
+/*\r
+ ssd1306.c\r
+\r
+ SSD1306 display driver (SPI mode)\r
+\r
+ Copyright 2014 Doug Szumski <d.s.szumski@gmail.com>\r
+\r
+ Inspired by the work of Gabriel Anzziani.\r
+\r
+ This program is free software: you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation, either version 3 of the License, or\r
+ (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program. If not, see <http://www.gnu.org/licenses/>\r
+ */\r
+\r
+#include <string.h>\r
+\r
+#include <avr/pgmspace.h>\r
+#include <avr/io.h>\r
+#include <util/delay.h>\r
+\r
+#include "ssd1306.h"\r
+\r
+uint8_t ssd1306_frame_buffer_g[SSD1306_PIXEL_PAGES][SSD1306_X_PIXELS];\r
+\r
+void\r
+ssd1306_reset_display (void)\r
+{\r
+ PORTB |= (1 << SSD1306_RESET_PIN);\r
+ _delay_us (3);\r
+ PORTB &= ~(1 << SSD1306_RESET_PIN);\r
+ _delay_us (3);\r
+ PORTB |= (1 << SSD1306_RESET_PIN);\r
+}\r
+\r
+static inline void\r
+ssd1306_tx_spi_byte(const uint8_t byte)\r
+{\r
+ SPDR = byte;\r
+ // Wait for transmission to complete\r
+ while (!(SPSR & (1 << SPIF)));\r
+}\r
+\r
+void\r
+ssd1306_write_data (const uint8_t byte)\r
+{\r
+ PORTB |= (1 << SSD1306_DATA_INST);\r
+ PORTB &= ~(1 << SSD1306_CHIP_SELECT);\r
+ ssd1306_tx_spi_byte(byte);\r
+ PORTB |= (1 << SSD1306_CHIP_SELECT);\r
+}\r
+\r
+void\r
+ssd1306_write_instruction (const uint8_t byte)\r
+{\r
+ PORTB &= ~((1 << SSD1306_DATA_INST) | (1 << SSD1306_CHIP_SELECT));\r
+ ssd1306_tx_spi_byte(byte);\r
+ PORTB |= (1 << SSD1306_CHIP_SELECT);\r
+}\r
+\r
+/* Initialise display mostly as per p64 of the datasheet */\r
+void\r
+ssd1306_init_display (void)\r
+{\r
+ ssd1306_reset_display ();\r
+\r
+ ssd1306_set_power_state (POWER_STATE_SLEEP);\r
+\r
+ ssd1306_write_instruction (SSD1306_SET_MULTIPLEX_RATIO);\r
+ ssd1306_write_instruction (0x3F);\r
+\r
+ ssd1306_write_instruction (SSD1306_SET_VERTICAL_OFFSET);\r
+ ssd1306_write_instruction (0x00);\r
+\r
+ ssd1306_write_instruction (SSD1306_SET_DISP_START_LINE);\r
+\r
+ ssd1306_set_display_orientation(DISP_ORIENT_NORMAL);\r
+\r
+ ssd1306_write_instruction (SSD1306_SET_WIRING_SCHEME);\r
+ ssd1306_write_instruction (0x12);\r
+\r
+ ssd1306_set_contrast (SSD1306_DEFAULT_CONTRAST);\r
+\r
+ ssd1306_write_instruction (SSD1306_RESUME_TO_RAM_CONTENT);\r
+\r
+ ssd1306_set_display_mode (DISPLAY_MODE_NORMAL);\r
+\r
+ // Horizontal memory addressing mode\r
+ ssd1306_write_instruction (SSD1306_MEM_ADDRESSING);\r
+ ssd1306_write_instruction (0x00);\r
+\r
+ ssd1306_write_instruction (SSD1306_SET_DISP_CLOCK);\r
+ ssd1306_write_instruction (0x80);\r
+\r
+ ssd1306_write_instruction (SSD1306_CHARGE_PUMP_REGULATOR);\r
+ ssd1306_write_instruction (SSD1306_CHARGE_PUMP_ON);\r
+\r
+ ssd1306_set_power_state (POWER_STATE_ON);\r
+}\r
+\r
+void\r
+ssd1306_set_display_orientation (const disp_orient_t disp_orient)\r
+{\r
+ switch (disp_orient)\r
+ {\r
+ case DISP_ORIENT_NORMAL:\r
+ ssd1306_write_instruction (SSD1306_SET_SEG_REMAP_0);\r
+ ssd1306_write_instruction (SSD1306_SET_COM_SCAN_NORMAL);\r
+ break;\r
+ case DISP_ORIENT_NORMAL_MIRRORED:\r
+ // The display is mirrored from the upper edge\r
+ ssd1306_write_instruction (SSD1306_SET_SEG_REMAP_0);\r
+ ssd1306_write_instruction (SSD1306_SET_COM_SCAN_INVERTED);\r
+ break;\r
+ case DISP_ORIENT_UPSIDE_DOWN:\r
+ ssd1306_write_instruction (SSD1306_SET_SEG_REMAP_127);\r
+ ssd1306_write_instruction (SSD1306_SET_COM_SCAN_INVERTED);\r
+ break;\r
+ case DISP_ORIENT_UPSIDE_DOWN_MIRRORED:\r
+ // The upside down display is mirrored from the upper edge\r
+ ssd1306_write_instruction (SSD1306_SET_SEG_REMAP_127);\r
+ ssd1306_write_instruction (SSD1306_SET_COM_SCAN_NORMAL);\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
+}\r
+\r
+/* Move the cursor to the start */\r
+static void\r
+ssd1306_reset_cursor (void)\r
+{\r
+ ssd1306_write_instruction (SSD1306_SET_PAGE_START_ADDR);\r
+ ssd1306_write_instruction (SSD1306_SET_COL_HI_NIBBLE);\r
+ ssd1306_write_instruction (SSD1306_SET_COL_LO_NIBBLE);\r
+}\r
+\r
+void\r
+ssd1306_set_contrast (const uint8_t contrast)\r
+{\r
+ ssd1306_write_instruction (SSD1306_SET_CONTRAST);\r
+ ssd1306_write_instruction (contrast);\r
+}\r
+\r
+void\r
+ssd1306_set_display_mode(const display_mode_t display_mode)\r
+{\r
+ switch (display_mode) {\r
+ case DISPLAY_MODE_NORMAL:\r
+ ssd1306_write_instruction (SSD1306_DISP_NORMAL);\r
+ break;\r
+ case DISPLAY_MODE_INVERTED:\r
+ ssd1306_write_instruction (SSD1306_DISP_INVERTED);\r
+ break;\r
+ default:\r
+ ssd1306_write_instruction (SSD1306_DISP_NORMAL);\r
+ break;\r
+ }\r
+}\r
+\r
+void\r
+ssd1306_set_power_state (const power_state_t power_state)\r
+{\r
+ switch (power_state)\r
+ {\r
+ case POWER_STATE_ON:\r
+ ssd1306_write_instruction (SSD1306_DISP_ON);\r
+ break;\r
+ case POWER_STATE_SLEEP:\r
+ ssd1306_write_instruction (SSD1306_DISP_SLEEP);\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
+}\r
+\r
+void\r
+ssd1306_write_byte (const uint8_t x, const uint8_t page, const uint8_t byte)\r
+{\r
+ ssd1306_write_instruction (SSD1306_SET_PAGE_START_ADDR | page);\r
+ ssd1306_write_instruction (SSD1306_SET_COL_LO_NIBBLE | (x & 0xF));\r
+ ssd1306_write_instruction (SSD1306_SET_COL_HI_NIBBLE | (x >> 4));\r
+ ssd1306_write_data(byte);\r
+}\r
+\r
+void\r
+ssd1306_clear_screen (void)\r
+{\r
+ ssd1306_reset_cursor ();\r
+\r
+ for (uint16_t byte = 0; byte < SSD1306_PIXEL_BYTES; byte++)\r
+ {\r
+ ssd1306_write_data (0x00);\r
+ }\r
+}\r
+\r
+/* Transfer display buffer to LCD */\r
+void\r
+ssd1306_display_fb (void)\r
+{\r
+ ssd1306_reset_cursor ();\r
+\r
+ for (uint8_t page = 0; page < SSD1306_PIXEL_PAGES; page++)\r
+ {\r
+ for (uint8_t column = 0; column < SSD1306_X_PIXELS; column++)\r
+ {\r
+ ssd1306_write_data (ssd1306_frame_buffer_g[page][column]);\r
+ }\r
+ }\r
+}\r
+\r
+void\r
+ssd1306_clear_fb (void)\r
+{\r
+ memset(ssd1306_frame_buffer_g, 0, SSD1306_PIXEL_BYTES);\r
+}\r
+\r
+void\r
+ssd1306_set_pixel_fb (const uint8_t x, const uint8_t y, const pixel_state_t pixel_state)\r
+{\r
+ switch (pixel_state)\r
+ {\r
+ case PIXEL_STATE_ON:\r
+ ssd1306_frame_buffer_g[y / SSD1306_PIXEL_PAGES][x] |= (1 << y % SSD1306_PIXEL_PAGES);\r
+ break;\r
+ case PIXEL_STATE_OFF:\r
+ ssd1306_frame_buffer_g[y / SSD1306_PIXEL_PAGES][x] &= ~(1 << y % SSD1306_PIXEL_PAGES);\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
+}\r
+\r
+/* Writes a run length encoded image to the display buffer */\r
+void\r
+ssd1306_write_image_fb (const uint8_t * image)\r
+{\r
+ uint8_t image_byte = 0, next_image_byte, write_byte_count = 0;\r
+\r
+ for (uint8_t page = 0; page < SSD1306_PIXEL_PAGES; page++)\r
+ {\r
+ for (uint8_t column = 0; column < SSD1306_X_PIXELS; column++)\r
+ {\r
+ if (!write_byte_count)\r
+ {\r
+ image_byte = pgm_read_byte_near (image++);\r
+ next_image_byte = pgm_read_byte_near (image++);\r
+ if (image_byte == next_image_byte)\r
+ {\r
+ write_byte_count = pgm_read_byte_near (image++);\r
+ }\r
+ else\r
+ {\r
+ write_byte_count = 1;\r
+ image--;\r
+ }\r
+ }\r
+ write_byte_count--;\r
+ ssd1306_frame_buffer_g[page][column] = image_byte;\r
+ }\r
+ }\r
+}\r
--- /dev/null
+/*\r
+ ssd1306.h\r
+\r
+ SSD1306 display driver (SPI mode)\r
+\r
+ Copyright 2014 Doug Szumski <d.s.szumski@gmail.com>\r
+\r
+ Inspired by the work of Gabriel Anzziani.\r
+\r
+ This program is free software: you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation, either version 3 of the License, or\r
+ (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program. If not, see <http://www.gnu.org/licenses/>\r
+ */\r
+\r
+#ifndef SSD1306_H\r
+#define SSD1306_H\r
+\r
+#include <stdint.h>\r
+\r
+// SPI pin config\r
+#define SSD1306_RESET_PIN PB3\r
+#define SSD1306_DATA_INST PB1\r
+#define SSD1306_CHIP_SELECT PB4\r
+\r
+#define SSD1306_X_PIXELS 128\r
+#define SSD1306_Y_PIXELS 64\r
+#define SSD1306_PIXEL_PAGES (SSD1306_Y_PIXELS / 8)\r
+#define SSD1306_PIXEL_BYTES (SSD1306_X_PIXELS * SSD1306_PIXEL_PAGES)\r
+\r
+\r
+// Default settings\r
+#define SSD1306_DEFAULT_CONTRAST 0x7F\r
+\r
+// Fundamental commands\r
+#define SSD1306_CHARGE_PUMP_REGULATOR 0x8D\r
+#define SSD1306_CHARGE_PUMP_ON 0x14\r
+#define SSD1306_SET_CONTRAST 0x81\r#define SSD1306_RESUME_TO_RAM_CONTENT 0xA4\r
+#define SSD1306_IGNORE_RAM_CONTENT 0xA5\r
+#define SSD1306_DISP_NORMAL 0xA6\r
+#define SSD1306_DISP_INVERTED 0xA7\r
+#define SSD1306_DISP_SLEEP 0xAE\r
+#define SSD1306_DISP_ON 0xAF\r
+\r
+// Scroll commands\r
+#define SSD1306_SCROLL_RIGHT 0x26\r
+#define SSD1306_SCROLL_LEFT 0x27\r
+#define SSD1306_SCROLL_VERTICAL_RIGHT 0x29\r
+#define SSD1306_SCROLL_VERTICAL_LEFT 0x2A\r
+#define SSD1306_SCROLL_OFF 0x2E\r
+#define SSD1306_SCROLL_ON 0x2F\r
+#define SSD1306_VERT_SCROLL_AREA 0xA3\r
+\r
+// Address setting commands\r
+#define SSD1306_SET_COL_LO_NIBBLE 0x00\r
+#define SSD1306_SET_COL_HI_NIBBLE 0x10\r
+#define SSD1306_MEM_ADDRESSING 0x20\r
+#define SSD1306_SET_COL_ADDR 0x21\r
+#define SSD1306_SET_PAGE_ADDR 0x22\r
+#define SSD1306_SET_PAGE_START_ADDR 0xB0\r
+\r
+// Hardware configuration\r
+#define SSD1306_SET_DISP_START_LINE 0x40\r
+#define SSD1306_SET_SEG_REMAP_0 0xA0\r#define SSD1306_SET_SEG_REMAP_127 0xA1\r
+#define SSD1306_SET_MULTIPLEX_RATIO 0xA8\r
+#define SSD1306_SET_COM_SCAN_NORMAL 0xC0\r
+#define SSD1306_SET_COM_SCAN_INVERTED 0xC8\r
+#define SSD1306_SET_VERTICAL_OFFSET 0xD3\r
+#define SSD1306_SET_WIRING_SCHEME 0xDA\r
+#define SSD1306_SET_DISP_CLOCK 0xD5\r
+#define SSD1306_SET_PRECHARGE_PERIOD 0xD9\r
+#define SSD1306_SET_VCOM_DESELECT_LEVEL 0xDB\r
+#define SSD1306_NOP 0xE3\r
+\r
+typedef enum\r
+{\r
+ DISPLAY_MODE_NORMAL, DISPLAY_MODE_INVERTED\r
+} display_mode_t;\r
+\r
+typedef enum\r
+{\r
+ POWER_STATE_SLEEP, POWER_STATE_ON\r
+} power_state_t;\r
+\r
+typedef enum\r
+{\r
+ PIXEL_STATE_OFF, PIXEL_STATE_ON\r
+} pixel_state_t;\r
+\r
+typedef enum\r
+{\r
+ DISP_ORIENT_NORMAL,\r
+ DISP_ORIENT_NORMAL_MIRRORED,\r
+ DISP_ORIENT_UPSIDE_DOWN,\r
+ DISP_ORIENT_UPSIDE_DOWN_MIRRORED\r
+} disp_orient_t;\r
+\r
+extern uint8_t ssd1306_frame_buffer_g[SSD1306_PIXEL_PAGES][SSD1306_X_PIXELS];\r
+\r
+void\r
+ssd1306_write_data (const uint8_t);\r
+void\r
+ssd1306_write_instruction (const uint8_t);\r
+void\r
+ssd1306_reset_display (void);\r
+void\r
+ssd1306_init_display (void);\r
+void\r
+ssd1306_set_display_orientation (const disp_orient_t disp_orient);\r
+void\r
+ssd1306_set_contrast (const uint8_t contrast);\r
+void\r
+ssd1306_set_power_state (const power_state_t power_state);\r
+void\r
+ssd1306_set_display_mode (const display_mode_t display_mode);\r
+void\r
+ssd1306_write_byte (const uint8_t x, const uint8_t page, const uint8_t byte);\r
+void\r
+ssd1306_clear_screen (void);\r
+\r
+/* Frame buffer operations */\r
+void\r
+ssd1306_display_fb (void);\r
+void\r
+ssd1306_set_pixel_fb (const uint8_t x, const uint8_t y, const pixel_state_t pixel_state);\r
+void\r
+ssd1306_clear_fb (void);\r
+void\r
+ssd1306_write_image_fb (const uint8_t * image);\r
+\r
+#endif\r
--- /dev/null
+/*
+ charlcd.c
+
+ Copyright Luki <humbell@ethz.ch>
+ Copyright 2011 Michel Pollet <buserror@gmail.com>
+ Copyright 2014 Doug Szumski <d.s.szumski@gmail.com>
+
+ 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <libgen.h>
+
+#include "sim_avr.h"
+#include "avr_ioport.h"
+#include "sim_elf.h"
+#include "sim_gdb.h"
+#include "sim_vcd_file.h"
+
+#if __APPLE__
+#include <GLUT/glut.h>
+#else
+#include <GL/glut.h>
+#endif
+
+#include <pthread.h>
+
+#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 ();
+}