Commit 318d3ab8ea77206a97a46c740716d083cc5e149e
authorDoug Szumski <d.s.szumski@gmail.com>
Tue, 5 Aug 2014 10:49:30 +0000 (11:49 +0100)
committerDoug Szumski <d.s.szumski@gmail.com>
Tue, 5 Aug 2014 11:01:12 +0000 (12:01 +0100)
atmega32_ssd1306.c  Example avr firmware
ssd1306.* SSD1306 avr driver
images.* simavr logo used in example firmware
ssd1306demo.c simavr demo for ssd1306 part

8 files changed:
examples/board_ssd1306/Makefile [new file with mode: 0644]
examples/board_ssd1306/README [new file with mode: 0644]
examples/board_ssd1306/atmega32_ssd1306.c [new file with mode: 0644]
examples/board_ssd1306/images.c [new file with mode: 0644]
examples/board_ssd1306/images.h [new file with mode: 0644]
examples/board_ssd1306/ssd1306.c [new file with mode: 0644]
examples/board_ssd1306/ssd1306.h [new file with mode: 0644]
examples/board_ssd1306/ssd1306demo.c [new file with mode: 0644]

diff --git a/examples/board_ssd1306/Makefile b/examples/board_ssd1306/Makefile
new file mode 100644 (file)
index 0000000..985f1ea
--- /dev/null
@@ -0,0 +1,55 @@
+# 
+#      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
diff --git a/examples/board_ssd1306/README b/examples/board_ssd1306/README
new file mode 100644 (file)
index 0000000..5a3096d
--- /dev/null
@@ -0,0 +1,10 @@
+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
diff --git a/examples/board_ssd1306/atmega32_ssd1306.c b/examples/board_ssd1306/atmega32_ssd1306.c
new file mode 100644 (file)
index 0000000..bf9cc25
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ 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 ();
+       }
+
+}
diff --git a/examples/board_ssd1306/images.c b/examples/board_ssd1306/images.c
new file mode 100644 (file)
index 0000000..354f62c
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ 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
+};
+
+
diff --git a/examples/board_ssd1306/images.h b/examples/board_ssd1306/images.h
new file mode 100644 (file)
index 0000000..3534ade
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ 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_ */
diff --git a/examples/board_ssd1306/ssd1306.c b/examples/board_ssd1306/ssd1306.c
new file mode 100644 (file)
index 0000000..801a8cb
--- /dev/null
@@ -0,0 +1,270 @@
+/*\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
diff --git a/examples/board_ssd1306/ssd1306.h b/examples/board_ssd1306/ssd1306.h
new file mode 100644 (file)
index 0000000..7860fa4
--- /dev/null
@@ -0,0 +1,139 @@
+/*\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
diff --git a/examples/board_ssd1306/ssd1306demo.c b/examples/board_ssd1306/ssd1306demo.c
new file mode 100644 (file)
index 0000000..fb729c5
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ 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 ();
+}