This commit is contained in:
2022-10-30 23:00:53 +01:00
commit 7f087ae854
226 changed files with 27881 additions and 0 deletions
+47
View File
@@ -0,0 +1,47 @@
# MIT License
#
# Copyright (c) 2018, Alexey Dynda
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
#################################################################
# Makefile to build ssd1306 library for AVR controllers
#
# Accept the following parameters:
# CC
# CXX
# STRIP
# AR
# MCU
# FREQUENCY
CC = avr-gcc
CXX = avr-g++
STRIP = avr-strip
AR = avr-ar
MCU ?= atmega328p
FREQUENCY ?= 16000000
CCFLAGS += -mmcu=$(MCU) -DF_CPU=$(FREQUENCY) -Wno-array-bounds
ifeq ($(ADAFRUIT),y)
INCLUDES += -I./ssd1306_hal/avr/arduino
endif
include Makefile.common
+107
View File
@@ -0,0 +1,107 @@
# MIT License
#
# Copyright (c) 2018, Alexey Dynda
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
#################################################################
# Makefile containing common logic for all systems
#
# Accepts the following parameters:
# CC
# CXX
# STRIP
# AR
default: all
DESTDIR ?=
BLD ?= ../bld
BACKSLASH?=/
MKDIR?=mkdir -p
convert=$(subst /,$(BACKSLASH),$1)
.SUFFIXES: .c .cpp .ino
$(BLD)/%.o: %.c
-$(MKDIR) $(call convert,$(dir $@))
$(CC) -std=gnu11 $(CCFLAGS) -c $< -o $@
$(BLD)/%.o: %.ino
-$(MKDIR) $(call convert,$(dir $@))
$(CXX) -std=c++11 $(CCFLAGS) $(CXXFLAGS) $(CCFLAGS-$(basename $(notdir $@))) -x c++ -c $< -o $@
$(BLD)/%.o: %.cpp
-$(MKDIR) $(call convert,$(dir $@))
$(CXX) -std=c++11 $(CCFLAGS) $(CXXFLAGS) $(CCFLAGS-$(basename $(notdir $@))) -c $< -o $@
################ OPTIONS ##########################
ifeq ($(ADAFRUIT),y)
ADAFRUIT_DIR ?= $(shell readlink -f ~)/Arduino/libraries/Adafruit_GFX_Library
INCLUDES += -I$(ADAFRUIT_DIR) \
# -I$(shell readlink -f ../src)/ssd1306_hal/linux/arduino
CCFLAGS-Adafruit_GFX= -DARDUINO=100
SRCS += \
$(ADAFRUIT_DIR)/Adafruit_GFX.cpp
endif
# ************* Common defines ********************
INCLUDES += \
-I.
CCFLAGS += -MD -g -Os $(INCLUDES) -Wall -Werror -ffunction-sections -fdata-sections \
-fno-exceptions
CXXFLAGS += -fno-rtti
ifeq ($(SDL_EMULATION),y)
CCFLAGS += -DSDL_EMULATION -I../tools/sdl
endif
.PHONY: clean ssd1306 all help
include Makefile.src
####################### Compiling library #########################
$(BLD)/libssd1306.a: $(OBJS)
$(AR) rcs $@ $(OBJS)
ssd1306: $(BLD)/libssd1306.a
all: ssd1306
clean:
rm -rf $(BLD)
help:
@echo "Makefile accepts the following options:"
@echo " ADAFRUIT=y/n Enables compilation of Adafruit GFX library"
@echo " ADAFRUIT_DIR=path Path to Adafruit GFX library"
@echo " SDL_EMULATION=y/n Enables SDL emulator in the library"
@echo " FREQUENCY=N Frequency in Hz"
@echo " MCU=mcu_code Specifies MCU to compile for (valid for AVR)"
-include $(OBJS:%.o=%.d)
+4
View File
@@ -0,0 +1,4 @@
# NO MAKEFILE REQUIRED FOR ENERGIA PLATFORM
#
# For using ssd1306 library just copy it to the libraries folder
# located in the Energia folder in Documents.
+5
View File
@@ -0,0 +1,5 @@
# NO MAKEFILE REQUIRED FOR ESP32 IDF platform, as Makefile.esp32 in examples
# generates all required mk file to compile sketches and library.
#
# For using ssd1306 library as IDF component module, there is component.mk,
# located in root folder of ssd1306 library
+38
View File
@@ -0,0 +1,38 @@
# MIT License
#
# Copyright (c) 2018, Alexey Dynda
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
#################################################################
# Makefile to build ssd1306 library for AVR controllers
#
# Accept the following parameters:
# CC
# CXX
# STRIP
# AR
# MCU
# FREQUENCY
ifeq ($(ADAFRUIT),y)
INCLUDES += -I./ssd1306_hal/linux/arduino
endif
include Makefile.common
+42
View File
@@ -0,0 +1,42 @@
# MIT License
#
# Copyright (c) 2018, Alexey Dynda
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
#################################################################
# Makefile to build ssd1306 library for AVR controllers
#
# Accept the following parameters:
# CC
# CXX
# STRIP
# AR
# MCU
# FREQUENCY
CC=gcc
MKDIR=mkdir
BACKSLASH=\\
ifeq ($(ADAFRUIT),y)
INCLUDES += -I./ssd1306_hal/mingw/arduino
endif
include Makefile.common
+80
View File
@@ -0,0 +1,80 @@
# MIT License
#
# Copyright (c) 2018-2019, Alexey Dynda
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
SRCS_C = \
ssd1306_fonts.c \
ssd1306_generic.c \
ssd1306_1bit.c \
ssd1306_8bit.c \
ssd1306_16bit.c \
ssd1306_menu.c \
ssd1306_hal/avr/platform.c \
ssd1306_hal/linux/platform.c \
ssd1306_hal/mingw/platform.c \
ssd1306_hal/stm32/platform.c \
ssd1306_hal/template/platform.c \
intf/i2c/ssd1306_i2c.c \
intf/i2c/ssd1306_i2c_embedded.c \
intf/i2c/ssd1306_i2c_twi.c \
intf/spi/ssd1306_spi.c \
intf/spi/ssd1306_spi_avr.c \
intf/spi/ssd1306_spi_usi.c \
intf/ssd1306_interface.c \
intf/uart/ssd1306_uart_builtin.c \
lcd/lcd_common.c \
lcd/lcd_pcd8544.c \
lcd/lcd_il9163.c \
lcd/lcd_ili9341.c \
lcd/oled_sh1106.c \
lcd/oled_ssd1306.c \
lcd/oled_ssd1325.c \
lcd/oled_ssd1327.c \
lcd/oled_ssd1331.c \
lcd/oled_ssd1351.c \
lcd/oled_template.c \
lcd/vga_monitor.c \
intf/vga/vga.c \
intf/vga/atmega328p/vga128x64.c \
intf/vga/atmega328p/vga96x40.c \
ssd1306_uart.c \
SRCS_CPP = \
nano_engine/canvas.cpp \
nano_engine/core.cpp \
nano_gfx.cpp \
sprite_pool.cpp \
ssd1306_console.cpp \
ssd1306_hal/arduino/platform.cpp \
ssd1306_hal/energia/platform.cpp \
intf/vga/esp32/vga128x64.cpp \
intf/vga/esp32/CompositeOutput.cpp \
SRCS = $(SRCS_C) $(SRCS_CPP)
# Due to absence of Print class tiny_ssd1306.cpp cannot be compiled without Arduino libs.
# tiny_ssd1306.cpp \
OBJS_C = $(addprefix src/, $(addsuffix .o, $(basename $(SRCS_C))))
OBJS = $(addprefix $(BLD)/, $(addsuffix .o, $(basename $(SRCS))))
+49
View File
@@ -0,0 +1,49 @@
# MIT License
#
# Copyright (c) 2018, Alexey Dynda
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
#################################################################
# Makefile to build ssd1306 library for STM32 controllers
#
# Accept the following parameters:
# CC
# CXX
# STRIP
# AR
# MCU
# FREQUENCY
CC = arm-none-eabi-gcc
CXX = arm-none-eabi-g++
STRIP = arm-none-eabi-strip
AR = arm-none-eabi-ar
CORE ?= cortex-m3
MCU ?= stm32f4x
FREQUENCY ?= 16000000
CCFLAGS += -DSTM32F4
CCFLAGS += -mlittle-endian -mthumb -mthumb-interwork -mcpu=$(CORE) -DF_CPU=$(FREQUENCY)
ifeq ($(ADAFRUIT),y)
INCLUDES += -I./ssd1306_hal/avr/arduino
endif
include Makefile.common
+169
View File
@@ -0,0 +1,169 @@
# ssd1306 library introduction # {#index}
***
[tocstart]: # (toc start)
* [Introduction](#introduction)
* [Key Features](#key-features)
* [Supported displays](#supported-displays)
* [Supported platforms](#supported-platforms)
* [Setting up](#setting-up)
* [License](#license)
[tocend]: # (toc end)
<a name="introduction"></a>
## Introduction
SSD1306 driver is Arduino style C/C++ library with unicode support. The library can be compiled for plain Linux
(for example, raspberry spi), or you can use it with plain avr-gcc compiler without Arduino IDE, or with
ESP32 IDF. It supports monochrome and RGB oleds and has debug mode, allowing to execute code on PC, using SDL2.0.
Initially the library is intended for very small microcontrollers (with a little of RAM). It was developed to use as
few resources as possible, but still has powerful capabilities, allowing to develop nice animation.
It works on any powerful devices like raspberry pi, esp32; and can be easily ported to new platform.
Since ssd1306 library supports different display types: monochrome, 8-bit color, 16-bit color displays, -
there are several group of API functions:
* Generic API functions (font specific, cursor positioning, menu implementation)
* 1-bit API functions for monochrome displays (these ones can be used both for color and mono lcd)
* 8-bit API functions for color displays (these ones work only for color displays)
* 16-bit API functions for color displays (only color displays)
Also, for graphics animation there special C++ API, called [Nano Engine](nano_engine/README.md).
<a name="key-features"></a>
## Key Features
* Supports color, monochrome OLED displays, and VGA monitor
* The library has modular structure, and some modules can be excluded from compilation at all to reduce flash usage.
* Needs very little RAM (Attiny85 with Damellis package needs minimum 25 bytes of RAM to communicate with OLED)
* Fast implementation to provide reasonable speed on slow microcontrollers
* Supports i2c and spi interfaces:
* i2c (software implementation, Wire library, AVR Twi, Linux i2c-dev)
* spi (4-wire spi via Arduino SPI library, AVR Spi, AVR USI module)
* Primitive graphics functions (lines, rectangles, pixels, bitmaps)
* Printing text to display (using fonts of different size, you can use GLCD Font Creator to create new fonts)
* Includes [graphics engine](https://github.com/lexus2k/ssd1306/wiki/Using-NanoEngine-for-systems-with-low-resources) to support
double buffering on tiny microcontrollers.
* Can be used for game development (bonus examples):
* Arkanoid game ([arkanoid](examples/games/arkanoid) in old style API and [arkanoid8](examples/games/arkanoid8) in new style API)
* Simple [Lode runner](examples/games/lode_runner) game.
* [Snowflakes](examples/nano_engine/snowflakes)
The i2c pins can be changed via API functions. Please, refer to documentation. Keep in mind,
that the pins, which are allowed for i2c or spi interface, depend on the hardware.
The default spi SCLK and MOSI pins are defined by SPI library, and DC, RST, CES pins are configurable
through API.
<a name="supported-displays"></a>
## Supported displays:
| **Display** | **I2C** | **SPI** | **Orientation** | **Comments** |
| :-------- |:---:|:---:|:---:|:---------|
| sh1106 128x64 | X | | | |
| ssd1306 128x64 | X | X | | |
| ssd1306 128x32 | X | X | | |
| ssd1325 128x64 | | X | | |
| ssd1327 128x128 | | X | | |
| ssd1351 128x128 | | X | | |
| il9163 128x128 | | X | X | |
| st7735 128x160 | | X | X | |
| ili9341 240x320 | | X | X | |
| pcd8544 84x48 | | X | | Nokia 5110 |
| vga 96x40 color | | | | direct D-sub output, atmega328p only |
| vga 128x64 bw | | | | direct D-sub output, atmega328p only |
<a name="supported-platforms"></a>
## Supported platforms
| **Platforms** | **I2C** | **SPI** | **Comments** |
| :-------- |:---:|:---:|:---------|
| **Arduino** | | | |
| Attiny85, Attiny45 | X | X | Refer to [Damellis attiny package](https://raw.githubusercontent.com/damellis/attiny/ide-1.6.x-boards-manager/package_damellis_attiny_index.json) |
| Attiny84, Attiny44 | X | X | Refer to [Damellis attiny package](https://raw.githubusercontent.com/damellis/attiny/ide-1.6.x-boards-manager/package_damellis_attiny_index.json) |
| Atmega328p, Atmega168 | X | X | |
| Atmega32u4 | X | X | |
| Atmega2560 | X | X | |
| Digispark, including PRO version | X | X | check [examples compatibility list](examples/Digispark_compatibility.txt) |
| ESP8266 | X | X | check [examples compatibility list](examples/ESP8266_compatibility.txt) |
| ESP32 | X | X | check [examples compatibility list](examples/ESP8266_compatibility.txt) |
| STM32 | X | X | [stm32duino](https://github.com/stm32duino/wiki/wiki) |
| Arduino Zero | X | X | |
| Nordic nRF5 (nRF51, nRF52) | X | X | nRF users, enable c++11 in platform.txt `-std=gnu++11` |
| Nordic nRF5 (nRF51, nRF52) | X | X | via [Sandeep Mistry arduino-nRF5](https://github.com/sandeepmistry/arduino-nRF5) package |
| **Plain AVR** | | | |
| Attiny85, Attiny45 | X | X | |
| Atmega328p, Atmega168 | X | X | |
| Atmega32u4 | X | X | |
| **Plain ESP32** | | | |
| ESP32 | X | X | library can be used as IDF component |
| **Linux** | | | |
| Raspberry Pi | X | X | i2c-dev, spidev, sys/class/gpio |
| [SDL Emulation](https://github.com/lexus2k/ssd1306/wiki/How-to-run-emulator-mode) | X | X | demo code can be run without real OLED HW via SDL library |
| **Windows** | | | |
| [SDL Emulation](https://github.com/lexus2k/ssd1306/wiki/How-to-run-emulator-mode) | X | X | demo code can be run without real OLED HW via MinGW32 + SDL library |
Digispark users, please check compilation options in your Arduino prior to using this library.
Ssd1306 library requires at least c++11 and c99 (by default Digispark package misses the options
-std=gnu11, -std=gnu++11).
<a name="setting-up"></a>
## Setting up
*i2c Hardware setup is described [here](https://github.com/lexus2k/ssd1306/wiki/Hardware-setup)*
*Setting up for Arduino from github sources)*
* Download source from https://github.com/lexus2k/ssd1306
* Put the sources to Arduino/libraries/ssd1306/ folder
*Setting up for Arduino from Arduino IDE library manager*
* Install ssd1306 library (named ssd1306 by Alexey Dynda) via Arduino IDE library manager
*Using with plain avr-gcc:*
* Download source from https://github.com/lexus2k/ssd1306
* Build the library (variant 1)
* cd ssd1306/src && make -f Makefile.avr MCU=\<your_mcu\>
* Link library to your project (refer to [Makefile.avr](examples/Makefile.avr) in examples folder).
* Build demo code (variant 2)
* cd ssd1306/tools && ./build_and_run.sh -p avr -m \<your_mcu\> ssd1306_demo
*For esp32:*
* Download source from https://github.com/lexus2k/ssd1306
* Put downloaded sources to components/ssd1306/ folder.
* Compile your project as described in ESP-IDF build system documentation
For more information about this library, please, visit https://github.com/lexus2k/ssd1306.
Doxygen documentation can be found at [github.io site](http://lexus2k.github.io/ssd1306).
If you found any problem or have any idea, please, report to Issues section.
<a name="license"></a>
## License
The library is free. If this project helps you, you can give me a cup of coffee. [Donate via Paypal](https://www.paypal.me/lexus2k)
MIT License
Copyright (c) 2016-2019, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
File diff suppressed because it is too large Load Diff
+23
View File
@@ -0,0 +1,23 @@
/*
* SSD1306xLED - Drivers for SSD1306 controlled dot matrix OLED/PLED 128x64 displays
*
* @created: 2014-08-12
* @author: Neven Boyanov
*
* Copyright (c) 2015 Neven Boyanov, Tinusaur Team. All Rights Reserved.
* Distributed as open source software under MIT License, see LICENSE.txt file.
* Please, as a favour, retain the link http://tinusaur.org to The Tinusaur Project.
*
* Source code available at: https://bitbucket.org/tinusaur/ssd1306xled
*
*/
/**
* @file font6x8.h Fonts 6x8. Header file is here only for compatibility with previous library releases
*/
#ifndef FONT6x8_H
#define FONT6x8_H
#include "ssd1306_fonts.h"
#endif // FONT6x8_H
+65
View File
@@ -0,0 +1,65 @@
/*
MIT License
Copyright (c) 2017-2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "ssd1306_i2c.h"
#include "intf/ssd1306_interface.h"
void ssd1306_i2cInitEx(int8_t scl, int8_t sda, int8_t sa)
{
#if defined(CONFIG_PLATFORM_I2C_AVAILABLE) && defined(CONFIG_PLATFORM_I2C_ENABLE)
ssd1306_platform_i2cConfig_t cfg;
cfg.scl = scl;
cfg.sda = sda;
ssd1306_platform_i2cInit(-1, sa, &cfg);
#elif defined(CONFIG_TWI_I2C_AVAILABLE) && defined(CONFIG_TWI_I2C_ENABLE)
ssd1306_i2cConfigure_Twi(0);
ssd1306_i2cInit_Twi(sa);
#elif defined(CONFIG_SOFTWARE_I2C_AVAILABLE) && defined(CONFIG_SOFTWARE_I2C_ENABLE)
ssd1306_i2cInit_Embedded(scl, sda, sa);
#else
#warning "ssd1306 library: no i2c support for the target platform"
#endif
}
void ssd1306_i2cInitEx2(int8_t busId, int8_t scl, int8_t sda, int8_t sa)
{
#if defined(CONFIG_PLATFORM_I2C_AVAILABLE) && defined(CONFIG_PLATFORM_I2C_ENABLE)
ssd1306_platform_i2cConfig_t cfg;
cfg.scl = scl;
cfg.sda = sda;
ssd1306_platform_i2cInit(busId, sa, &cfg);
#elif defined(CONFIG_TWI_I2C_AVAILABLE) && defined(CONFIG_TWI_I2C_ENABLE)
ssd1306_i2cConfigure_Twi(0);
ssd1306_i2cInit_Twi(sa);
#elif defined(CONFIG_SOFTWARE_I2C_AVAILABLE) && defined(CONFIG_SOFTWARE_I2C_ENABLE)
ssd1306_i2cInit_Embedded(scl, sda, sa);
#else
#warning "ssd1306 library: no i2c support for the target platform"
#endif
}
void ssd1306_i2cInit()
{
ssd1306_i2cInitEx(-1, -1, SSD1306_SA);
}
+112
View File
@@ -0,0 +1,112 @@
/*
MIT License
Copyright (c) 2016-2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* @file ssd1306_i2c.h SSD1306 i2c communication functions
*/
#ifndef _SSD1306_I2C_H_
#define _SSD1306_I2C_H_
#include "ssd1306_i2c_conf.h"
#include "ssd1306_i2c_embedded.h"
#include "ssd1306_i2c_twi.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @ingroup LCD_HW_INTERFACE_API
*
* Inits display interface to use i2c bus.
* The function automatically selects available type of i2c implementation
* 1. Wire library
* 2. sw i2c implementation
* In case of using Wire library this function calls Wire.begin() and
* sets speed to fast i2c (400kHz). If you prefer to use your own Wire settings
* or avoid reinitializing of Wire library, please use ssd1306_i2cInit_Wire().
* If you want to use embedded i2c (if it is supported), use ssd1306_i2cInit_Embedded().
*
* @note: after call to this function you need to initialize lcd display.
*/
void ssd1306_i2cInit(void);
/**
* @ingroup LCD_HW_INTERFACE_API
*
* Inits display interface to use i2c bus.
* The function automatically selects available type of i2c implementation
* 1. Wire library
* 2. sw i2c implementation
* In case of using Wire library this function calls Wire.begin() and
* sets speed to fast i2c (400kHz). If you prefer to use your own Wire settings
* or avoid reinitializing of Wire library, please use ssd1306_i2cInit_Wire().
* If you want to use embedded i2c (if it is supported), use ssd1306_i2cInit_Embedded().
*
* @param scl - i2c clock pin. Use -1 if you don't need to change default pin number
* @param sda - i2c data pin. Use -1 if you don't need to change default pin number
* @param sa - i2c address of lcd display. Use 0 to leave default
*
* @note scl and sda parameters depend on used hardware. For many hardware boards these
* parameters do not have any effect. ESP8266 allows to specify these parameters
*
* @note scl and sda for Linux systems should be the same, and should contain i2c bus id.
*
* @note: after call to this function you need to initialize lcd display.
*/
void ssd1306_i2cInitEx(int8_t scl, int8_t sda, int8_t sa);
/**
* @ingroup LCD_HW_INTERFACE_API
*
* Inits display interface to use i2c bus.
* The function automatically selects available type of i2c implementation
* 1. Wire library
* 2. sw i2c implementation
* In case of using Wire library this function calls Wire.begin() and
* sets speed to fast i2c (400kHz). If you prefer to use your own Wire settings
* or avoid reinitializing of Wire library, please use ssd1306_i2cInit_Wire().
* If you want to use embedded i2c (if it is supported), use ssd1306_i2cInit_Embedded().
*
* @param busId - number of i2c bus if there are multiple hw blocks avialable.
* @param scl - i2c clock pin. Use -1 if you don't need to change default pin number
* @param sda - i2c data pin. Use -1 if you don't need to change default pin number
* @param sa - i2c address of lcd display. Use 0 to leave default
*
* @note scl and sda parameters depend on used hardware. For many hardware boards these
* parameters do not have any effect. ESP8266 allows to specify these parameters
*
* @note scl and sda for Linux systems should be the same, and should contain i2c bus id.
*
* @note: after call to this function you need to initialize lcd display.
*/
void ssd1306_i2cInitEx2(int8_t busId, int8_t scl, int8_t sda, int8_t sa);
#ifdef __cplusplus
}
#endif
// ----------------------------------------------------------------------------
#endif // _SSD1306_I2C_H_
@@ -0,0 +1,77 @@
/*
MIT License
Copyright (c) 2016-2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* @file ssd1306_i2c_conf.h SSD1306 library basic i2c definitions
*/
#ifndef _SSD1306_I2C_CONF_H_
#define _SSD1306_I2C_CONF_H_
#include "ssd1306_hal/io.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifndef SSD1306_SA
/**
* @ingroup LCD_HW_INTERFACE_API
*
* SSD1306_SA defines default i2c address of LCD display. Please, check your device.
* If you LCD device has different address, you can set different one via
* ssd1306_i2cInit_Wire() or ssd1306_i2cInit_Embedded() functions.
* Write command will be SSD1306_SA<<1 and read will be SSD1306_SA<<1 | 1
*/
#define SSD1306_SA 0x3C // Slave address
#endif
#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
#ifndef SSD1306_SCL
#define SSD1306_SCL 3 ///< SCL, Pin 3 on SSD1306 Board
#endif
#ifndef SSD1306_SDA
#define SSD1306_SDA 4 ///< SDA, Pin 4 on SSD1306 Board
#endif
#elif defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
#ifndef SSD1306_SCL
#define SSD1306_SCL 4 ///< SCL, Pin 4 - physical pin 9 of Attiny84
#endif
#ifndef SSD1306_SDA
#define SSD1306_SDA 6 ///< SDA, Pin 6 - physical pin 7 of Attiny84
#endif
#else
#ifndef SSD1306_SCL
#define SSD1306_SCL 5 // SCL, Pin A5 on SSD1306 Board
#endif
#ifndef SSD1306_SDA
#define SSD1306_SDA 4 // SDA, Pin A4 on SSD1306 Board
#endif
#endif
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,191 @@
/*
MIT License
Copyright (c) 2016-2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "ssd1306_i2c_embedded.h"
#include "intf/ssd1306_interface.h"
#include "ssd1306_i2c.h"
#include "ssd1306_hal/io.h"
#if defined(CONFIG_SOFTWARE_I2C_AVAILABLE) && defined(CONFIG_SOFTWARE_I2C_ENABLE)
#include <util/delay_basic.h>
/**
* Port registers, containing pins, which SSD1306 display is connected to.
* For ATtiny controllers it is standard PORTB
* For ATmega328p, it is PORTC, which corresponds to Analog inputs/outputs
*/
static uint8_t s_scl = (1<<SSD1306_SCL);
static uint8_t s_sda = (1<<SSD1306_SDA);
static uint8_t s_sa = SSD1306_SA;
#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
// at 8Mhz each command takes ~ 0.125us
#define DDR_REG DDRB
#define PORT_REG PORTB
#elif defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
// For AttinyX4 controllers
// at 8Mhz each command takes ~ 0.125us
#define DDR_REG DDRA
#define PORT_REG PORTA
#else // For Atmega
// at 16Mhz each command takes ~ 0.0625us
#define DDR_REG DDRC
#define PORT_REG PORTC
#endif
#ifndef F_CPU
#warning "F_CPU is not defined, there can be I2C issues"
#define F_CPU 8000000
#endif
#define CPU_CYCLE_NS (1000000000/F_CPU)
#define DELAY_LOOP_CYCLES 4
#define ssd1306_delay(x) _delay_loop_2(x)
/**
* Section, which defines I2C timings for SSD1306 display from datasheet
*/
#define SSD1306_I2C_START_STOP_DELAY 600
#define SSD1306_I2C_RISE_TIME 300
#define SSD1306_I2C_FALL_TIME 300
#define SSD1306_I2C_DATA_HOLD_TIME 300
#define SSD1306_I2C_IDLE_TIME 1300
#define SSD1306_I2C_CLOCK 2500
#define I2C_START_STOP_DELAY ((SSD1306_I2C_START_STOP_DELAY/CPU_CYCLE_NS + DELAY_LOOP_CYCLES/2)/DELAY_LOOP_CYCLES)
#define I2C_RISE_TIME ((SSD1306_I2C_RISE_TIME/CPU_CYCLE_NS)/DELAY_LOOP_CYCLES)
#define I2C_DATA_HOLD_TIME ((SSD1306_I2C_DATA_HOLD_TIME/CPU_CYCLE_NS + DELAY_LOOP_CYCLES/2)/DELAY_LOOP_CYCLES)
#define I2C_IDLE_TIME (((SSD1306_I2C_IDLE_TIME/CPU_CYCLE_NS) + DELAY_LOOP_CYCLES/2)/DELAY_LOOP_CYCLES)
#define I2C_HALF_CLOCK (((SSD1306_I2C_CLOCK - SSD1306_I2C_FALL_TIME - SSD1306_I2C_RISE_TIME - SSD1306_I2C_FALL_TIME)/CPU_CYCLE_NS/2 \
)/DELAY_LOOP_CYCLES)
/* I2C HIGH = PORT as INPUT(0) and PULL-UP ENABLE (1) */
//#define DIGITAL_WRITE_HIGH(DREG, PREG, BIT) { DREG &= ~(1 << BIT); PREG |= (1 << BIT); }
#define DIGITAL_WRITE_HIGH(DREG, PREG, BIT) { DREG &= ~BIT; PREG |= BIT; }
/* I2C LOW = PORT as OUTPUT(1) and OUTPUT LOW (0) */
//#define DIGITAL_WRITE_LOW(DREG, PREG, BIT) { DREG |= (1 << BIT); PREG &= ~(1 << BIT); }
#define DIGITAL_WRITE_LOW(DREG, PREG, BIT) { DREG |= BIT; PREG &= ~BIT; }
static uint8_t oldSREG;
static uint8_t interruptsOff = 0;
/**
* Inputs: SCL is LOW, SDA is has no meaning
* Outputs: SCL is LOW
*/
static void ssd1306_i2cSendByte_Embedded(uint8_t data)
{
uint8_t i;
for(i=8; i>0; i--)
{
if(data & 0x80)
DIGITAL_WRITE_HIGH(DDR_REG, PORT_REG, s_sda)
else
DIGITAL_WRITE_LOW(DDR_REG, PORT_REG, s_sda);
data<<=1;
ssd1306_delay(I2C_RISE_TIME); // Fall time is the same as rise time
DIGITAL_WRITE_HIGH(DDR_REG, PORT_REG, s_scl);
ssd1306_delay(I2C_HALF_CLOCK);
DIGITAL_WRITE_LOW(DDR_REG, PORT_REG, s_scl);
ssd1306_delay(I2C_HALF_CLOCK);
}
// generating confirmation impulse
DIGITAL_WRITE_HIGH(DDR_REG, PORT_REG, s_sda);
ssd1306_delay(I2C_RISE_TIME); // Fall time is the same as rise time
DIGITAL_WRITE_HIGH(DDR_REG, PORT_REG, s_scl);
ssd1306_delay(I2C_HALF_CLOCK);
DIGITAL_WRITE_LOW(DDR_REG, PORT_REG, s_scl);
ssd1306_delay(I2C_HALF_CLOCK);
}
static void ssd1306_i2cSendBytes_Embedded(const uint8_t *buffer, uint16_t size)
{
while (size--)
{
ssd1306_i2cSendByte_Embedded(*buffer);
buffer++;
}
}
/**
* SCL remains HIGH on EXIT, Low SDA means start transmission
*/
static void ssd1306_i2cStart_Embedded(void)
{
oldSREG = SREG;
cli();
interruptsOff = 1;
DIGITAL_WRITE_LOW(DDR_REG, PORT_REG, s_sda); // Set to LOW
ssd1306_delay(I2C_START_STOP_DELAY);
DIGITAL_WRITE_LOW(DDR_REG, PORT_REG, s_scl); // Set to LOW
ssd1306_delay(I2C_HALF_CLOCK);
ssd1306_i2cSendByte_Embedded((s_sa << 1) | 0);
}
static void ssd1306_i2cStop_Embedded(void)
{
DIGITAL_WRITE_LOW(DDR_REG, PORT_REG, s_sda); // Set to LOW
ssd1306_delay(I2C_RISE_TIME); // Fall time is the same as rise time
DIGITAL_WRITE_HIGH(DDR_REG, PORT_REG, s_scl); // Set to HIGH
ssd1306_delay(I2C_START_STOP_DELAY);
DIGITAL_WRITE_HIGH(DDR_REG, PORT_REG, s_sda); // Set to HIGH
ssd1306_delay(I2C_IDLE_TIME);
if (interruptsOff)
{
SREG = oldSREG;
interruptsOff = 0;
}
}
static void ssd1306_i2cClose_Embedded()
{
}
void ssd1306_i2cInit_Embedded(int8_t scl, int8_t sda, uint8_t sa)
{
if (scl>=0) s_scl = (1<<scl);
if (sda>=0) s_sda = (1<<sda);
if (sa) s_sa = sa;
ssd1306_intf.spi = 0;
ssd1306_intf.start = ssd1306_i2cStart_Embedded;
ssd1306_intf.stop = ssd1306_i2cStop_Embedded;
ssd1306_intf.send = ssd1306_i2cSendByte_Embedded;
ssd1306_intf.send_buffer = ssd1306_i2cSendBytes_Embedded;
ssd1306_intf.close = ssd1306_i2cClose_Embedded;
}
#endif
@@ -0,0 +1,63 @@
/*
MIT License
Copyright (c) 2017-2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* @file ssd1306_i2c_embedded.h embedded SSD1306 i2c communication functions
*/
#ifndef _SSD1306_I2C_EMBEDDED_H_
#define _SSD1306_I2C_EMBEDDED_H_
#include "ssd1306_hal/io.h"
#include "ssd1306_i2c_conf.h"
#if defined(CONFIG_SOFTWARE_I2C_AVAILABLE) && defined(CONFIG_SOFTWARE_I2C_ENABLE)
#ifdef __cplusplus
extern "C" {
#endif
/**
* @ingroup LCD_HW_INTERFACE_API
*
* Initializes software implementation of i2c.
* If you do not know i2c parameters, try ssd1306_i2cInit_Embedded(0,0,0).
* @warning the function disables interrupts.
* @param scl - i2c clock pin. Use -1 if you don't need to change default pin number
* @param sda - i2c data pin. Use -1 if you don't need to change default pin number
* @param sa - i2c address of lcd display. Use 0 to leave default
*
* @note: after call to this function you need to initialize lcd display.
*/
void ssd1306_i2cInit_Embedded(int8_t scl, int8_t sda, uint8_t sa);
#ifdef __cplusplus
}
#endif
#endif
#endif /* _SSD1306_I2C_EMBEDDED_H_ */
@@ -0,0 +1,173 @@
/*
MIT License
Copyright (c) 2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "ssd1306_i2c_twi.h"
#include "intf/ssd1306_interface.h"
#include "ssd1306_i2c.h"
#if defined(CONFIG_TWI_I2C_AVAILABLE) && defined(CONFIG_TWI_I2C_ENABLE)
#include <avr/io.h>
#include <util/twi.h>
/* Max i2c frequency, supported by OLED controllers */
#define SSD1306_TWI_FREQ 400000
#define MAX_RETRIES 64
static uint8_t s_sa = SSD1306_SA;
static uint8_t ssd1306_twi_start(void)
{
uint8_t twst;
uint8_t iters = MAX_RETRIES;
do
{
TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
while ( (TWCR & (1<<TWINT)) == 0 );
twst = TWSR & 0xF8;
if (!--iters)
{
break;
}
} while (twst == TW_MT_ARB_LOST);
if ((twst != TW_START) && (twst != TW_REP_START))
{
return twst;
}
return 0;
}
static uint8_t ssd1306_twi_send(uint8_t data)
{
uint8_t twsr;
uint8_t iters = MAX_RETRIES;
do
{
TWDR = data;
TWCR = (1<<TWINT) | (1<<TWEN);
while ( (TWCR & (1<<TWINT)) == 0 );
twsr = TWSR & 0xF8;
if ((twsr == TW_MT_SLA_ACK) || (twsr == TW_MT_DATA_ACK))
{
return 0;
}
if (twsr == TW_MT_ARB_LOST)
{
return twsr;
}
iters++;
if (!--iters)
{
break;
}
} while (twsr != TW_MT_ARB_LOST);
return twsr;
}
static void ssd1306_twi_stop(void)
{
TWCR = (1<<TWEN) | (1<<TWSTO) | (1<<TWINT);
}
static void ssd1306_i2cStart_Twi(void)
{
do
{
if (ssd1306_twi_start() != 0)
{
/* Some serious error happened, but we don't care. Our API functions have void type */
return;
}
} while (ssd1306_twi_send(s_sa << 1) == TW_MT_ARB_LOST);
}
static void ssd1306_i2cStop_Twi(void)
{
ssd1306_twi_stop();
}
void ssd1306_i2cConfigure_Twi(uint8_t arg)
{
#if defined(__AVR_ATmega328P__)
/* Enable internal pull-ups */
DDRC &= ~(1<<PINC4); PORTC |= (1<<PINC4);
DDRC &= ~(1<<PINC5); PORTC |= (1<<PINC5);
#endif
#if defined(TWPS0)
TWSR = 0;
#endif
TWBR = ((F_CPU / SSD1306_TWI_FREQ) - 16) / 2 / (1); // Always use prescaler 1 (TWSR 0x00)
TWCR = (1 << TWEN) | (1 << TWEA);
}
static void ssd1306_i2cSendByte_Twi(uint8_t data)
{
for(;;)
{
if (ssd1306_twi_send(data) != TW_MT_ARB_LOST)
{
break;
}
if (ssd1306_twi_start() != 0)
{
/* Some serious error happened, but we don't care. Our API functions have void type */
break;
}
if (ssd1306_twi_send(s_sa << 1) != TW_MT_ARB_LOST)
{
/* Some serious error happened, but we don't care. Our API functions have void type */
break;
}
}
}
static void ssd1306_i2cSendBytes_Twi(const uint8_t *buffer, uint16_t size)
{
while (size--)
{
ssd1306_i2cSendByte_Twi(*buffer);
buffer++;
}
}
static void ssd1306_i2cClose_Twi()
{
}
void ssd1306_i2cInit_Twi(uint8_t sa)
{
if (sa) s_sa = sa;
ssd1306_intf.spi = 0;
ssd1306_intf.start = ssd1306_i2cStart_Twi;
ssd1306_intf.stop = ssd1306_i2cStop_Twi;
ssd1306_intf.send = ssd1306_i2cSendByte_Twi;
ssd1306_intf.send_buffer = ssd1306_i2cSendBytes_Twi;
ssd1306_intf.close = ssd1306_i2cClose_Twi;
}
#endif
@@ -0,0 +1,72 @@
/*
MIT License
Copyright (c) 2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* @file ssd1306_i2c_twi.h SSD1306 i2c communication functions for standard AVR TWI interface
*/
#ifndef _SSD1306_I2C_TWI_H_
#define _SSD1306_I2C_TWI_H_
#include "ssd1306_hal/io.h"
#include "ssd1306_i2c_conf.h"
#if defined(CONFIG_TWI_I2C_AVAILABLE) && defined(CONFIG_TWI_I2C_ENABLE)
#ifdef __cplusplus
extern "C" {
#endif
/**
* @ingroup LCD_HW_INTERFACE_API
*
* Configures standard TWI AVR module (at 400kHz).
* This function is called by ssd1306_i2cInit().
* @param arg - has no meaning for now. Should be zero
*
* @note scl and sda pins depend on used hardware.
*/
void ssd1306_i2cConfigure_Twi(uint8_t arg);
/**
* @ingroup LCD_HW_INTERFACE_API
*
* Initializes ssd1306 library to use TWI AVR module for i2c.
* If you do not know i2c parameters, try ssd1306_i2cInit_Twi(0).
* SCL and SDA pins depend on platform.
* @param sa - i2c address of lcd display. Use 0 to leave default
*
* @note: after call to this function you need to initialize lcd display.
*/
void ssd1306_i2cInit_Twi(uint8_t sa);
#ifdef __cplusplus
}
#endif
#endif
#endif /* _SSD1306_I2C_TWI_H_ */
+56
View File
@@ -0,0 +1,56 @@
/*
MIT License
Copyright (c) 2017-2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "ssd1306_spi.h"
#include "ssd1306_spi_avr.h"
#include "ssd1306_spi_usi.h"
#include "intf/ssd1306_interface.h"
#include "lcd/lcd_common.h"
#include "ssd1306_hal/io.h"
int8_t s_ssd1306_cs = 4;
int8_t s_ssd1306_dc = 5;
uint32_t s_ssd1306_spi_clock = 8000000;
void ssd1306_spiInit(int8_t cesPin, int8_t dcPin)
{
#if defined(CONFIG_AVR_SPI_AVAILABLE) && defined(CONFIG_AVR_SPI_ENABLE)
ssd1306_spiInit_avr(cesPin, dcPin);
#elif defined(CONFIG_PLATFORM_SPI_AVAILABLE) && defined(CONFIG_PLATFORM_SPI_ENABLE)
ssd1306_platform_spiInit(-1, cesPin, dcPin);
#elif defined(CONFIG_USI_SPI_AVAILABLE) && defined(CONFIG_USI_SPI_ENABLE)
ssd1306_spiInit_Usi(cesPin, dcPin);
#else
#warning "ssd1306 library: no spi support for the target platform"
#endif
}
void ssd1306_spiDataMode(uint8_t mode)
{
if (s_ssd1306_dc)
{
digitalWrite(s_ssd1306_dc, mode ? HIGH : LOW);
}
}
+85
View File
@@ -0,0 +1,85 @@
/*
MIT License
Copyright (c) 2017-2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* @file ssd1306_spi.h SSD1306 spi communication functions
*/
#ifndef _SSD1306_SPI_H_
#define _SSD1306_SPI_H_
#include "ssd1306_hal/io.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @ingroup LCD_HW_INTERFACE_API
*
* chip enable pin to controll lcd display over spi
*/
extern int8_t s_ssd1306_cs;
/**
* @ingroup LCD_HW_INTERFACE_API
*
* data/command control pin for spi interface of lcd display
*/
extern int8_t s_ssd1306_dc;
/**
* @ingroup LCD_HW_INTERFACE_API
* maximum SPI clock, supported by OLED display
*/
extern uint32_t s_ssd1306_spi_clock;
/**
* @ingroup LCD_HW_INTERFACE_API
*
* Inits lcd interface to use hardware spi for communication.
* The function automatically selects available type of spi implementation
* 1. SPI library (ssd1306_spiInit_hw())
* @param cesPin - pin, controlling chip enable of LCD
* @param dcPin - pin, controlling data/command mode of LCD
*
* @note: after call to this function you need to initialize lcd display.
*/
void ssd1306_spiInit(int8_t cesPin, int8_t dcPin);
/**
* @ingroup LCD_HW_INTERFACE_API
*
* Switches spi to data(1) or command(0) mode.
* @param mode - 1 data mode
* 0 command mode
*/
void ssd1306_spiDataMode(uint8_t mode);
#ifdef __cplusplus
}
#endif
// ----------------------------------------------------------------------------
#endif // _SSD1306_SPI_H_
@@ -0,0 +1,150 @@
/*
MIT License
Copyright (c) 2018-2019, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "ssd1306_spi_avr.h"
#include "ssd1306_spi.h"
#include "intf/ssd1306_interface.h"
#include "lcd/lcd_common.h"
#include "ssd1306_hal/io.h"
#if defined(CONFIG_AVR_SPI_AVAILABLE) && defined(CONFIG_AVR_SPI_ENABLE)
#include <stdlib.h>
#define PORT_SPI PORTB
#define DDR_SPI DDRB
#if defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1280__)
#define DD_MISO DDB3
#define DD_MOSI DDB2
#define DD_SCK DDB1
#define DD_SS DDB0
#else
#define DD_MISO DDB4
#define DD_MOSI DDB3
#define DD_SCK DDB5
#define DD_SS DDB2
#endif
#define SPI_CLOCK_MASK 0x03
#define SPI_2XCLOCK_MASK 0x01
extern uint32_t s_ssd1306_spi_clock;
static void ssd1306_spiConfigure_avr()
{
uint8_t clockDiv;
uint32_t clockSetting = F_CPU / 2;
clockDiv = 0;
while ((clockDiv < 6) && (s_ssd1306_spi_clock < clockSetting))
{
clockSetting /= 2;
clockDiv++;
}
if (clockDiv == 6)
{
clockDiv = 7;
}
// Invert the SPI2X bit
clockDiv ^= 0x1;
// SS pin must be HIGH, when enabling MASTER SPI mode
// Otherwise, SPI will drop automatically to SLAVE mode
DDR_SPI &= ~((1<<DD_SCK)|(1<<DD_SS)|(1<<DD_MOSI));
PORT_SPI |= (1<<DD_SS);
/* Define the following pins as output */
DDR_SPI |= ((1<<DD_MOSI)|(1<<DD_SCK)|(1<<DD_SS));
PORT_SPI |= (1<<DD_SS);
SPCR = (1<<SPE)|(1<<MSTR)|(0<<CPOL)|(0<<CPHA)|
((clockDiv >> 1) & SPI_CLOCK_MASK);
SPSR = clockDiv & SPI_2XCLOCK_MASK; // Double Clock Rate
// Wait for some time to give SPI HW module to initialize
delay(10);
}
static void ssd1306_spiClose_avr()
{
}
static void ssd1306_spiStart_avr()
{
if (s_ssd1306_cs >= 0)
{
digitalWrite(s_ssd1306_cs,LOW);
}
}
static void ssd1306_spiSendByte_avr(uint8_t data)
{
SPDR = data;
asm volatile("nop");
while((SPSR & (1<<SPIF))==0);
}
static void ssd1306_spiSendBytes_avr(const uint8_t * buffer, uint16_t size)
{
while (size--)
{
SPDR = *buffer;
asm volatile("nop"); // to improve speed
while((SPSR & (1<<SPIF))==0);
SPDR; // read SPI input
buffer++;
}
}
static void ssd1306_spiStop_avr()
{
if (ssd1306_lcd.type == LCD_TYPE_PCD8544)
{
digitalWrite(s_ssd1306_dc, LOW);
ssd1306_spiSendByte_avr( 0x00 ); // Send NOP command to allow last data byte to pass (bug in PCD8544?)
// ssd1306 E3h is NOP command
}
if (s_ssd1306_cs >= 0)
{
digitalWrite(s_ssd1306_cs, HIGH);
}
}
void ssd1306_spiInit_avr(int8_t cesPin, int8_t dcPin)
{
if (cesPin >=0) pinMode(cesPin, OUTPUT);
if (dcPin >= 0) pinMode(dcPin, OUTPUT);
if (cesPin) s_ssd1306_cs = cesPin;
if (dcPin) s_ssd1306_dc = dcPin;
ssd1306_intf.spi = 1;
ssd1306_spiConfigure_avr();
ssd1306_intf.start = ssd1306_spiStart_avr;
ssd1306_intf.stop = ssd1306_spiStop_avr;
ssd1306_intf.send = ssd1306_spiSendByte_avr;
ssd1306_intf.send_buffer = ssd1306_spiSendBytes_avr;
ssd1306_intf.close = ssd1306_spiClose_avr;
}
#endif
@@ -0,0 +1,60 @@
/*
MIT License
Copyright (c) 2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* @file ssd1306_spi_avr.h SSD1306 AVR spi communication functions
*/
#ifndef _SSD1306_AVR_SPI_H_
#define _SSD1306_AVR_SPI_H_
#include "ssd1306_spi_conf.h"
#include "ssd1306_hal/io.h"
#ifdef __cplusplus
extern "C" {
#endif
#if defined(CONFIG_AVR_SPI_AVAILABLE) && defined(CONFIG_AVR_SPI_ENABLE)
/**
* @ingroup LCD_HW_INTERFACE_API
*
* Inits lcd interface to use hardware SPI for communication (SPI.h library).
* It uses standard MOSI, SCLK pins to send data to LCD.
* @param cesPin - pin, controlling chip enable of LCD
* @param dcPin - pin, controlling data/command mode of LCD
*
* @note: after call to this function you need to initialize lcd display.
*/
void ssd1306_spiInit_avr(int8_t cesPin, int8_t dcPin);
#endif
#ifdef __cplusplus
}
#endif
// ----------------------------------------------------------------------------
#endif // _SSD1306_AVR_SPI_H_
@@ -0,0 +1,34 @@
/*
MIT License
Copyright (c) 2017-2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* @file ssd1306_spi_conf.h SSD1306 library basic spi definitions. Only for compatibility
*/
#ifndef _SSD1306_SPI_CONF_H_
#define _SSD1306_SPI_CONF_H_
// TODO: Remove this module completely
#endif
@@ -0,0 +1,136 @@
/*
MIT License
Copyright (c) 2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "ssd1306_spi_usi.h"
#include "ssd1306_spi.h"
#include "intf/ssd1306_interface.h"
#include "lcd/lcd_common.h"
#include "ssd1306_hal/io.h"
#if defined(CONFIG_USI_SPI_AVAILABLE) && defined(CONFIG_USI_SPI_ENABLE)
#include <stdlib.h>
#include <util/atomic.h>
#define PORT_SPI PORTB
#define DDR_SPI DDRB
#define DD_DI DDB0
#define DD_DO DDB1
#define DD_SCK DDB2
static void ssd1306_spiConfigure_Usi()
{
DDR_SPI |= (1<<DD_DO); // as output (DO) - data out
DDR_SPI |= (1<<DD_SCK); // as output (USISCK) - clock
/* DI pin is still used by USI, although ssd1306 library doesn't need it */
// DDR_SPI &= ~(1<<DD_DI); // as input (DI) - data in
// PORT_SPI|= (1<<DD_DI); // pullup on (DI)
}
static void ssd1306_spiClose_Usi()
{
}
static void ssd1306_spiStart_Usi()
{
if (s_ssd1306_cs >= 0)
{
digitalWrite(s_ssd1306_cs,LOW);
}
USICR = (0<<USIWM1) | (1<<USIWM0) |
(1<<USICS1) | (0<<USICS0) | (1<<USICLK);
}
static void ssd1306_spiSendByte_Usi(uint8_t data)
{
USIDR = data;
USISR = (1<<USIOIF);
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
{
while ( (USISR & (1<<USIOIF)) == 0 )
{
USICR |= (1<<USITC);
}
}
}
static void ssd1306_spiSendBytes_Usi(const uint8_t *buffer, uint16_t size)
{
while (size--)
{
USIDR = *buffer;
USISR = (1<<USIOIF);
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
{
while ( (USISR & (1<<USIOIF)) == 0 )
{
USICR |= (1<<USITC);
}
}
buffer++;
};
}
static void ssd1306_spiStop_Usi()
{
if (s_ssd1306_cs >= 0)
{
digitalWrite(s_ssd1306_cs, HIGH);
}
if (ssd1306_lcd.type == LCD_TYPE_PCD8544)
{
digitalWrite(s_ssd1306_dc, LOW);
ssd1306_spiSendByte_Usi( 0x00 ); // Send NOP command to allow last data byte to pass (bug in PCD8544?)
// ssd1306 E3h is NOP command
}
// USICR &= ~((1<<USIWM1) | (1<<USIWM0));
}
void ssd1306_spiInit_Usi(int8_t cesPin, int8_t dcPin)
{
if (cesPin >=0)
{
pinMode(cesPin, OUTPUT);
digitalWrite(cesPin, HIGH);
}
if (dcPin >= 0) pinMode(dcPin, OUTPUT);
if ((cesPin >= 0) || (dcPin >= 0))
{
/* Even if CS pin is not used we need still to set it to value passed to the function */
s_ssd1306_cs = cesPin;
s_ssd1306_dc = dcPin;
}
ssd1306_spiConfigure_Usi();
ssd1306_intf.spi = 1;
ssd1306_intf.start = ssd1306_spiStart_Usi;
ssd1306_intf.stop = ssd1306_spiStop_Usi;
ssd1306_intf.send = ssd1306_spiSendByte_Usi;
ssd1306_intf.send_buffer = ssd1306_spiSendBytes_Usi;
ssd1306_intf.close = ssd1306_spiClose_Usi;
}
#endif
@@ -0,0 +1,60 @@
/*
MIT License
Copyright (c) 2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* @file ssd1306_spi_usi.h SSD1306 SPI USI communication functions
*/
#ifndef _SSD1306_SPI_USI_H_
#define _SSD1306_SPI_USI_H_
#include "ssd1306_spi_conf.h"
#include "ssd1306_hal/io.h"
#ifdef __cplusplus
extern "C" {
#endif
#if defined(CONFIG_USI_SPI_AVAILABLE) && defined(CONFIG_USI_SPI_ENABLE)
/**
* @ingroup LCD_HW_INTERFACE_API
*
* Inits lcd interface to use USI for SPI communication.
* It uses standard USI CLK, USI DO, USI DI pins to send data to LCD.
* @param cesPin - pin, controlling chip enable of LCD
* @param dcPin - pin, controlling data/command mode of LCD
*
* @note: after call to this function you need to initialize lcd display.
*/
void ssd1306_spiInit_Usi(int8_t cesPin, int8_t dcPin);
#endif
#ifdef __cplusplus
}
#endif
// ----------------------------------------------------------------------------
#endif // _SSD1306_SPI_USI_H_
@@ -0,0 +1,68 @@
/*
MIT License
Copyright (c) 2017-2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "ssd1306_interface.h"
#include "spi/ssd1306_spi.h"
#include <stddef.h>
static void ssd1306_send_buffer_generic(const uint8_t* buffer, uint16_t size);
ssd1306_interface_t ssd1306_intf =
{
.send_buffer = ssd1306_send_buffer_generic
};
void ssd1306_commandStart(void)
{
ssd1306_intf.start();
if (ssd1306_intf.spi)
ssd1306_spiDataMode(0);
else
ssd1306_intf.send(0x00);
}
void ssd1306_dataStart(void)
{
ssd1306_intf.start();
if (ssd1306_intf.spi)
ssd1306_spiDataMode(1);
else
ssd1306_intf.send(0x40);
}
void ssd1306_sendCommand(uint8_t command)
{
ssd1306_commandStart();
ssd1306_intf.send(command);
ssd1306_intf.stop();
}
void ssd1306_send_buffer_generic(const uint8_t* buffer, uint16_t size)
{
while (size--)
{
ssd1306_intf.send(*buffer);
buffer++;
}
}
+152
View File
@@ -0,0 +1,152 @@
/*
MIT License
Copyright (c) 2017-2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* @file ssd1306_interface.h SSD1306 interface functions.
*/
#ifndef _SSD1306_INTERFACE_H_
#define _SSD1306_INTERFACE_H_
#include "ssd1306_hal/io.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup LCD_HW_INTERFACE_API I2C/SPI: physical interface functions
* @{
*
* @brief i2c/spi initialization functions for different platforms
*
* @details This group of API functions serves to prepare the library to work via specific hardware
* interface. There are a bunch of functions for different platforms. In general display
* initialization goes in two steps: hardware interface initialization, and then display
* driver initialization. But there are functions, which combine 2 steps in single call:
* ssd1306_128x64_i2c_initEx(), ssd1351_128x128_spi_init(), etc.
*/
/** Describes low level hardware API */
typedef struct
{
/**
* Indicates if spi or i2c interface is used.
*/
uint8_t spi;
/**
* Starts communication with SSD1306 display.
*/
void (*start)(void);
/**
* Ends communication with SSD1306 display.
*/
void (*stop)(void);
/**
* Sends byte to SSD1306 device
* @param data - byte to send
*/
void (*send)(uint8_t data);
/**
* @brief Sends bytes to SSD1306 device
*
* Sends bytes to SSD1306 device. This functions gives
* ~ 30% performance increase than ssd1306_intf.send.
*
* @param buffer - bytes to send
* @param size - number of bytes to send
*/
void (*send_buffer)(const uint8_t *buffer, uint16_t size);
/**
* @brief deinitializes internal resources, allocated for interface.
*
* Deinitializes internal resources, allocated for interface.
* There is no need to use this function for microcontrollers. In general
* the function has meaning in Linux-like systems.
*/
void (*close)(void);
} ssd1306_interface_t;
/**
* Holds pointers to functions of currently initialized interface.
*/
extern ssd1306_interface_t ssd1306_intf;
/**
* Deprecated
*/
#define ssd1306_dcQuickSwitch ssd1306_intf.spi
/**
* Deprecated
*/
#define ssd1306_startTransmission ssd1306_intf.start
/**
* Deprecated
*/
#define ssd1306_endTransmission ssd1306_intf.stop
/**
* Deprecated
*/
#define ssd1306_sendByte ssd1306_intf.send
/**
* Deprecated
*/
#define ssd1306_sendBytes ssd1306_intf.send_buffer
/**
* Deprecated
*/
#define ssd1306_closeInterface ssd1306_intf.close
/**
* Sends command to SSD1306 device: includes initiating of
* transaction, sending data and completing transaction.
* @param command - command to send
*/
void ssd1306_sendCommand(uint8_t command);
/**
* Starts transaction for sending commands.
*/
void ssd1306_commandStart(void);
/**
* Starts transaction for sending bitmap data.
*/
void ssd1306_dataStart(void);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
// ----------------------------------------------------------------------------
#endif // _SSD1306_INTERFACE_H_
@@ -0,0 +1,75 @@
/*
MIT License
Copyright (c) 2016-2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "ssd1306_uart_builtin.h"
#include "intf/ssd1306_interface.h"
#include "ssd1306_hal/io.h"
#if defined(CONFIG_AVR_UART_AVAILABLE) && defined(CONFIG_AVR_UART_ENABLE)
#include "ssd1306_uart.h"
static void ssd1306_uartStart(void)
{
}
static void ssd1306_uartStop(void)
{
uart_send_byte(0x7E);
}
static void ssd1306_uartSendByte(uint8_t data)
{
if ((data == 0x7E) || (data == 0x7D))
{
uart_send_byte(0x7D);
data ^= 0x20;
}
uart_send_byte(data);
}
static void ssd1306_uartSendBytes(const uint8_t * buffer, uint16_t len)
{
while (len--)
{
ssd1306_uartSendByte(*buffer);
buffer++;
}
}
void ssd1306_uartInit_Builtin(uint32_t baud)
{
if (!baud) baud = 115200;
uart_init(baud);
ssd1306_intf.spi = 0;
ssd1306_intf.start = ssd1306_uartStart;
ssd1306_intf.stop = ssd1306_uartStop;
ssd1306_intf.send = ssd1306_uartSendByte;
ssd1306_intf.send_buffer = ssd1306_uartSendBytes;
ssd1306_intf.close = ssd1306_uartStart;
}
#endif
@@ -0,0 +1,59 @@
/*
MIT License
Copyright (c) 2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* @file ssd1306_uart_builtin.h embedded SSD1306 uart communication functions
*/
#ifndef _SSD1306_UART_BUILTIN_H_
#define _SSD1306_UART_BUILTIN_H_
#include "ssd1306_hal/io.h"
#if defined(CONFIG_AVR_UART_AVAILABLE) && defined(CONFIG_AVR_UART_ENABLE)
#ifdef __cplusplus
extern "C" {
#endif
/**
* @ingroup LCD_HW_INTERFACE_API
*
* Initializes built-in implementation of uart functions, based on USART hw module.
* If you do not know uart parameters, try ssd1306_uartInit_Builtin(0).
* @param baud uart baud rate
*
* @note: after call to this function you need to initialize lcd display.
*/
void ssd1306_uartInit_Builtin(uint32_t baud);
#ifdef __cplusplus
}
#endif
#endif
#endif /* _SSD1306_UART_BUILTIN_H_ */
@@ -0,0 +1,243 @@
/*
MIT License
Copyright (c) 2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "intf/vga/vga.h"
// Never include vga128x64_isr.h here!!!
#include "intf/ssd1306_interface.h"
#include "lcd/lcd_common.h"
#include "lcd/vga_commands.h"
#if defined(CONFIG_VGA_AVAILABLE) && defined(CONFIG_VGA_ENABLE) && defined(__AVR_ATmega328P__)
extern uint16_t ssd1306_color;
/* This buffer fits 128x64 pixels
Each 8 pixels are packed to 3 bytes:
BYTE1: B7 R2 G2 B2 B8 R1 G1 B1
BYTE2: G7 R4 G4 B4 G8 R3 G3 B3
BYTE3: R7 R6 G6 B6 R8 R5 G5 B5
Yeah, a little bit complicated, but this allows to quickly unpack structure
*/
// Set to ssd1306 compatible mode by default
static uint8_t s_mode = 0x01;
static uint8_t s_vga_command = 0xFF;
static uint8_t s_vga_arg = 0;
static uint8_t s_column = 0;
static uint8_t s_column_end = 0;
static uint8_t s_cursor_x = 0;
static uint8_t s_cursor_y = 0;
volatile uint8_t s_vga_frames;
static void vga_controller_init(void)
{
s_vga_command = 0xFF;
}
static void vga_controller_stop(void)
{
s_vga_command = 0xFF;
}
static void vga_controller_close(void)
{
}
/*
* Function sends 8 vertical pixels to buffer
*/
static inline void vga_controller_put_pixels(uint8_t x, uint8_t y, uint8_t pixels)
{
uint16_t addr = (x >> 3) + (uint16_t)(y * 16);
uint8_t offset = x & 0x07;
uint8_t mask = 1 << offset;
if (addr >= 16*64)
{
return;
}
for (uint8_t i=8; i>0; i--)
{
if (pixels & 0x01) __vga_buffer[addr] |= mask;
else __vga_buffer[addr] &= ~mask;
addr += 16;
pixels >>= 1;
}
}
static void vga_controller_send_byte(uint8_t data)
{
if (s_vga_command == 0xFF)
{
s_vga_command = data;
return;
}
if (s_vga_command == 0x40)
{
vga_controller_put_pixels(s_cursor_x, s_cursor_y, data);
s_cursor_x++;
if (s_cursor_x > s_column_end)
{
s_cursor_x = s_column;
s_cursor_y += 8;
}
return;
}
// command mode
if (!s_vga_command)
{
s_vga_command = data;
s_vga_arg = 0;
}
if (s_vga_command == VGA_SET_BLOCK)
{
// set block
if (s_vga_arg == 1)
{
s_column = data >= ssd1306_lcd.width ? ssd1306_lcd.width - 1 : data ;
s_cursor_x = s_column;
}
if (s_vga_arg == 2) { s_column_end = data >= ssd1306_lcd.width ? ssd1306_lcd.width - 1 : data; }
if (s_vga_arg == 3) { s_cursor_y = (data << 3); }
if (s_vga_arg == 4) { s_vga_command = 0; }
}
if (s_vga_command == VGA_SET_MODE)
{
if (s_vga_arg == 1) { s_mode = data; s_vga_command = 0; }
}
s_vga_arg++;
}
static void vga_controller_send_bytes(const uint8_t *buffer, uint16_t len)
{
while (len--)
{
ssd1306_intf.send(*buffer);
buffer++;
}
}
static inline void init_vga_crt_driver(uint8_t enable_jitter_fix)
{
cli();
if (enable_jitter_fix)
{
// Configure Timer 0 to calculate jitter fix
TIMSK0=0;
TCCR0A=0;
TCCR0B=1;
OCR0A=0;
OCR0B=0;
TCNT0=0;
}
else
{
// Sorry, we still need to disable timer0 interrupts to avoid wake up in sleep mode
TIMSK0 &= ~(1<<TOIE0);
}
// Timer 1 - vertical sync pulses
pinMode (V_SYNC_PIN, OUTPUT);
TCCR1A=(1<<WGM10) | (1<<WGM11) | (1<<COM1B1);
TCCR1B=(1<<WGM12) | (1<<WGM13) | (1<<CS12) | (1<<CS10); //1024 prescaler
OCR1A = 259; // 16666 / 64 us = 260 (less one)
OCR1B = 0; // 64 / 64 us = 1 (less one)
TIFR1 = (1<<TOV1); // clear overflow flag
TIMSK1 = (1<<TOIE1); // interrupt on overflow on timer 1
// Timer 2 - horizontal sync pulses
pinMode (H_SYNC_PIN, OUTPUT);
TCCR2A=(1<<WGM20) | (1<<WGM21) | (1<<COM2B1); //pin3=COM2B1
TCCR2B=(1<<WGM22) | (1<<CS21); //8 prescaler
OCR2A = 63; // 32 / 0.5 us = 64 (less one)
OCR2B = 7; // 4 / 0.5 us = 8 (less one)
// if (enable_jitter_fix)
{
TIFR2 = (1<<OCF2B); // on end of h-sync pulse
TIMSK2 = (1<<OCIE2B); // on end of h-sync pulse
}
// else
// {
// TIFR2 = (1<<TOV2); // int on start of h-sync pulse
// TIMSK2 = (1<<TOIE2); // int on start of h-sync pulse
// }
// Set up USART in SPI mode (MSPIM)
pinMode(14, OUTPUT);
pinMode(15, OUTPUT);
pinMode(16, OUTPUT);
PORTC = 0;
sei();
}
void ssd1306_vga_controller_128x64_init_no_output(void)
{
ssd1306_intf.spi = 0;
ssd1306_intf.start = vga_controller_init;
ssd1306_intf.stop = vga_controller_stop;
ssd1306_intf.send = vga_controller_send_byte;
ssd1306_intf.send_buffer = vga_controller_send_bytes;
ssd1306_intf.close = vga_controller_close;
}
void ssd1306_vga_controller_128x64_init_enable_output(void)
{
ssd1306_vga_controller_128x64_init_no_output();
init_vga_crt_driver(1);
}
void ssd1306_vga_controller_128x64_init_enable_output_no_jitter_fix(void)
{
ssd1306_vga_controller_128x64_init_no_output();
init_vga_crt_driver(0);
// set_sleep_mode (SLEEP_MODE_IDLE);
}
void ssd1306_debug_print_vga_buffer_128x64(void (*func)(uint8_t))
{
for(int y = 0; y < ssd1306_lcd.height; y++)
{
for(int x = 0; x < ssd1306_lcd.width; x++)
{
uint8_t color = __vga_buffer[(x >> 3) + y * 16] & (1<< (x&0x07));
if (color)
{
func('#');
func('#');
}
else
{
func(' ');
func(' ');
}
}
func('\n');
}
func('\n');
}
#endif
@@ -0,0 +1,292 @@
/*
MIT License
Copyright (c) 2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "intf/vga/vga.h"
// Never include vga96x40_isr.h here!!!
#include "intf/ssd1306_interface.h"
#include "lcd/lcd_common.h"
#include "lcd/vga_commands.h"
#if defined(CONFIG_VGA_AVAILABLE) && defined(CONFIG_VGA_ENABLE) && defined(__AVR_ATmega328P__)
extern uint16_t ssd1306_color;
/* This buffer fits 96x40 pixels
Each 8 pixels are packed to 3 bytes:
BYTE1: B7 R2 G2 B2 B8 R1 G1 B1
BYTE2: G7 R4 G4 B4 G8 R3 G3 B3
BYTE3: R7 R6 G6 B6 R8 R5 G5 B5
Yeah, a little bit complicated, but this allows to quickly unpack structure
*/
// Set to ssd1306 compatible mode by default
static uint8_t s_mode = 0x01;
static uint8_t s_vga_command = 0xFF;
static uint8_t s_vga_arg = 0;
static uint8_t s_column = 0;
static uint8_t s_column_end = 0;
static uint8_t s_cursor_x = 0;
static uint8_t s_cursor_y = 0;
volatile uint8_t s_vga_frames;
static void vga_controller_init(void)
{
s_vga_command = 0xFF;
}
static void vga_controller_stop(void)
{
s_vga_command = 0xFF;
}
static void vga_controller_close(void)
{
}
/* This buffer fits 96x40 pixels
Each 8 pixels are packed to 3 bytes:
BYTE1: B7 R2 G2 B2 B8 R1 G1 B1
BYTE2: G7 R4 G4 B4 G8 R3 G3 B3
BYTE3: R7 R6 G6 B6 R8 R5 G5 B5
Yeah, a little bit complicated, but this allows to quickly unpack structure
*/
static inline void vga_controller_put_pixel3(uint8_t x, uint8_t y, uint8_t color)
{
uint16_t addr = (x >> 3)*3 + (uint16_t)y*36;
uint8_t offset = x & 0x07;
if (addr >= 36*40)
{
return;
}
if (offset < 6)
{
if (x&1)
{
__vga_buffer[addr + (offset>>1)] &= 0x8F;
__vga_buffer[addr + (offset>>1)] |= (color<<4);
}
else
{
__vga_buffer[addr + (offset>>1)] &= 0xF8;
__vga_buffer[addr + (offset>>1)] |= color;
}
}
else if (offset == 6)
{
__vga_buffer[addr+0] &= 0x7F;
__vga_buffer[addr+0] |= ((color & 0x01) << 7);
__vga_buffer[addr+1] &= 0x7F;
__vga_buffer[addr+1] |= ((color & 0x02) << 6);
__vga_buffer[addr+2] &= 0x7F;
__vga_buffer[addr+2] |= ((color & 0x04) << 5);
}
else // if (offset == 7)
{
__vga_buffer[addr+0] &= 0xF7;
__vga_buffer[addr+0] |= ((color & 0x01) << 3);
__vga_buffer[addr+1] &= 0xF7;
__vga_buffer[addr+1] |= ((color & 0x02) << 2);
__vga_buffer[addr+2] &= 0xF7;
__vga_buffer[addr+2] |= ((color & 0x04) << 1);
}
}
static void vga_controller_send_byte4(uint8_t data)
{
if (s_vga_command == 0xFF)
{
s_vga_command = data;
return;
}
if (s_vga_command == 0x40)
{
uint8_t color = ((data & 0x80) >> 5) | ((data & 0x10) >> 3) | ((data & 0x02)>>1);
vga_controller_put_pixel3(s_cursor_x, s_cursor_y, color);
if (s_mode == 0x00)
{
s_cursor_x++;
if (s_cursor_x > s_column_end)
{
s_cursor_x = s_column;
s_cursor_y++;
}
}
else
{
s_cursor_y++;
if ((s_cursor_y & 0x07) == 0)
{
s_cursor_y -= 8;
s_cursor_x++;
}
}
return;
}
// command mode
if (!s_vga_command)
{
s_vga_command = data;
s_vga_arg = 0;
}
if (s_vga_command == VGA_SET_BLOCK)
{
// set block
if (s_vga_arg == 1) { s_column = data; s_cursor_x = data; }
if (s_vga_arg == 2) { s_column_end = data; }
if (s_vga_arg == 3) { s_cursor_y = data; }
if (s_vga_arg == 4) { s_vga_command = 0; }
}
if (s_vga_command == VGA_SET_MODE)
{
if (s_vga_arg == 1) { s_mode = data; s_vga_command = 0; }
}
s_vga_arg++;
}
static void vga_controller_send_bytes(const uint8_t *buffer, uint16_t len)
{
while (len--)
{
ssd1306_intf.send(*buffer);
buffer++;
}
}
static inline void init_vga_crt_driver(uint8_t enable_jitter_fix)
{
cli();
if (enable_jitter_fix)
{
// Configure Timer 0 to calculate jitter fix
TIMSK0=0;
TCCR0A=0;
TCCR0B=1;
OCR0A=0;
OCR0B=0;
TCNT0=0;
}
else
{
// Sorry, we still need to disable timer0 interrupts to avoid wake up in sleep mode
TIMSK0 &= ~(1<<TOIE0);
}
// Timer 1 - vertical sync pulses
pinMode (V_SYNC_PIN, OUTPUT);
TCCR1A=(1<<WGM10) | (1<<WGM11) | (1<<COM1B1);
TCCR1B=(1<<WGM12) | (1<<WGM13) | (1<<CS12) | (1<<CS10); //1024 prescaler
OCR1A = 259; // 16666 / 64 us = 260 (less one)
OCR1B = 0; // 64 / 64 us = 1 (less one)
TIFR1 = (1<<TOV1); // clear overflow flag
TIMSK1 = (1<<TOIE1); // interrupt on overflow on timer 1
// Timer 2 - horizontal sync pulses
pinMode (H_SYNC_PIN, OUTPUT);
TCCR2A=(1<<WGM20) | (1<<WGM21) | (1<<COM2B1); //pin3=COM2B1
TCCR2B=(1<<WGM22) | (1<<CS21); //8 prescaler
OCR2A = 63; // 32 / 0.5 us = 64 (less one)
OCR2B = 7; // 4 / 0.5 us = 8 (less one)
// if (enable_jitter_fix)
{
TIFR2 = (1<<OCF2B); // on end of h-sync pulse
TIMSK2 = (1<<OCIE2B); // on end of h-sync pulse
}
// else
// {
// TIFR2 = (1<<TOV2); // int on start of h-sync pulse
// TIMSK2 = (1<<TOIE2); // int on start of h-sync pulse
// }
// Set up USART in SPI mode (MSPIM)
pinMode(14, OUTPUT);
pinMode(15, OUTPUT);
pinMode(16, OUTPUT);
PORTC = 0;
sei();
}
void ssd1306_vga_controller_96x40_init_no_output(void)
{
ssd1306_intf.spi = 0;
ssd1306_intf.start = vga_controller_init;
ssd1306_intf.stop = vga_controller_stop;
ssd1306_intf.send = vga_controller_send_byte4;
ssd1306_intf.send_buffer = vga_controller_send_bytes;
ssd1306_intf.close = vga_controller_close;
}
void ssd1306_vga_controller_96x40_init_enable_output(void)
{
ssd1306_vga_controller_96x40_init_no_output();
init_vga_crt_driver(1);
}
void ssd1306_vga_controller_96x40_init_enable_output_no_jitter_fix(void)
{
ssd1306_vga_controller_96x40_init_no_output();
init_vga_crt_driver(0);
// set_sleep_mode (SLEEP_MODE_IDLE);
}
void ssd1306_debug_print_vga_buffer_96x40(void (*func)(uint8_t))
{
for(int y = 0; y < ssd1306_lcd.height; y++)
{
for(int x = 0; x < ssd1306_lcd.width; x++)
{
uint8_t color = (__vga_buffer[(y*ssd1306_lcd.width + x)/2] >> ((x&1)<<2)) & 0x0F;
if (color)
{
func('#');
func('#');
}
else
{
func(' ');
func(' ');
}
}
func('\n');
}
func('\n');
}
void ssd1306_vga_delay(uint32_t ms)
{
while (ms >= 16)
{
uint8_t vga_frames;
vga_frames = s_vga_frames;
while (vga_frames == s_vga_frames);
ms-=16;
}
}
#endif
@@ -0,0 +1,312 @@
/*
MIT License
Copyright (c) 2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* @file vga_isr.h VGA ISR code to communicate with VGA-monitor from the sketch directly
*
* @details Please, include this file only once in your sketch, if you want to control
* vga monitor directly from your sketch.
* This header supports different modes: VGA_CONTROLLER_DEBUG, SSD1306_VGA_SLEEP_MODE.
* If you want to use vga_controller module in debug mode without producing VGA output,
* define VGA_CONTROLLER_DEBUG before including this header. If you want to use library with
* AVR sleep mode, then jitter fix is not required, you will able to use TIMER0, so define
* SSD1306_VGA_SLEEP_MODE before including this header.
*/
#ifndef _SSD1306_VGA_ATMEGA328P_ISR_H_
#define _SSD1306_VGA_ATMEGA328P_ISR_H_
#include "intf/vga/vga.h"
#include "ssd1306_hal/io.h"
#ifdef __cplusplus
extern "C" {
#endif
// Including this header defines ISR handlers in your application automatically
#if defined(CONFIG_VGA_AVAILABLE) && defined(CONFIG_VGA_ENABLE) && defined(__AVR_ATmega328P__)
#ifndef DEJITTER_OFFSET
#define DEJITTER_OFFSET -4
#endif
#if defined(CONFIG_VGA_128X64_ENABLE)
static const uint16_t __VGA_VERTICAL_PIXELS = 64;
static const uint16_t __VGA_LINE_BYTES = 16;
static const uint16_t __VGA_PIXEL_HEIGHT = 7;
volatile uint8_t __vga_buffer[16*64] = {0};
static const volatile uint8_t *__VGA_BUFFER_PTR = &__vga_buffer[0];
void ssd1306_vga_controller_128x64_init_no_output(void);
void ssd1306_vga_controller_128x64_init_enable_output(void);
void ssd1306_vga_controller_128x64_init_enable_output_no_jitter_fix(void);
void ssd1306_debug_print_vga_buffer_128x64(void (*func)(uint8_t));
#elif defined(CONFIG_VGA_96X40_ENABLE)
static const uint16_t __VGA_VERTICAL_PIXELS = 40;
static const uint16_t __VGA_LINE_BYTES = 36;
static const uint16_t __VGA_PIXEL_HEIGHT = 10;
volatile uint8_t __vga_buffer[36*40] = {0};
static const volatile uint8_t * __VGA_BUFFER_PTR = &__vga_buffer[0];
void ssd1306_vga_controller_96x40_init_no_output(void);
void ssd1306_vga_controller_96x40_init_enable_output(void);
void ssd1306_vga_controller_96x40_init_enable_output_no_jitter_fix(void);
void ssd1306_debug_print_vga_buffer_96x40(void (*func)(uint8_t));
#else
#error "Please, define one of VGA options"
#endif
#if !defined(VGA_CONTROLLER_DEBUG)
// Total number of lines used in specific scan mode
static const uint16_t VGA_TOTAL_MODE_LINES = __VGA_VERTICAL_PIXELS*__VGA_PIXEL_HEIGHT;
// Lines to skip before starting to draw first line of the screen content
// This includes V-sync signal + front porch
static const uint8_t V_BACKPORCH_LINES = 40;
// Lines to skip before starting to draw first line of the screen content
// This includes V-sync signal + front porch
volatile int s_current_scan_line;
volatile uint8_t s_lines_to_skip;
volatile uint8_t s_scan_line_index;
volatile const uint8_t * volatile s_current_scan_line_data = __VGA_BUFFER_PTR;
extern volatile uint8_t s_vga_frames;
extern unsigned long timer0_millis;
// ISR: Vsync pulse
ISR(TIMER1_OVF_vect)
{
s_current_scan_line = 0;
s_scan_line_index = 0;
s_current_scan_line_data = __VGA_BUFFER_PTR;
s_lines_to_skip = V_BACKPORCH_LINES;
s_vga_frames++;
timer0_millis += 16;
} // end of TIMER1_OVF_vect
#if defined(CONFIG_VGA_128X64_ENABLE)
static inline void /*__attribute__ ((noinline))*/ do_scan_line()
{
// output all pixels
asm volatile(
".rept 16\n\t"
"ld r24, Z+\n\t"
"out %[port], r24\n\t"
"lsr r24\n\t"
"nop\n\t"
"out %[port], r24\n\t"
"lsr r24\n\t"
"out %[port], r24\n\t"
"lsr r24\n\t"
"nop\n\t"
"out %[port], r24\n\t"
"lsr r24\n\t"
"nop\n\t"
"out %[port], r24\n\t"
"lsr r24\n\t"
"nop\n\t"
"out %[port], r24\n\t"
"lsr r24\n\t"
"nop\n\t"
"out %[port], r24\n\t"
"lsr r24\n\t"
"nop\n\t"
"out %[port], r24\n\t"
".endr\n\t"
"nop\n\t"
"ldi r24,0\n\t"
"out %[port], r24 \n\t"
"nop\n\t"
:
: [port] "I" (_SFR_IO_ADDR(PORTC)),
"z" "I" ((uint8_t *)s_current_scan_line_data )
: "r24", "memory"
);
}
#elif defined(CONFIG_VGA_96X40_ENABLE)
static inline void /*__attribute__ ((noinline))*/ do_scan_line()
{
// output all pixels
asm volatile(
".rept 12\n\t"
"ld r24, Z+\n\t" // r24 = 82227111
// "nop\n\t" // to make pixel wider in 96x40 mode
"out %[port], r24\n\t" // 111
"ld r25, Z+\n\t" // r25 = 84447333
"swap r24\n\t" // r24 = 71118222
"out %[port], r24\n\t" // 222
"andi r24, 0x88\n\t" // r24 = 70008000
"ld r20, Z+\n\t" // r20 = 86667555
"out %[port], r25\n\t" // 333
"swap r25\n\t" // r25 = 73338444
"lsr r24\n\t" // r24 = 00080007
"lsr r24\n\t" // r24 = 00800070
"out %[port], r25\n\t" // 444
"andi r25, 0x88\n\t" // r25 = 70008000
"lsr r24\n\t" // r24 = 08000700
"lsr r25\n\t" // r25 = 00080007
"out %[port], r20\n\t" // 555
"swap r20\n\t" // r20 = 75558666
"lsr r25\n\t" // r25 = 00800070
"or r24, r25\n\t" // r24 = 08800770
"out %[port], r20\n\t" // 666
"andi r20, 0x88\n\t" // r20 = 70008000
"lsr r20\n\t" // r20 = 00080007 b
"or r24, r20\n\t" // r24 = 08880777 rgb
"out %[port], r24\n\t" // 777
"swap r24\n\t" // r24 = 07770888
// "nop\n\t" // to make pixel wider in 96x40 mode
"nop\n\t"
"out %[port], r24\n\t" // 888
".endr\n\t"
// "nop\n\t" // to make pixel wider in 96x40 mode
"nop\n\t"
"ldi r24,0\n\t"
"out %[port], r24 \n\t"
"nop\n\t"
:
: [port] "I" (_SFR_IO_ADDR(PORTC)),
"z" "I" ((uint8_t *)s_current_scan_line_data )
: "r24", "r25", "r20", "memory"
);
}
#endif
//#ifdef SSD1306_VGA_SLEEP_MODE
//ISR(TIMER2_OVF_vect) // for start of h-sync pulse
//#else
ISR(TIMER2_COMPB_vect) // for end of h-sync pulse
//#endif
{
// ISR should work as fast as possible
if (s_lines_to_skip)
{
s_lines_to_skip--;
return;
}
else if (s_current_scan_line >= VGA_TOTAL_MODE_LINES)
{
return;
}
#ifndef SSD1306_VGA_SLEEP_MODE
// This is dejitter code, it purpose to start pixels output at the same offset after h-sync
asm volatile(
" lds r24, %[timer0] \n\t" //
" subi r24, %[toffset] \n\t" // some offset, calculated experimentally
" andi r24, 7 \n\t" // use module 8 value from Timer 0 counter
" ldi r31, pm_hi8(LW) \n\t" // load label address
" ldi r30, pm_lo8(LW) \n\t" //
" add r30, r24 \n\t" // no need to multiply by 2 since AVR addresses are half-values
" adc r31, __zero_reg__ \n\t" //
" ijmp \n\t" //
"LW: \n\t" //
" nop \n\t" //
" nop \n\t" //
" nop \n\t" //
" nop \n\t" //
" nop \n\t" //
" nop \n\t" //
" nop \n\t" //
:
: [timer0] "i" (&TCNT0),
[toffset] "i" ((uint8_t)DEJITTER_OFFSET)
: "r30", "r31", "r24", "r25");
#endif
do_scan_line();
s_current_scan_line++;
s_scan_line_index++;
if ( s_scan_line_index >= __VGA_PIXEL_HEIGHT )
{
s_scan_line_index=0;
s_current_scan_line_data += __VGA_LINE_BYTES;
}
}
#endif // VGA_CONTROLLER_DEBUG
#if defined(CONFIG_VGA_128X64_ENABLE)
static inline void ssd1306_vga_controller_init(void)
{
// if there is no builtin support then only debug mode is available
#if defined(VGA_CONTROLLER_DEBUG)
ssd1306_vga_controller_128x64_init_no_output();
#elif defined(SSD1306_VGA_SLEEP_MODE)
ssd1306_vga_controller_128x64_init_enable_output_no_jitter_fix();
#else
ssd1306_vga_controller_128x64_init_enable_output();
#endif
}
void ssd1306_debug_print_vga_buffer(void (*func)(uint8_t))
{
ssd1306_debug_print_vga_buffer_128x64(func);
}
#elif defined(CONFIG_VGA_96X40_ENABLE)
static inline void ssd1306_vga_controller_init(void)
{
// if there is no builtin support then only debug mode is available
#if defined(VGA_CONTROLLER_DEBUG)
ssd1306_vga_controller_96x40_init_no_output();
#elif defined(SSD1306_VGA_SLEEP_MODE)
ssd1306_vga_controller_96x40_init_enable_output_no_jitter_fix();
#else
ssd1306_vga_controller_96x40_init_enable_output();
#endif
}
void ssd1306_debug_print_vga_buffer(void (*func)(uint8_t))
{
ssd1306_debug_print_vga_buffer_96x40(func);
}
#endif // CONFIG_VGA_XXX_ENABLE
#endif // SSD1306_BUILTIN_VGA_SUPPORT
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,286 @@
/*
* Credits to https://github.com/bitluni/ESP32CompositeVideo
*/
#include "CompositeOutput.h"
#if defined(CONFIG_VGA_AVAILABLE) && defined(CONFIG_VGA_ENABLE) && defined(__XTENSA__)
#include "driver/i2s.h"
#define I2S_VGA_SAMPLE_RATE (4000000)
static const i2s_port_t I2S_PORT = (i2s_port_t)I2S_NUM_0;
const TechProperties PALProperties = {
.lineMicros = 64,
.syncMicros = 4.7,
.blankEndMicros = 10.4,
.backMicros = 1.65,
.shortVSyncMicros = 2.35,
.overscanLeftMicros = 1.6875,
.overscanRightMicros = 1.6875,
.syncVolts = -0.3,
.blankVolts = 0.0,
.blackVolts = 0.005,//specs 0.0,
.whiteVolts = 0.7,
.lines = 625,
.linesFirstTop = 23,
.linesOverscanTop = 9,
.linesOverscanBottom = 9,
.imageAspect = 4./3.
};
const TechProperties NTSCProperties = {
.lineMicros = 63.492,
.syncMicros = 4.7,
.blankEndMicros = 9.2,
.backMicros = 1.5,
.shortVSyncMicros = 2.3,
.overscanLeftMicros = 0,//1.3,
.overscanRightMicros = 0,//1,
.syncVolts = -0.286,
.blankVolts = 0.0,
.blackVolts = 0.05, //specs 0.054,
.whiteVolts = 0.714,
.lines = 525,
.linesFirstTop = 20,
.linesOverscanTop = 6,
.linesOverscanBottom = 9,
.imageAspect = 4./3.
};
CompositeOutput::CompositeOutput(Mode mode, double Vcc)
:properties((mode==NTSC) ? NTSCProperties: PALProperties)
{
double dacPerVolt = 255.0 / Vcc;
levelSync = 0;
levelBlank = (properties.blankVolts - properties.syncVolts) * dacPerVolt + 0.5;
levelBlack = (properties.blackVolts - properties.syncVolts) * dacPerVolt + 0.5;
levelWhite = (properties.whiteVolts - properties.syncVolts) * dacPerVolt + 0.5;
grayValues = levelWhite - levelBlack + 1;
}
void CompositeOutput::init(int xres, int yres, int bpp)
{
const int LINES_SYNC_TOP = 5;
const int LINES_SYNC_BOTTOM = 3;
m_buffer_width = xres;
m_buffer_height = yres;
m_bpp = bpp;
linesOdd = properties.lines / 2;
linesEven = properties.lines - linesOdd;
linesEvenActive = linesEven - properties.linesFirstTop - LINES_SYNC_BOTTOM;
linesOddActive = linesOdd - properties.linesFirstTop - LINES_SYNC_BOTTOM;
linesEvenVisible = linesEvenActive - properties.linesOverscanTop - properties.linesOverscanBottom;
linesOddVisible = linesOddActive - properties.linesOverscanTop - properties.linesOverscanBottom;
targetYresOdd = (yres / 2 < linesOddVisible) ? yres / 2 : linesOddVisible;
targetYresEven = (yres - targetYresOdd < linesEvenVisible) ? yres - targetYresOdd : linesEvenVisible;
targetYres = targetYresEven + targetYresOdd;
linesEvenBlankTop = properties.linesFirstTop - LINES_SYNC_TOP + properties.linesOverscanTop + (linesEvenVisible - targetYresEven) / 2;
linesEvenBlankBottom = linesEven - linesEvenBlankTop - targetYresEven - LINES_SYNC_BOTTOM;
linesOddBlankTop = linesEvenBlankTop;
linesOddBlankBottom = linesOdd - linesOddBlankTop - targetYresOdd - LINES_SYNC_BOTTOM;
double samplesPerSecond = I2S_VGA_SAMPLE_RATE;
double samplesPerMicro = samplesPerSecond * 0.000001;
m_samples_per_line = (int)(samplesPerMicro * properties.lineMicros + 1.5) & ~1;
samplesSync = samplesPerMicro * properties.syncMicros + 0.5;
samplesBlank = samplesPerMicro * (properties.blankEndMicros - properties.syncMicros + properties.overscanLeftMicros) + 0.5;
samplesBack = samplesPerMicro * (properties.backMicros + properties.overscanRightMicros) + 0.5;
samplesActive = m_samples_per_line - samplesSync - samplesBlank - samplesBack;
targetXres = xres < samplesActive ? xres : samplesActive;
samplesVSyncShort = samplesPerMicro * properties.shortVSyncMicros + 0.5;
samplesBlackLeft = (samplesActive - targetXres) / 2;
samplesBlackRight = samplesActive - targetXres - samplesBlackLeft;
// pixelAspect = (float(samplesActive) / (linesEvenVisible + linesOddVisible)) / properties.imageAspect;
line = (uint16_t*)malloc(sizeof(uint16_t) * m_samples_per_line * 2);
m_ptr = line;
m_end = line + m_samples_per_line * 2;
init_hardware();
}
void CompositeOutput::init_hardware()
{
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN),
.sample_rate = I2S_VGA_SAMPLE_RATE, //not really used
.bits_per_sample = (i2s_bits_per_sample_t)I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT,
.communication_format = I2S_COMM_FORMAT_I2S_MSB,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 2,
.dma_buf_len = m_samples_per_line //a buffer per line
};
i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL); //start i2s driver
i2s_set_pin(I2S_PORT, NULL); //use internal DAC
i2s_set_sample_rates(I2S_PORT, I2S_VGA_SAMPLE_RATE); //dummy sample rate, since the function fails at high values
}
void CompositeOutput::fillValues(uint8_t value, int count)
{
for(int j = 0; j < count; j++)
{
*m_ptr = ((uint16_t)value << 8);
m_ptr++;
}
}
void CompositeOutput::sendFrameHalfResolution(const uint8_t *frame)
{
generate_long_sync(); // 1
generate_long_sync(); // 2
generate_long_short_sync(); // 3
generate_short_sync(); // 4
generate_short_sync(); // 5
for (int y = 0; y < linesEvenBlankTop; y++)
{
generate_blank_line(); // top blank lines
}
for (int y = 0; y < targetYresEven; y++)
{
generate_line_from_buffer( &frame[(y >> 3)*(m_buffer_width * m_bpp / 8)] ); // real data
}
for (int y = 0; y < linesEvenBlankBottom; y++)
{
generate_blank_line(); // bottom blank lines
}
generate_short_sync(); // 311
generate_short_sync(); // 312
generate_short_long_sync(); // 313
generate_long_sync(); // 314
generate_long_sync(); // 315
generate_short_sync(); // 316
generate_short_sync(); // 317
generate_short_blank_sync(); // 318
for (int y = 0; y < linesOddBlankTop; y++)
{
generate_blank_line(); // top blank lines
}
for (int y = 0; y < targetYresOdd; y++)
{
generate_line_from_buffer( &frame[(y>>3)*(m_buffer_width * m_bpp / 8)] ); // real data
}
for(int y = 0; y < linesOddBlankBottom; y++)
{
generate_blank_line(); // bottom blank lines
}
generate_blank_short_sync(); // 623
generate_short_sync(); // 624
generate_short_sync(); // 625
if (m_ptr != line) // force to send data
{
size_t bytes_written;
i2s_write(I2S_PORT, (char*)line, (m_ptr - line) * sizeof(uint16_t), &bytes_written, portMAX_DELAY);
m_ptr = line;
}
}
void CompositeOutput::generate_long_sync()
{
for (int i = 0; i < 2; i++)
{
fillValues(levelSync, m_samples_per_line / 2 - samplesVSyncShort);
fillValues(levelBlank, samplesVSyncShort);
}
check_buffer();
}
void CompositeOutput::generate_short_sync()
{
for (int i = 0; i < 2; i++)
{
fillValues(levelSync, samplesVSyncShort);
fillValues(levelBlank, m_samples_per_line / 2 - samplesVSyncShort);
}
check_buffer();
}
void CompositeOutput::generate_long_short_sync()
{
fillValues(levelSync, m_samples_per_line / 2 - samplesVSyncShort);
fillValues(levelBlank, samplesVSyncShort);
fillValues(levelSync, samplesVSyncShort);
fillValues(levelBlank, m_samples_per_line / 2 - samplesVSyncShort);
check_buffer();
}
void CompositeOutput::generate_short_long_sync()
{
fillValues(levelSync, samplesVSyncShort);
fillValues(levelBlank, m_samples_per_line / 2 - samplesVSyncShort);
fillValues(levelSync, m_samples_per_line / 2 - samplesVSyncShort);
fillValues(levelBlank, samplesVSyncShort);
check_buffer();
}
void CompositeOutput::generate_short_blank_sync()
{
fillValues(levelSync, samplesVSyncShort);
fillValues(levelBlank, m_samples_per_line / 2 - samplesVSyncShort);
fillValues(levelBlank, m_samples_per_line / 2);
check_buffer();
}
void CompositeOutput::generate_blank_short_sync()
{
fillValues(levelSync, samplesSync);
fillValues(levelBlank, m_samples_per_line / 2 - samplesSync);
fillValues(levelSync, samplesVSyncShort);
fillValues(levelBlank, m_samples_per_line / 2 - samplesVSyncShort);
check_buffer();
}
void CompositeOutput::generate_blank_line()
{
fillValues(levelSync, samplesSync);
fillValues(levelBlank, samplesBlank);
fillValues(levelBlack, samplesActive);
fillValues(levelBlank, samplesBack);
check_buffer();
}
const uint8_t* CompositeOutput::generate_line_from_buffer(const uint8_t *pixels)
{
fillValues(levelSync, samplesSync);
fillValues(levelBlank, samplesBlank);
fillValues(levelBlack, samplesBlackLeft);
for (int x = 0; x < targetXres; x++)
{
uint8_t color = pixels[(x >> 3)] & (1<< (x&0x07));
// *m_ptr = (levelBlack + pixels[x]) << 8;
*m_ptr = (levelBlack + (color ? 0x80: 0x00 )) << 8;
m_ptr++;
}
fillValues(levelBlack, samplesBlackRight);
fillValues(levelBlank, samplesBack);
check_buffer();
return pixels + m_buffer_width * m_bpp / 8;
// return pixels + targetXres;
}
void CompositeOutput::check_buffer()
{
if (m_ptr == m_end)
{
size_t bytes_written;
i2s_write(I2S_PORT, (char*)line, sizeof(uint16_t) * (m_end - line), &bytes_written, portMAX_DELAY);
m_ptr = line;
}
}
#endif
@@ -0,0 +1,112 @@
/*
* Credits to https://github.com/bitluni/ESP32CompositeVideo
*/
#pragma once
#include "ssd1306_hal/io.h"
#if defined(CONFIG_VGA_AVAILABLE) && defined(CONFIG_VGA_ENABLE) && defined(__XTENSA__)
#include <stdint.h>
#include "driver/i2s.h"
typedef struct
{
float lineMicros;
float syncMicros;
float blankEndMicros;
float backMicros;
float shortVSyncMicros;
float overscanLeftMicros;
float overscanRightMicros;
float syncVolts;
float blankVolts;
float blackVolts;
float whiteVolts;
short lines;
short linesFirstTop;
short linesOverscanTop;
short linesOverscanBottom;
float imageAspect;
} TechProperties;
class CompositeOutput
{
public:
enum Mode
{
PAL,
NTSC
};
CompositeOutput(Mode mode, double Vcc = 3.3);
void init(int xres, int yres, int bpp);
void fillValues(uint8_t value, int count);
void sendFrameHalfResolution(const uint8_t *frame);
private:
const TechProperties &properties;
int m_samples_per_line = 0;
int samplesSync = 0;
int samplesBlank = 0;
int samplesBack = 0;
int samplesActive = 0;
int samplesBlackLeft = 0;
int samplesBlackRight = 0;
int samplesVSyncShort = 0;
int samplesVSyncLong = 0;
uint8_t levelSync = 0;
uint8_t levelBlank = 0;
uint8_t levelBlack = 0;
uint8_t levelWhite = 0;
uint8_t grayValues = 0;
int targetXres = 0;
int targetYres = 0;
int targetYresEven = 0;
int targetYresOdd = 0;
int linesEven = 0;
int linesOdd = 0;
int linesEvenActive = 0;
int linesOddActive = 0;
int linesEvenVisible = 0;
int linesOddVisible = 0;
int linesEvenBlankTop = 0;
int linesEvenBlankBottom = 0;
int linesOddBlankTop = 0;
int linesOddBlankBottom = 0;
int m_buffer_width = 0;
int m_buffer_height = 0;
int m_bpp = 0;
// float pixelAspect;
uint16_t *line = nullptr;
uint16_t *m_end = nullptr;
uint16_t *m_ptr = nullptr;
void init_hardware();
void check_buffer();
void generate_vsync();
void generate_long_sync();
void generate_short_sync();
void generate_long_short_sync();
void generate_short_long_sync();
void generate_short_blank_sync();
void generate_blank_short_sync();
void generate_blank_line();
const uint8_t * generate_line_from_buffer(const uint8_t * buffer);
};
#endif
@@ -0,0 +1,211 @@
/*
MIT License
Copyright (c) 2019, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "intf/ssd1306_interface.h"
#include "intf/vga/vga.h"
#include "lcd/lcd_common.h"
#include "lcd/vga_commands.h"
#if defined(CONFIG_VGA_AVAILABLE) && defined(CONFIG_VGA_ENABLE) && defined(ESP32)
#include "CompositeOutput.h"
//#define VGA_CONTROLLER_DEBUG
static uint8_t *__vga_buffer = nullptr;
extern uint16_t ssd1306_color;
// Set to ssd1306 compatible mode by default
static uint8_t s_mode = 0x01;
static uint8_t s_vga_command = 0xFF;
static uint8_t s_vga_arg = 0;
static uint8_t s_column = 0;
static uint8_t s_column_end = 0;
static uint8_t s_cursor_x = 0;
static uint8_t s_cursor_y = 0;
static uint8_t s_width = 0;
static uint8_t s_height = 0;
static uint8_t s_bpp = 0;
static CompositeOutput output(CompositeOutput::PAL);
static void compositeCore(void *data)
{
while (true)
{
//just send the graphics frontbuffer whithout any interruption
output.sendFrameHalfResolution(__vga_buffer);
}
}
static void vga_controller_init(void)
{
s_vga_command = 0xFF;
}
#ifdef VGA_CONTROLLER_DEBUG
#include <stdio.h>
void uart_send_byte(uint8_t data)
{
printf("%c", data);
}
#endif
static void vga_controller_stop(void)
{
s_vga_command = 0xFF;
#ifdef VGA_CONTROLLER_DEBUG
ssd1306_debug_print_vga_buffer( uart_send_byte );
#endif
}
static void vga_controller_close(void)
{
}
/*
* Function sends 8 vertical pixels to buffer
*/
static inline void vga_controller_put_pixels(uint8_t x, uint8_t y, uint8_t pixels)
{
uint16_t addr = (x >> 3) + (uint16_t)(y * 16);
uint8_t offset = x & 0x07;
uint8_t mask = 1 << offset;
if (addr >= 16*64)
{
return;
}
for (uint8_t i=8; i>0; i--)
{
if (pixels & 0x01) __vga_buffer[addr] |= mask;
else __vga_buffer[addr] &= ~mask;
addr += 16;
pixels >>= 1;
}
}
static void vga_controller_send_byte(uint8_t data)
{
if (s_vga_command == 0xFF)
{
s_vga_command = data;
return;
}
if (s_vga_command == 0x40)
{
vga_controller_put_pixels(s_cursor_x, s_cursor_y, data);
s_cursor_x++;
if (s_cursor_x > s_column_end)
{
s_cursor_x = s_column;
s_cursor_y += 8;
}
return;
}
// command mode
if (!s_vga_command)
{
s_vga_command = data;
s_vga_arg = 0;
}
if (s_vga_command == VGA_SET_BLOCK)
{
// set block
if (s_vga_arg == 1)
{
s_column = data >= ssd1306_lcd.width ? ssd1306_lcd.width - 1 : data ;
s_cursor_x = s_column;
}
if (s_vga_arg == 2) { s_column_end = data >= ssd1306_lcd.width ? ssd1306_lcd.width - 1 : data; }
if (s_vga_arg == 3) { s_cursor_y = (data << 3); }
if (s_vga_arg == 4) { s_vga_command = 0; }
}
else if (s_vga_command == VGA_SET_MODE)
{
if (s_vga_arg == 1) { s_mode = data; s_vga_command = 0; }
if (s_vga_arg == 2) { s_vga_command = 0; }
}
else if (s_vga_command == VGA_SET_RESOLUTION )
{
if (s_vga_arg == 1) { s_width = data; }
if (s_vga_arg == 2) { s_height = data; }
if (s_vga_arg == 3) { s_bpp = data; s_vga_command = 0; }
}
else if (s_vga_command == VGA_DISPLAY_ON )
{
__vga_buffer = (uint8_t *) malloc(s_width * s_height * s_bpp / 8);
output.init(s_width, s_height, s_bpp);
xTaskCreatePinnedToCore(compositeCore, "c", 1024, NULL, 1, NULL, 0);
s_vga_command = 0;
}
s_vga_arg++;
}
static void vga_controller_send_bytes(const uint8_t *buffer, uint16_t len)
{
while (len--)
{
ssd1306_intf.send(*buffer);
buffer++;
}
}
extern "C" void ssd1306_CompositeVideoInit_esp32(void);
void ssd1306_CompositeVideoInit_esp32(void)
{
ssd1306_intf.spi = 0;
ssd1306_intf.start = vga_controller_init;
ssd1306_intf.stop = vga_controller_stop;
ssd1306_intf.send = vga_controller_send_byte;
ssd1306_intf.send_buffer = vga_controller_send_bytes;
ssd1306_intf.close = vga_controller_close;
}
void ssd1306_debug_print_vga_buffer_128x64(void (*func)(uint8_t))
{
for(int y = 0; y < ssd1306_lcd.height; y++)
{
for(int x = 0; x < ssd1306_lcd.width; x++)
{
uint8_t color = __vga_buffer[(x >> 3) + y * 16] & (1<< (x&0x07));
if (color)
{
func('#');
}
else
{
func(' ');
}
}
func('\n');
}
func('\n');
}
void ssd1306_debug_print_vga_buffer(void (*func)(uint8_t))
{
ssd1306_debug_print_vga_buffer_128x64(func);
}
#endif
+41
View File
@@ -0,0 +1,41 @@
/*
MIT License
Copyright (c) 2019, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "ssd1306_hal/io.h"
#include "vga.h"
#if defined(CONFIG_VGA_AVAILABLE) && defined(CONFIG_VGA_ENABLE) && defined(ESP32)
extern void ssd1306_CompositeVideoInit_esp32(void);
void ssd1306_vgaInit()
{
ssd1306_CompositeVideoInit_esp32();
}
#else
void ssd1306_vgaInit()
{
}
#endif
+86
View File
@@ -0,0 +1,86 @@
/*
MIT License
Copyright (c) 2018-2019, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* @file vga.h VGA basic data. Do not include this header in your project!!!
*/
#ifndef _SSD1306_VGA_H_
#define _SSD1306_VGA_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "ssd1306_hal/io.h"
#if defined(CONFIG_VGA_AVAILABLE) && defined(CONFIG_VGA_ENABLE)
#ifndef DOXYGEN_SHOULD_SKIP_THIS
#if defined(__AVR_ATmega328P__)
/* TODO: Move defines out of this file */
static const uint8_t H_SYNC_PIN = 3;
static const uint8_t V_SYNC_PIN = 10;
extern volatile uint8_t __vga_buffer[];
/**
* Make ms milliseconds delay. This function has very low precision: 16ms.
*
* @param ms time in milliseconds
*/
void ssd1306_vga_delay(uint32_t ms);
#elif defined(ESP32)
#endif
#endif // DOXYGEN_SHOULD_SKIP_THIS
/**
* Prints vga buffer in text form using passed callback
*
* @param func callback to use for printing single character
*/
void ssd1306_debug_print_vga_buffer(void (*func)(uint8_t));
/**
* Initializes hardware VGA controller
* Be careful, this function reinitialized Atmega328p timers.
* delay() function will not work after call.
*/
//void ssd1306_vga_controller_init(void);
#endif
/**
*
*/
void ssd1306_vgaInit(void);
#ifdef __cplusplus
}
#endif
#endif
+142
View File
@@ -0,0 +1,142 @@
/*
MIT License
Copyright (c) 2019, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "composite_video.h"
#include "vga_commands.h"
#include "lcd_common.h"
#include "intf/ssd1306_interface.h"
#include "ssd1306_hal/io.h"
#include "intf/vga/vga.h"
static const uint8_t PROGMEM s_composite128x64_initData[] =
{
#ifdef SDL_EMULATION
SDL_LCD_SSD1306,
0x00,
#endif
VGA_SET_RESOLUTION,128,64,1,
VGA_DISPLAY_ON,
};
static uint8_t s_column = 0;
static uint8_t s_page = 0;
extern uint16_t ssd1306_color;
static void vga_set_block1(lcduint_t x, lcduint_t y, lcduint_t w)
{
uint8_t rx = w ? (x + w - 1) : (ssd1306_lcd.width - 1);
s_column = x;
s_page = y;
ssd1306_intf.start();
ssd1306_intf.send(0x00);
ssd1306_intf.send(VGA_SET_BLOCK);
ssd1306_intf.send(s_column);
ssd1306_intf.send(rx);
ssd1306_intf.send(s_page * 8);
ssd1306_intf.stop();
ssd1306_intf.start();
ssd1306_intf.send(0x40);
}
static void vga_next_page1(void)
{
ssd1306_intf.stop();
vga_set_block1(s_column,s_page+1,0);
}
static void vga_set_block2(lcduint_t x, lcduint_t y, lcduint_t w)
{
uint8_t rx = w ? (x + w - 1) : (ssd1306_lcd.width - 1);
ssd1306_intf.start();
ssd1306_intf.send(0x00);
ssd1306_intf.send(VGA_SET_BLOCK); // set block
ssd1306_intf.send(x);
ssd1306_intf.send(rx);
ssd1306_intf.send(y);
ssd1306_intf.stop();
ssd1306_intf.start();
ssd1306_intf.send(0x40);
}
static void vga_next_page2(void)
{
}
#if 0
static void vga_send_pixels(uint8_t data)
{
for (uint8_t i=8; i>0; i--)
{
if ( data & 0x01 )
{
ssd1306_intf.send( (uint8_t)ssd1306_color );
}
else
{
ssd1306_intf.send( 0B00000000 );
}
data >>= 1;
}
}
#endif
static void vga_set_mode(lcd_mode_t mode)
{
if (mode == LCD_MODE_NORMAL)
{
ssd1306_lcd.set_block = vga_set_block2;
ssd1306_lcd.next_page = vga_next_page2;
}
else if (mode == LCD_MODE_SSD1306_COMPAT)
{
ssd1306_lcd.set_block = vga_set_block1;
ssd1306_lcd.next_page = vga_next_page1;
}
ssd1306_intf.start();
ssd1306_intf.send( 0x00 );
ssd1306_intf.send( VGA_SET_MODE );
ssd1306_intf.send( (uint8_t)mode );
ssd1306_intf.stop();
// empty for a while
}
void composite_video_128x64_mono_init(void)
{
// init vga interface
ssd1306_vgaInit();
// init display
ssd1306_lcd.type = LCD_TYPE_SSD1306;
ssd1306_lcd.width = 128;
ssd1306_lcd.height = 64;
ssd1306_lcd.set_block = vga_set_block2;
ssd1306_lcd.next_page = vga_next_page2;
ssd1306_lcd.send_pixels1 = ssd1306_intf.send;
ssd1306_lcd.send_pixels_buffer1 = ssd1306_intf.send_buffer;
ssd1306_lcd.set_mode = vga_set_mode;
ssd1306_configureI2cDisplay( s_composite128x64_initData, sizeof(s_composite128x64_initData));
}
+63
View File
@@ -0,0 +1,63 @@
/*
MIT License
Copyright (c) 2019, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* @file vga_monitor.h Interface to vga_monitor
*/
#ifndef _SSD1306_COMPOSITE_VIDEO_H_
#define _SSD1306_COMPOSITE_VIDEO_H_
#include "ssd1306_hal/io.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @ingroup LCD_INTERFACE_API
* @{
*/
/**
* @brief Inits 128x64 monochrome VGA display.
*
* Inits 128x64 monochrome VGA display. This mode supports 2 colors: black and white.
* User must init communication interface (uart) for vga client mode or init vga
* interface for host mode prior to calling this function.
*
* @see ssd1306_uartInit_Builtin()
* @see ssd1306_vga_controller_init()
*/
void composite_video_128x64_mono_init(void);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif
+150
View File
@@ -0,0 +1,150 @@
/*
MIT License
Copyright (c) 2017-2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "lcd/lcd_common.h"
#include "intf/ssd1306_interface.h"
#include "intf/spi/ssd1306_spi.h"
#include <stddef.h>
#define CMD_ARG 0xFF
#define CMD_DELAY 0xFF
ssd1306_lcd_t ssd1306_lcd = { 0 };
void ssd1306_sendData(uint8_t data)
{
ssd1306_dataStart();
ssd1306_lcd.send_pixels1( data );
ssd1306_intf.stop();
}
void ssd1306_configureI2cDisplay(const uint8_t *config, uint8_t configSize)
{
ssd1306_commandStart();
for( uint8_t i=0; i<configSize; i++)
{
uint8_t data = pgm_read_byte(&config[i]);
ssd1306_intf.send(data);
}
ssd1306_intf.stop();
}
void ssd1306_configureSpiDisplay(const uint8_t *config, uint8_t configSize)
{
ssd1306_intf.start();
ssd1306_spiDataMode(0);
for( uint8_t i=0; i<configSize; i++)
{
uint8_t data = pgm_read_byte(&config[i]);
if (data == CMD_ARG)
{
data = pgm_read_byte(&config[++i]);
ssd1306_spiDataMode(1);
ssd1306_intf.send(data);
ssd1306_spiDataMode(0);
}
else
{
ssd1306_intf.send(data);
}
}
ssd1306_intf.stop();
}
void ssd1306_configureSpiDisplay2(const uint8_t *config, uint8_t configSize)
{
uint8_t command = 1;
int8_t args = -1;
ssd1306_intf.start();
ssd1306_spiDataMode(0);
for( uint8_t i=0; i<configSize; i++)
{
uint8_t data = pgm_read_byte(&config[i]);
if ( command )
{
if ( command == CMD_DELAY )
{
command = 1;
delay( data == 0xFF ? 500: data );
}
else
{
ssd1306_intf.send(data);
command = 0;
args = -1;
}
}
else
{
if (args < 0)
{
if ( data >= 128 )
{
command = data;
}
else if ( data > 0 )
{
args = data;
ssd1306_spiDataMode(1);
}
else
{
command = 1;
}
}
else
{
args--;
ssd1306_intf.send(data);
if ( !args )
{
command = 1;
ssd1306_spiDataMode(0);
}
}
}
}
ssd1306_intf.stop();
}
void ssd1306_setMode(lcd_mode_t mode)
{
if (ssd1306_lcd.set_mode)
{
ssd1306_lcd.set_mode( mode );
}
}
void ssd1306_resetController(int8_t rstPin, uint8_t delayMs)
{
pinMode(rstPin, OUTPUT);
digitalWrite(rstPin, HIGH);
/* Wait at least 10ms after VCC is up for LCD */
delay(10);
/* Perform reset operation of LCD display */
digitalWrite(rstPin, LOW);
delay(delayMs);
digitalWrite(rstPin, HIGH);
}
+459
View File
@@ -0,0 +1,459 @@
/*
MIT License
Copyright (c) 2017-2019, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* @file lcd_common.h global lcd settings
*/
#ifndef _LCD_COMMON_H_
#define _LCD_COMMON_H_
#include "ssd1306_hal/io.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup LCD_INTERFACE_API OLEDs: initialization and service functions
* @{
* @brief LCD initialization and service functions
*
* @details This group contains API functions for OLED displays initialization and
* direct programming of GDRAM. This API can be used to create your own
* graphics functions.
*/
/**
* Enumeration, describing display type
*/
typedef enum
{
/** Default type of LCD display: ssd1306 oled */
LCD_TYPE_SSD1306,
/** Experimental type of LCD display: pcd8544 led */
LCD_TYPE_PCD8544,
/** Support for sh1106 OLED display */
LCD_TYPE_SH1106,
/** Default type of LCD display: ssd1331 oled */
LCD_TYPE_SSD1331,
/** User LCD type */
LCD_TYPE_CUSTOM,
} lcd_type_t;
/**
* Available lcd modes used by the library.
* LCD_MODE_SSD1306_COMPAT is compatible mode, which should be used
* with standard monochrome functions.
*/
typedef enum
{
/**
* Normal mode RGB displays. All ssd1306 monochrome direct draw
* functions do not work in this mode.
*/
LCD_MODE_NORMAL = 0,
/**
* ssd1306 compatible mode. This is special mode, that allows
* to use ssd1306 monochrome direct draw functions, but RGB
* functions will not work.
*/
LCD_MODE_SSD1306_COMPAT = 1,
} lcd_mode_t;
/**
* Structure, describing display driver configuration
*/
typedef struct
{
/** Current selected lcd display type */
lcd_type_t type;
/** Current display width */
lcduint_t width;
/** Current display height */
lcduint_t height;
/**
* @brief Sets block in RAM of lcd display controller to write data to.
*
* Sets block in RAM of lcd display controller to write data to.
* For ssd1306 it uses horizontal addressing mode, while for
* sh1106 the function uses page addressing mode.
* Width can be specified as 0, thus the library will set the right boundary to
* region of RAM block to the right column of the display.
* @param x - column (left region)
* @param y - page (top page of the block)
* @param w - width of the block in pixels to control
*
* @warning - this function initiates session (i2c or spi) and do not close it.
* To close session, please, use ssd1306_intf.stop().
*/
void (*set_block)(lcduint_t x, lcduint_t y, lcduint_t w);
/**
* Switches to the start of next RAM page for the block, specified by
* set_block().
* For ssd1306 it does nothing, while for sh1106 the function moves cursor to
* next page.
*/
void (*next_page)(void);
/**
* Sends 8 monochrome vertical pixels to OLED driver.
* @param data - byte, representing 8 pixels.
*/
void (*send_pixels1)(uint8_t data);
/**
* Sends buffer containing 8 monochrome vertical pixels, encoded in each byte.
* @param buffer - buffer containing monochrome pixels.
* @param len - length of buffer in bytes.
*/
void (*send_pixels_buffer1)(const uint8_t *buffer, uint16_t len);
/**
* @brief Sends RGB pixel encoded in 3-3-2 format to OLED driver.
* Sends RGB pixel encoded in 3-3-2 format to OLED driver.
* @param data - byte, representing RGB8 pixel.
*/
void (*send_pixels8)(uint8_t data);
/**
* @brief Sends RGB pixel encoded in 5-6-5 format to OLED driver.
* Sends RGB pixel encoded in 5-6-5 format to OLED driver.
* @param data 16-bit word, representing RGB16 pixel
*/
void (*send_pixels16)(uint16_t data);
/**
* @brief Sets library display mode for direct draw functions.
*
* Sets library display mode for direct draw functions.
* There are currently 2 modes supported: LCD_MODE_SSD1306_COMPAT and
* LCD_MODE_NORMAL. In general, ssd1306 compatible mode uses different GDRAM
* addressing mode, than normal mode, intended for using with RBG full-color functions.
*
* @param mode lcd mode to activate.
* @see LCD_MODE_SSD1306_COMPAT
* @see LCD_MODE_NORMAL
* @see lcd_mode_t
*/
void (*set_mode)(lcd_mode_t mode);
} ssd1306_lcd_t;
/**
* Structure containing callback to low level function for currently enabled display
*/
extern ssd1306_lcd_t ssd1306_lcd;
/**
* Current display height
* @deprecated Use ssd1306_lcd.height instead.
*/
#define s_displayHeight ssd1306_lcd.height
/**
* Current display width
* @deprecated Use ssd1306_lcd.width instead.
*/
#define s_displayWidth ssd1306_lcd.width
/**
* Current selected lcd display type
* @deprecated Use ssd1306_lcd.type instead.
*/
#define g_lcd_type ssd1306_lcd.type
/**
* Sends byte data to SSD1306 controller memory.
* Performs 3 operations at once: ssd1306_intf.start(), ssd1306_intf.send(), ssd1306_intf.stop();
* @param data - byte to send to the controller memory
* @note At present this function is used only in Arkanoid demo.
* @deprecated There is wide variaty of functions, that can be used for this.
*/
void ssd1306_sendData(uint8_t data) __attribute__ ((deprecated));
/**
* @brief Sets block in RAM of lcd display controller to write data to.
*
* Sets block in RAM of lcd display controller to write data to.
* For ssd1306 it uses horizontal addressing mode, while for
* sh1106 the function uses page addressing mode.
* Width can be specified as 0, thus the library will set the right boundary to
* region of RAM block to the right column of the display.
* @param x - column (left region)
* @param y - page (top page of the block)
* @param w - width of the block in pixels to control
*
* @deprecated Use ssd1306_lcd.set_block() instead.
* @warning - this function initiates session (i2c or spi) and do not close it.
* To close session, please, use ssd1306_intf.stop().
*/
#define ssd1306_setRamBlock ssd1306_lcd.set_block
/**
* Switches to the start of next RAM page for the block, specified by
* ssd1306_setRamBlock().
* For ssd1306 it does nothing, while for sh1106 the function moves cursor to
* next page.
* @deprecated Use ssd1306_lcd.next_page() instead.
*/
#define ssd1306_nextRamPage ssd1306_lcd.next_page
/**
* Sends 8 monochrome vertical pixels to OLED driver.
* @param data - byte, representing 8 pixels.
* @deprecated Use ssd1306_lcd.send_pixels1() instead.
*/
#define ssd1306_sendPixels ssd1306_lcd.send_pixels1
/**
* Sends buffer containing 8 monochrome vertical pixels, encoded in each byte.
* @param buffer - buffer containing monochrome pixels.
* @param len - length of buffer in bytes.
* @deprecated Use ssd1306_lcd.send_pixels_buffer1() instead.
*/
#define ssd1306_sendPixelsBuffer ssd1306_lcd.send_pixels_buffer1
/**
* @brief Sends RGB pixel encoded in 3-3-2 format to OLED driver.
* Sends RGB pixel encoded in 3-3-2 format to OLED driver.
* @param data - byte, representing RGB8 pixel.
* @deprecated Use ssd1306_lcd.send_pixels8() instead.
*/
#define ssd1306_sendPixel8 ssd1306_lcd.send_pixels8
/**
* @brief Sends configuration being passed to lcd display i2c/spi controller.
*
* Sends configuration being passed to lcd display i2c/spi controller.
* The data bytes are sent to lcd controller as is. In case of spi display
* this function sends cmd arguments in command mode. If lcd controller requires
* arguments to be sent in data mode, please use ssd1306_configureSpiDisplay().
*
* @param config configuration, located in flash, to send to i2c/spi controller.
* @param configSize - size of configuration data in bytes.
*/
void ssd1306_configureI2cDisplay(const uint8_t *config, uint8_t configSize);
/**
* @brief Sends configuration being passed to lcd display spi controller.
*
* Sends configuration being passed to lcd display spi controller. If data byte value
* to be sent is less than 255, then data byte is sent in command mode. If data byte
* is 0xFF, the function does't send it to controller, but switches to spi data mode,
* and next byte after will be sent in data spi mode. Then the function will switch back
* to command mode. If lcd controller requires cmd arguments to be sent in command mode,
* please use ssd1306_configureI2cDisplay().
*
* @param config configuration, located in flash, to send to i2c/spi controller.
* @param configSize - size of configuration data in bytes.
*/
void ssd1306_configureSpiDisplay(const uint8_t *config, uint8_t configSize);
/**
* @brief Sends configuration being passed to lcd display spi controller.
*
* Sends configuration being passed to lcd display spi controller. If data byte value
* to be sent is less than 255, then data byte is sent in command mode. Each command has
* additional parameter: number of arguments.
* If lcd controller requires cmd arguments to be sent in command mode,
* please use ssd1306_configureI2cDisplay().
*
* @param config configuration, located in flash, to send to i2c/spi controller.
* @param configSize - size of configuration data in bytes.
*/
void ssd1306_configureSpiDisplay2(const uint8_t *config, uint8_t configSize);
/**
* @brief Sets library display mode for direct draw functions.
*
* Sets library display mode for direct draw functions.
* There are currently 2 modes supported: LCD_MODE_SSD1306_COMPAT and
* LCD_MODE_NORMAL. In general, ssd1306 compatible mode uses different GDRAM
* addressing mode, than normal mode, intended for using with RBG full-color functions.
*
* @param mode lcd mode to activate.
* @see LCD_MODE_SSD1306_COMPAT
* @see LCD_MODE_NORMAL
* @see lcd_mode_t
*/
void ssd1306_setMode(lcd_mode_t mode);
/**
* @brief Does hardware reset for oled controller.
*
* Does hardware reset for oled controller. The function pulls up rstPin
* for 10 milliseconds, then pulls down rstPin for delayMs milliseconds
* and then finally pulls rstPin up.
*
* @param rstPin reset pin number
* @param delayMs delay in milliseconds to hold rstPin in low state
*/
void ssd1306_resetController(int8_t rstPin, uint8_t delayMs);
/**
* Macro SSD1306_COMPAT_SPI_BLOCK_8BIT_CMDS() generates 2 static functions,
* applicable for many oled controllers with 8-bit commands:
* set_block_compat(), next_page_compat(). These functions are to be used
* when working in ssd1306 compatible mode.
* @param column_cmd command opcode for setting column address according to
* oled controller datasheet
* @param row_cmd command opcode for setting row address according to
* oled controller datasheet
* @note It is assumed that column and row commands accept 2 single byte
* arguments: start and end of region
*/
#define SSD1306_COMPAT_SPI_BLOCK_8BIT_CMDS(column_cmd, row_cmd) \
static uint8_t __s_column; \
static uint8_t __s_page; \
static void set_block_compat(lcduint_t x, lcduint_t y, lcduint_t w) \
{ \
uint8_t rx = w ? (x + w - 1) : (ssd1306_lcd.width - 1); \
__s_column = x; \
__s_page = y; \
ssd1306_intf.start(); \
ssd1306_spiDataMode(0); \
ssd1306_intf.send(column_cmd); \
ssd1306_intf.send(x); \
ssd1306_intf.send(rx < ssd1306_lcd.width ? rx : (ssd1306_lcd.width - 1)); \
ssd1306_intf.send(row_cmd); \
ssd1306_intf.send(y<<3); \
ssd1306_intf.send(((y<<3) + 7) < ssd1306_lcd.height ? ((y<<3) + 7) : (ssd1306_lcd.height - 1)); \
ssd1306_spiDataMode(1); \
} \
static void next_page_compat(void) \
{ \
ssd1306_intf.stop(); \
set_block_compat(__s_column,__s_page+1,0); \
} \
/**
* Macro CONTROLLER_NATIVE_SPI_BLOCK_8BIT_CMDS() generates 2 static functions,
* applicable for many oled controllers with 8-bit commands:
* set_block_native(), next_page_native(). These functions are to be used
* when working in oled controller native mode.
* @param column_cmd command opcode for setting column address according to
* oled controller datasheet
* @param row_cmd command opcode for setting row address according to
* oled controller datasheet
* @note It is assumed that column and row commands accept 2 single byte
* arguments: start and end of region
*/
#define CONTROLLER_NATIVE_SPI_BLOCK_8BIT_CMDS(column_cmd, row_cmd) \
static void set_block_native(lcduint_t x, lcduint_t y, lcduint_t w) \
{ \
uint8_t rx = w ? (x + w - 1) : (ssd1306_lcd.width - 1); \
ssd1306_intf.start(); \
ssd1306_spiDataMode(0); \
ssd1306_intf.send(column_cmd); \
ssd1306_intf.send(x); \
ssd1306_intf.send(rx < ssd1306_lcd.width ? rx : (ssd1306_lcd.width - 1)); \
ssd1306_intf.send(row_cmd); \
ssd1306_intf.send(y); \
ssd1306_intf.send(ssd1306_lcd.height - 1); \
ssd1306_spiDataMode(1); \
} \
static void next_page_native(void) \
{ \
} \
/**
* Macro SSD1306_COMPAT_SEND_PIXELS_RGB8_CMDS() generates 2 static functions,
* applicable for many oled controllers in 8-bit RGB mode:
* send_pixels_compat(), send_pixels_buffer_compat(). These functions are to be used
* when working in ssd1306 compatible mode.
*/
#define SSD1306_COMPAT_SEND_PIXELS_RGB8_CMDS() \
extern uint16_t ssd1306_color; \
static void send_pixels_compat(uint8_t data) \
{ \
for (uint8_t i=8; i>0; i--) \
{ \
if ( data & 0x01 ) \
{ \
ssd1306_intf.send( (uint8_t)ssd1306_color ); \
} \
else \
{ \
ssd1306_intf.send( 0B00000000 ); \
} \
data >>= 1; \
} \
} \
static void send_pixels_buffer_compat(const uint8_t *buffer, uint16_t len) \
{ \
while(len--) \
{ \
send_pixels_compat(*buffer); \
buffer++; \
} \
}
/**
* Macro SSD1306_COMPAT_SEND_PIXELS_RGB16_CMDS() generates 2 static functions,
* applicable for many oled controllers in 16-bit RGB mode:
* send_pixels_compat16(), send_pixels_buffer_compat16(). These functions are to be used
* when working in ssd1306 compatible mode.
*/
#define SSD1306_COMPAT_SEND_PIXELS_RGB16_CMDS() \
extern uint16_t ssd1306_color; \
static void send_pixels_compat16(uint8_t data) \
{ \
for (uint8_t i=8; i>0; i--) \
{ \
if ( data & 0x01 ) \
{ \
ssd1306_intf.send( (uint8_t)(ssd1306_color >> 8 ) ); \
ssd1306_intf.send( (uint8_t)(ssd1306_color & 0xFF) ); \
} \
else \
{ \
ssd1306_intf.send( 0B00000000 ); \
ssd1306_intf.send( 0B00000000 ); \
} \
data >>= 1; \
} \
} \
static void send_pixels_buffer_compat16(const uint8_t *buffer, uint16_t len) \
{ \
while(len--) \
{ \
send_pixels_compat16(*buffer); \
buffer++; \
} \
}
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* _LCD_COMMON_H_ */
+434
View File
@@ -0,0 +1,434 @@
/*
MIT License
Copyright (c) 2018-2020, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "lcd_il9163.h"
#include "lcd_common.h"
#include "intf/ssd1306_interface.h"
#include "intf/spi/ssd1306_spi.h"
#include "ssd1306_hal/io.h"
#include "nano_gfx_types.h"
#ifdef SDL_EMULATION
#include "sdl_core.h"
#endif
#define CMD_ARG 0xFF
#define CMD_DELAY 0xFF
extern uint16_t ssd1306_color;
extern uint32_t s_ssd1306_spi_clock;
static uint8_t s_rotation = 0x00;
static uint8_t s_rgb_bit = 0b00001000;
static lcdint_t s_offset_x = 0;
static lcdint_t s_offset_y = 0;
static const PROGMEM uint8_t s_oled128x128_initData[] =
{
#ifdef SDL_EMULATION
SDL_LCD_IL9163,
0x00,
#endif
// 0x01, // sw reset. not needed, we do hardware reset
0x11, // exit sleep mode
0x3A, CMD_ARG, 0x05, // set 16-bit pixel format
0x26, CMD_ARG, 0x04, // set gamma curve: valid values 1, 2, 4, 8
// 0xF2, CMD_ARG, 0x01, // enable gamma adjustment, 0 - to disable
// 0xE0, CMD_ARG, 0x3F, CMD_ARG, 0x25, CMD_ARG, 0x1C,
// CMD_ARG, 0x1E, CMD_ARG, 0x20, CMD_ARG, 0x12,
// CMD_ARG, 0x2A, CMD_ARG, 0x90, CMD_ARG, 0x24,
// CMD_ARG, 0x11, CMD_ARG, 0x00, CMD_ARG, 0x00,
// CMD_ARG, 0x00, CMD_ARG, 0x00, CMD_ARG, 0x00, // positive gamma correction
// 0xE1, CMD_ARG, 0x20, CMD_ARG, 0x20, CMD_ARG, 0x20,
// CMD_ARG, 0x20, CMD_ARG, 0x05, CMD_ARG, 0x00,
// CMD_ARG, 0x15, CMD_ARG, 0xA7, CMD_ARG, 0x3D,
// CMD_ARG, 0x18, CMD_ARG, 0x25, CMD_ARG, 0x2A,
// CMD_ARG, 0x2B, CMD_ARG, 0x2B, CMD_ARG, 0x3A, // negative gamma correction
// 0xB1, CMD_ARG, 0x08, CMD_ARG, 0x08, // frame rate control 1, use by default
// 0xB4, CMD_ARG, 0x07, // display inversion, use by default
0xC0, CMD_ARG, 0x0A, CMD_ARG, 0x02, // power control 1
0xC1, CMD_ARG, 0x02, // power control 2
0xC5, CMD_ARG, 0x50, CMD_ARG, 0x5B, // vcom control 1
0xC7, CMD_ARG, 0x40, // vcom offset
// 0x2A, CMD_ARG, 0x00, CMD_ARG, 0x00, CMD_ARG, 0x00, CMD_ARG, 0x7F, // set column address, not needed. set by direct API
// 0x2B, CMD_ARG, 0x00, CMD_ARG, 0x00, CMD_ARG, 0x00, CMD_ARG, 0x9F, // set page address, not needed. set by direct API
0x36, CMD_ARG, 0b10001100, // enable fake "vertical addressing" mode (for il9163_setBlock() )
0x29, // display on
};
static const PROGMEM uint8_t s_oled128x160_initData[] =
{
#ifdef SDL_EMULATION
SDL_LCD_ST7735, 0x00,
0b00000011, 0x00,
#endif
0x01, CMD_DELAY, 150, // SWRESET sw reset. not needed, we do hardware reset
0x11, CMD_DELAY, 255, // SLPOUT exit sleep mode
0xB1, 0x03, 0x01, 0x2C, 0x2D, // FRMCTR1 frame rate control 1, use by default
0xB2, 0x03, 0x01, 0x2C, 0x2D, // FRMCTR2, Frame Rate Control (In Idle mode/ 8-colors)
0xB3, 0x06, // FRMCTR3 (B3h): Frame Rate Control (In Partial mode/ full colors)
0x01, 0x2C, 0x2D,
0x01, 0x2C, 0x2D,
0xB4, 0x01, 0x07, // INVCTR display inversion, use by default
0xB6, 0x02, 0x15, 0x02, // DISSET5
0xC0, 0x03, 0xA2, 0x02, 0x84, // PWCTR1 power control 1
0xC1, 0x01, 0xC5, // PWCTR2 power control 2
0xC2, 0x02, 0x0A, 0x00, // PWCTR3 power control 3
0xC3, 0x02, 0x8A, 0x2A, // PWCTR4 (C3h): Power Control 4 (in Idle mode/ 8-colors)
0xC4, 0x02, 0x8A, 0xEE, // PWCTR5 (C4h): Power Control 5 (in Partial mode/ full-colors)
0xC5, 0x01, 0x0E, // VMCTR vcom control 1
0x20, 0x00, // INVOFF (20h): Display Inversion Off
// 0xFC, 0x02, 0x11, 0x15, // PWCTR6
0x36, 0x01, 0b00100000, // MADCTL // enable fake "vertical addressing" mode (for il9163_setBlock() )
0x3A, 0x01, 0x05, // COLMOD set 16-bit pixel format
// 0x26, 1, 0x08, // GAMSET set gamma curve: valid values 1, 2, 4, 8
// 0xF2, 1, 0x01, // enable gamma adjustment, 0 - to disable
0xE0, 0x10, // GMCTRP1 positive gamma correction
0x0F, 0x1A, 0x0F, 0x18,
0x2F, 0x28, 0x20, 0x22,
0x1F, 0x1B, 0x23, 0x37,
0x00, 0x07, 0x02, 0x10,
0xE1, 0x10, // GMCTRN1 negative gamma correction
0x0F, 0x1B, 0x0F, 0x17,
0x33, 0x2C, 0x29, 0x2E,
0x30, 0x30, 0x39, 0x3F,
0x00, 0x07, 0x03, 0x10,
// 0xC7, 1, 0x40, // vcom offset
// 0x2A, CMD_ARG, 0x00, CMD_ARG, 0x00, CMD_ARG, 0x00, CMD_ARG, 0x7F, // set column address, not needed. set by direct API
// 0x2B, CMD_ARG, 0x00, CMD_ARG, 0x00, CMD_ARG, 0x00, CMD_ARG, 0x9F, // set page address, not needed. set by direct API
0x29, CMD_DELAY, 100, // DISPON display on
0x13, CMD_DELAY, 10, // NORON
};
static uint8_t s_column;
static uint8_t s_page;
static void il9163_setBlock(lcduint_t x, lcduint_t y, lcduint_t w)
{
uint8_t rx = w ? (x + w - 1) : (ssd1306_lcd.width - 1);
s_column = x;
s_page = y;
ssd1306_intf.start();
ssd1306_spiDataMode(0);
ssd1306_intf.send(0x2B);
ssd1306_spiDataMode(1); // According to datasheet all args must be passed in data mode
ssd1306_intf.send(0);
ssd1306_intf.send(x + s_offset_x);
ssd1306_intf.send(0);
ssd1306_intf.send((rx < ssd1306_lcd.width ? rx : (ssd1306_lcd.width - 1)) + s_offset_x);
ssd1306_spiDataMode(0);
ssd1306_intf.send(0x2A);
ssd1306_spiDataMode(1); // According to datasheet all args must be passed in data mode
ssd1306_intf.send(0);
ssd1306_intf.send((y<<3) + s_offset_y);
ssd1306_intf.send(0);
ssd1306_intf.send((((y<<3) + 7) < ssd1306_lcd.height ? ((y<<3) + 7) : (ssd1306_lcd.height - 1)) + s_offset_y);
ssd1306_spiDataMode(0);
ssd1306_intf.send(0x2C);
ssd1306_spiDataMode(1);
}
static void il9163_setBlock2(lcduint_t x, lcduint_t y, lcduint_t w)
{
uint8_t rx = w ? (x + w - 1) : (ssd1306_lcd.width - 1);
ssd1306_intf.start();
ssd1306_spiDataMode(0);
ssd1306_intf.send(0x2A);
ssd1306_spiDataMode(1); // According to datasheet all args must be passed in data mode
ssd1306_intf.send(0);
ssd1306_intf.send(x + s_offset_x);
ssd1306_intf.send(0);
ssd1306_intf.send((rx < ssd1306_lcd.width ? rx : (ssd1306_lcd.width - 1)) + s_offset_x);
ssd1306_spiDataMode(0);
ssd1306_intf.send(0x2B);
ssd1306_spiDataMode(1); // According to datasheet all args must be passed in data mode
ssd1306_intf.send(0);
ssd1306_intf.send(y + s_offset_y);
ssd1306_intf.send(0);
ssd1306_intf.send(ssd1306_lcd.height - 1 + s_offset_y);
ssd1306_spiDataMode(0);
ssd1306_intf.send(0x2C);
ssd1306_spiDataMode(1);
}
void il9163_setOffset(lcdint_t x, lcdint_t y)
{
s_offset_x = x;
s_offset_y = y;
}
static void il9163_nextPage(void)
{
ssd1306_intf.stop();
ssd1306_lcd.set_block(s_column,s_page+1,0);
}
static void il9163_nextPage2(void)
{
}
void il9163_setMode(lcd_mode_t mode)
{
ssd1306_intf.start();
ssd1306_spiDataMode(0);
ssd1306_intf.send( 0x36 );
ssd1306_spiDataMode(1);
ssd1306_intf.send( ( mode ? 0b00100000 : 0b00000000 ) | s_rgb_bit );
ssd1306_intf.stop();
if (mode == LCD_MODE_SSD1306_COMPAT )
{
ssd1306_lcd.set_block = il9163_setBlock;
ssd1306_lcd.next_page = il9163_nextPage;
}
else if ( mode == LCD_MODE_NORMAL )
{
ssd1306_lcd.set_block = il9163_setBlock2;
ssd1306_lcd.next_page = il9163_nextPage2;
}
s_rotation = mode ? 0x00 : 0x04;
}
static void il9163_sendPixels(uint8_t data)
{
for (uint8_t i=8; i>0; i--)
{
if ( data & 0x01 )
{
ssd1306_intf.send( (uint8_t)(ssd1306_color>>8) );
ssd1306_intf.send( (uint8_t)(ssd1306_color) );
}
else
{
ssd1306_intf.send( 0B00000000 );
ssd1306_intf.send( 0B00000000 );
}
data >>= 1;
}
}
static void il9163_sendPixelsBuffer(const uint8_t *buffer, uint16_t len)
{
while(len--)
{
il9163_sendPixels(*buffer);
buffer++;
}
}
static void il9163_sendPixel8(uint8_t data)
{
uint16_t color = RGB8_TO_RGB16(data);
ssd1306_intf.send( color >> 8 );
ssd1306_intf.send( color & 0xFF );
}
static void il9163_sendPixel16(uint16_t color)
{
ssd1306_intf.send( color >> 8 );
ssd1306_intf.send( color & 0xFF );
}
void il9163_128x128_init()
{
ssd1306_lcd.type = LCD_TYPE_SSD1331;
ssd1306_lcd.height = 128;
ssd1306_lcd.width = 128;
s_rgb_bit = 0b00001000; // set BGR mode mapping
ssd1306_lcd.set_block = il9163_setBlock;
ssd1306_lcd.next_page = il9163_nextPage;
ssd1306_lcd.send_pixels1 = il9163_sendPixels;
ssd1306_lcd.send_pixels_buffer1 = il9163_sendPixelsBuffer;
ssd1306_lcd.send_pixels8 = il9163_sendPixel8;
ssd1306_lcd.send_pixels16 = il9163_sendPixel16;
ssd1306_lcd.set_mode = il9163_setMode;
ssd1306_configureSpiDisplay(s_oled128x128_initData, sizeof(s_oled128x128_initData));
}
void il9163_128x128_spi_init(int8_t rstPin, int8_t cesPin, int8_t dcPin)
{
if (rstPin >=0)
{
pinMode(rstPin, OUTPUT);
digitalWrite(rstPin, HIGH);
/* Wait at least 1ms after VCC is up for LCD */
delay(1);
/* Perform reset operation of LCD display */
digitalWrite(rstPin, LOW);
delay(20);
digitalWrite(rstPin, HIGH);
}
/* ssd1351 cannot work faster than at 4MHz per datasheet */
s_ssd1306_spi_clock = 8000000;
ssd1306_spiInit(cesPin, dcPin);
il9163_128x128_init();
}
void il9163_setRotation(uint8_t rotation)
{
uint8_t ram_mode;
if ((rotation^s_rotation) & 0x01)
{
uint16_t t = ssd1306_lcd.width;
ssd1306_lcd.width = ssd1306_lcd.height;
ssd1306_lcd.height = t;
}
s_rotation = (rotation & 0x03) | (s_rotation & 0x04);
ssd1306_intf.start();
ssd1306_spiDataMode(0);
ssd1306_intf.send(0x28);
ssd1306_intf.send(0x36);
ssd1306_spiDataMode(1);
switch (s_rotation)
{
case 0:
ram_mode = 0b00000000;
break;
case 1: // 90 degree CW
ram_mode = 0b01000000;
break;
case 2: // 180 degree CW
ram_mode = 0b11100000;
break;
case 3: // 270 degree CW
ram_mode = 0b10000000;
break;
case 4:
ram_mode = 0b00000000;
break;
case 5: // 90 degree CW
ram_mode = 0b01100000;
break;
case 6: // 180 degree CW
ram_mode = 0b11000000;
break;
default: // 270 degree CW
ram_mode = 0b10100000;
break;
}
s_offset_x = ((s_rotation & 0x03) == 3 ? 32 : 0);
s_offset_y = ((s_rotation & 0x03) == 2 ? 32 : 0);
ssd1306_intf.send( ram_mode | s_rgb_bit );
ssd1306_spiDataMode(0);
ssd1306_intf.send(0x29);
ssd1306_intf.stop();
}
////////////////////////////////////////////////////////////////////////////////////////
// ST7735 support
////////////////////////////////////////////////////////////////////////////////////////
static void st7735_setBlock(lcduint_t x, lcduint_t y, lcduint_t w)
{
uint8_t rx = w ? (x + w - 1) : (ssd1306_lcd.width - 1);
s_column = x;
s_page = y;
ssd1306_intf.start();
ssd1306_spiDataMode(0);
ssd1306_intf.send(0x2B);
ssd1306_spiDataMode(1); // According to datasheet all args must be passed in data mode
ssd1306_intf.send(0);
ssd1306_intf.send(x);
ssd1306_intf.send(0);
ssd1306_intf.send((rx < ssd1306_lcd.width ? rx : (ssd1306_lcd.width - 1)));
ssd1306_spiDataMode(0);
ssd1306_intf.send(0x2A);
ssd1306_spiDataMode(1); // According to datasheet all args must be passed in data mode
ssd1306_intf.send(0);
ssd1306_intf.send((y<<3));
ssd1306_intf.send(0);
ssd1306_intf.send((((y<<3) + 7) < ssd1306_lcd.height ? ((y<<3) + 7) : (ssd1306_lcd.height - 1)));
ssd1306_spiDataMode(0);
ssd1306_intf.send(0x2C);
ssd1306_spiDataMode(1);
}
static void st7735_setBlock2(lcduint_t x, lcduint_t y, lcduint_t w)
{
uint8_t rx = w ? (x + w - 1) : (ssd1306_lcd.width - 1);
ssd1306_intf.start();
ssd1306_spiDataMode(0);
ssd1306_intf.send(0x2A);
ssd1306_spiDataMode(1); // According to datasheet all args must be passed in data mode
ssd1306_intf.send(0);
ssd1306_intf.send(x);
ssd1306_intf.send(0);
ssd1306_intf.send( rx < ssd1306_lcd.width ? rx : (ssd1306_lcd.width - 1) );
ssd1306_spiDataMode(0);
ssd1306_intf.send(0x2B);
ssd1306_spiDataMode(1); // According to datasheet all args must be passed in data mode
ssd1306_intf.send(0);
ssd1306_intf.send(y);
ssd1306_intf.send(0);
ssd1306_intf.send( ssd1306_lcd.height - 1 );
ssd1306_spiDataMode(0);
ssd1306_intf.send(0x2C);
ssd1306_spiDataMode(1);
}
static void st7735_setMode(lcd_mode_t mode)
{
if (mode == LCD_MODE_SSD1306_COMPAT )
{
ssd1306_lcd.set_block = st7735_setBlock;
ssd1306_lcd.next_page = il9163_nextPage;
}
else if ( mode == LCD_MODE_NORMAL )
{
ssd1306_lcd.set_block = st7735_setBlock2;
ssd1306_lcd.next_page = il9163_nextPage2;
}
s_rotation = mode ? (s_rotation & 0x03) : (s_rotation | 0x04);
il9163_setRotation( s_rotation & 0x03 );
}
void st7735_128x160_init()
{
ssd1306_lcd.type = LCD_TYPE_SSD1331;
ssd1306_lcd.width = 128;
ssd1306_lcd.height = 160;
s_rgb_bit = 0b00000000; // set RGB mode mapping
ssd1306_lcd.set_block = st7735_setBlock;
ssd1306_lcd.next_page = il9163_nextPage;
ssd1306_lcd.send_pixels1 = il9163_sendPixels;
ssd1306_lcd.send_pixels_buffer1 = il9163_sendPixelsBuffer;
ssd1306_lcd.send_pixels8 = il9163_sendPixel8;
ssd1306_lcd.send_pixels16 = il9163_sendPixel16;
ssd1306_lcd.set_mode = st7735_setMode;
ssd1306_configureSpiDisplay2(s_oled128x160_initData, sizeof(s_oled128x160_initData));
}
void st7735_128x160_spi_init(int8_t rstPin, int8_t cesPin, int8_t dcPin)
{
if (rstPin >=0)
{
ssd1306_resetController( rstPin, 20 );
/* Give 120ms display to initialize */
delay(120);
}
/* ssd1351 cannot work faster than at 4MHz per datasheet */
s_ssd1306_spi_clock = 8000000;
ssd1306_spiInit(cesPin, dcPin);
st7735_128x160_init();
}
+144
View File
@@ -0,0 +1,144 @@
/*
MIT License
Copyright (c) 2018-2020, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* @file lcd_il9163.h support for RGB TFT 128x128 display
*/
#ifndef _TFT_IL9163_H_
#define _TFT_IL9163_H_
#include "ssd1306_hal/io.h"
#include "lcd/lcd_common.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @ingroup LCD_INTERFACE_API
* @{
*/
/**
* @brief Sets GDRAM autoincrement mode
*
* Sets GDRAM autoincrement mode. By default, to make
* ssd1306_xxx functions compatible with RGB oled display,
* RGB oled is initialized in vertical auto-increment mode.
* But for pure rbg oled operations horizontal auto-increment mode is more suitable.
* So, if you're going to use NanoCanvas8 functions, please call
* il9163_setMode(0) prior to using pure RGB methods.
*
* @param mode 0 or 1
* @deprecated Use ssd1306_setMode() instead.
*/
void il9163_setMode(lcd_mode_t mode);
/**
* @brief Inits 128x128 RGB OLED display (based on il9163 controller).
*
* Inits 128x128 RGB OLED display (based on il9163 controller).
* User must init communication interface (i2c, spi) prior to calling this function.
* @see ssd1306_i2cInit()
* @see ssd1306_spiInit()
*/
void il9163_128x128_init(void);
/**
* @brief Sets screen offset (refer to datasheet of your display)
*
* Set offset for the display
* @param x offset in pixels
* @param y offset in pixels
*/
void il9163_setOffset(lcdint_t x, lcdint_t y);
/**
* @brief Inits 128x160 RGB OLED display (based on st7735 controller).
*
* Inits 128x160 RGB OLED display (based on st7735 controller).
* User must init communication interface (i2c, spi) prior to calling this function.
* @see ssd1306_i2cInit()
* @see ssd1306_spiInit()
*/
void st7735_128x160_init(void);
/**
* @brief Inits 128x128 RGB TFT display over spi (based on il9163 controller).
*
* Inits 128x128 RGB TFT display over spi (based on il9163 controller)
* @param rstPin - pin controlling LCD reset (-1 if not used)
* @param cesPin - chip enable pin to LCD slave (-1 if not used)
* @param dcPin - data/command pin to control LCD dc (required)
*/
void il9163_128x128_spi_init(int8_t rstPin, int8_t cesPin, int8_t dcPin);
/**
* @brief Inits 128x160 RGB TFT display over spi (based on st7735 controller).
*
* Inits 128x160 RGB TFT display over spi (based on st7735 controller)
* @param rstPin - pin controlling LCD reset (-1 if not used)
* @param cesPin - chip enable pin to LCD slave (-1 if not used)
* @param dcPin - data/command pin to control LCD dc (required)
*/
void st7735_128x160_spi_init(int8_t rstPin, int8_t cesPin, int8_t dcPin);
/**
* @}
*/
/**
* @defgroup IL9163_ST7734_API IL9163/ST7735: il9163/st7735 control functions
* @{
*/
/**
* @brief Sets screen orientation (rotation)
*
* Sets screen orientation (rotation): 0 - normal, 1 - 90 CW, 2 - 180 CW, 3 - 270 CW
* @param rotation - screen rotation 0 - normal, 1 - 90 CW, 2 - 180 CW, 3 - 270 CW
* @note works only with IL9163 display
*/
void il9163_setRotation(uint8_t rotation);
/**
* @brief Sets screen orientation (rotation)
*
* Sets screen orientation (rotation): 0 - normal, 1 - 90 CW, 2 - 180 CW, 3 - 270 CW
* @param rotation - screen rotation 0 - normal, 1 - 90 CW, 2 - 180 CW, 3 - 270 CW
* @note works only with ST7735 display
*/
#define st7735_setRotation il9163_setRotation
/**
* @}
*/
#ifdef __cplusplus
}
#endif
// ----------------------------------------------------------------------------
#endif // _TFT_IL9163_H_
+283
View File
@@ -0,0 +1,283 @@
/*
MIT License
Copyright (c) 2018-2019, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "lcd_ili9341.h"
#include "lcd_common.h"
#include "intf/ssd1306_interface.h"
#include "intf/spi/ssd1306_spi.h"
#include "ssd1306_hal/io.h"
#include "nano_gfx_types.h"
#ifdef SDL_EMULATION
#include "sdl_core.h"
#endif
#define CMD_ARG 0xFF
extern uint16_t ssd1306_color;
extern uint32_t s_ssd1306_spi_clock;
static uint8_t s_rotation = 0x00;
static uint8_t s_rgb_bit = 0b00001000;
static uint8_t s_rotate_output = 0;
static const PROGMEM uint8_t s_oled240x320_initData[] =
{
#ifdef SDL_EMULATION
SDL_LCD_ILI9341,
0x00,
#endif
0x01, // sw reset. not needed, we do hardware reset
0x11, // exit sleep mode
0x3A, CMD_ARG, 0x05, // set 16-bit pixel format
0x26, CMD_ARG, 0x04, // set gamma curve: valid values 1, 2, 4, 8
0xF2, CMD_ARG, 0x01, // enable gamma adjustment, 0 - to disable
0xE0, CMD_ARG, 0x3F, CMD_ARG, 0x25, CMD_ARG, 0x1C,
CMD_ARG, 0x1E, CMD_ARG, 0x20, CMD_ARG, 0x12,
CMD_ARG, 0x2A, CMD_ARG, 0x90, CMD_ARG, 0x24,
CMD_ARG, 0x11, CMD_ARG, 0x00, CMD_ARG, 0x00,
CMD_ARG, 0x00, CMD_ARG, 0x00, CMD_ARG, 0x00, // positive gamma correction
0xE1, CMD_ARG, 0x20, CMD_ARG, 0x20, CMD_ARG, 0x20,
CMD_ARG, 0x20, CMD_ARG, 0x05, CMD_ARG, 0x00,
CMD_ARG, 0x15, CMD_ARG, 0xA7, CMD_ARG, 0x3D,
CMD_ARG, 0x18, CMD_ARG, 0x25, CMD_ARG, 0x2A,
CMD_ARG, 0x2B, CMD_ARG, 0x2B, CMD_ARG, 0x3A, // negative gamma correction
// 0xB1, CMD_ARG, 0x08, CMD_ARG, 0x08, // frame rate control 1, use by default
// 0xB4, CMD_ARG, 0x07, // display inversion, use by default
0xC0, CMD_ARG, 0x0A, CMD_ARG, 0x02, // power control 1
0xC1, CMD_ARG, 0x02, // power control 2
0xC5, CMD_ARG, 0x50, CMD_ARG, 0x5B, // vcom control 1
0xC7, CMD_ARG, 0x40, // vcom offset
0x36, CMD_ARG, 0b10100000, // enable fake "vertical addressing" mode (for ili9341_setBlock() )
0x29, // display on
};
static lcduint_t s_column;
static lcduint_t s_page;
static void ili9341_setBlock(lcduint_t x, lcduint_t y, lcduint_t w)
{
lcduint_t rx = w ? (x + w - 1) : (ssd1306_lcd.width - 1);
s_column = x;
s_page = y;
ssd1306_intf.start();
ssd1306_spiDataMode(0);
ssd1306_intf.send(0x2B);
ssd1306_spiDataMode(1); // According to datasheet all args must be passed in data mode
ssd1306_intf.send(x >> 8);
ssd1306_intf.send(x & 0xFF);
ssd1306_intf.send((rx < ssd1306_lcd.width ? rx : (ssd1306_lcd.width - 1)) >> 8);
ssd1306_intf.send((rx < ssd1306_lcd.width ? rx : (ssd1306_lcd.width - 1)) & 0xFF);
ssd1306_spiDataMode(0);
ssd1306_intf.send(0x2A);
ssd1306_spiDataMode(1); // According to datasheet all args must be passed in data mode
ssd1306_intf.send((y<<3) >> 8);
ssd1306_intf.send((y<<3) & 0xFF);
ssd1306_intf.send((((y<<3) + 7) < ssd1306_lcd.height ? ((y<<3) + 7) : (ssd1306_lcd.height - 1))>>8);
ssd1306_intf.send((((y<<3) + 7) < ssd1306_lcd.height ? ((y<<3) + 7) : (ssd1306_lcd.height - 1)) & 0xFF);
ssd1306_spiDataMode(0);
ssd1306_intf.send(0x2C);
ssd1306_spiDataMode(1);
}
static void ili9341_setBlock2(lcduint_t x, lcduint_t y, lcduint_t w)
{
lcduint_t width = s_rotate_output ? ssd1306_lcd.height : ssd1306_lcd.width;
lcduint_t height = s_rotate_output ? ssd1306_lcd.width : ssd1306_lcd.height;
lcduint_t rx = w ? (x + w - 1) : (width - 1);
ssd1306_intf.start();
ssd1306_spiDataMode(0);
ssd1306_intf.send(0x2A);
ssd1306_spiDataMode(1); // According to datasheet all args must be passed in data mode
ssd1306_intf.send(x >> 8);
ssd1306_intf.send(x & 0xFF);
ssd1306_intf.send((rx < width ? rx : (width - 1))>>8);
ssd1306_intf.send((rx < width ? rx : (width - 1)) & 0xFF);
ssd1306_spiDataMode(0);
ssd1306_intf.send(0x2B);
ssd1306_spiDataMode(1); // According to datasheet all args must be passed in data mode
ssd1306_intf.send(y >> 8);
ssd1306_intf.send(y & 0xFF);
ssd1306_intf.send((height - 1) >> 8);
ssd1306_intf.send((height - 1) & 0xFF);
ssd1306_spiDataMode(0);
ssd1306_intf.send(0x2C);
ssd1306_spiDataMode(1);
}
static void ili9341_nextPage(void)
{
ssd1306_intf.stop();
ssd1306_lcd.set_block(s_column,s_page+1,0);
}
static void ili9341_nextPage2(void)
{
}
void ili9341_setMode(lcd_mode_t mode)
{
s_rotation &= 0x03;
s_rotation |= (mode == LCD_MODE_SSD1306_COMPAT ? 0x00 : 0x04);
ili9341_setRotation( s_rotation );
if (mode == LCD_MODE_SSD1306_COMPAT)
{
ssd1306_lcd.set_block = ili9341_setBlock;
ssd1306_lcd.next_page = ili9341_nextPage;
}
else if (mode == LCD_MODE_NORMAL)
{
ssd1306_lcd.set_block = ili9341_setBlock2;
ssd1306_lcd.next_page = ili9341_nextPage2;
}
}
static void ili9341_sendPixels(uint8_t data)
{
for (uint8_t i=8; i>0; i--)
{
if ( data & 0x01 )
{
ssd1306_intf.send( (uint8_t)(ssd1306_color>>8) );
ssd1306_intf.send( (uint8_t)(ssd1306_color) );
}
else
{
ssd1306_intf.send( 0B00000000 );
ssd1306_intf.send( 0B00000000 );
}
data >>= 1;
}
}
static void ili9341_sendPixelsBuffer(const uint8_t *buffer, uint16_t len)
{
while(len--)
{
ili9341_sendPixels(*buffer);
buffer++;
}
}
static void ili9341_sendPixel8(uint8_t data)
{
uint16_t color = RGB8_TO_RGB16(data);
ssd1306_intf.send( color >> 8 );
ssd1306_intf.send( color & 0xFF );
}
static void ili9341_sendPixel16(uint16_t color)
{
ssd1306_intf.send( color >> 8 );
ssd1306_intf.send( color & 0xFF );
}
void ili9341_240x320_init()
{
ssd1306_lcd.type = LCD_TYPE_SSD1331;
ssd1306_lcd.width = 240;
ssd1306_lcd.height = (lcduint_t)320;
s_rgb_bit = 0b00001000; // set BGR mode mapping
ssd1306_lcd.set_block = ili9341_setBlock;
ssd1306_lcd.next_page = ili9341_nextPage;
ssd1306_lcd.send_pixels1 = ili9341_sendPixels;
ssd1306_lcd.send_pixels_buffer1 = ili9341_sendPixelsBuffer;
ssd1306_lcd.send_pixels8 = ili9341_sendPixel8;
ssd1306_lcd.send_pixels16 = ili9341_sendPixel16;
ssd1306_lcd.set_mode = ili9341_setMode;
ssd1306_configureSpiDisplay(s_oled240x320_initData, sizeof(s_oled240x320_initData));
}
void ili9341_240x320_spi_init(int8_t rstPin, int8_t cesPin, int8_t dcPin)
{
if (rstPin >=0)
{
pinMode(rstPin, OUTPUT);
digitalWrite(rstPin, HIGH);
/* Wait at least 1ms after VCC is up for LCD */
delay(1);
/* Perform reset operation of LCD display */
digitalWrite(rstPin, LOW);
delay(100);
digitalWrite(rstPin, HIGH);
delay(100);
}
s_ssd1306_spi_clock = 10000000;
ssd1306_spiInit(cesPin, dcPin);
ili9341_240x320_init();
}
void ili9341_setRotation(uint8_t rotation)
{
uint8_t ram_mode;
if ((rotation^s_rotation) & 0x01)
{
uint16_t t = ssd1306_lcd.width;
ssd1306_lcd.width = ssd1306_lcd.height;
ssd1306_lcd.height = t;
}
s_rotation = (rotation & 0x03) | (s_rotation & 0x04);
ssd1306_intf.start();
ssd1306_spiDataMode(0);
ssd1306_intf.send(0x28);
ssd1306_intf.send(0x36);
ssd1306_spiDataMode(1);
switch (s_rotation)
{
case 0:
ram_mode = 0b10100000;
break;
case 1: // 90 degree CW
ram_mode = 0b11010000;
break;
case 2: // 180 degree CW
ram_mode = 0b01100000;
break;
case 3: // 270 degree CW
ram_mode = 0b00000000;
break;
case 4:
ram_mode = s_rotate_output ? 0b11100100: 0b10000100;
break;
case 5: // 90 degree CW
ram_mode = 0b11100000;
break;
case 6: // 180 degree CW
ram_mode = 0b01010100;
break;
default: // 270 degree CW
ram_mode = 0b00100000;
break;
}
ssd1306_intf.send( ram_mode | s_rgb_bit );
ssd1306_spiDataMode(0);
ssd1306_intf.send(0x29);
ssd1306_intf.stop();
}
void ili9341_rotateOutput(uint8_t on)
{
s_rotate_output = on;
ili9341_setRotation( s_rotation );
}
+117
View File
@@ -0,0 +1,117 @@
/*
MIT License
Copyright (c) 2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* @file lcd_ili9341.h support for RGB TFT 320x240 display
*/
#ifndef _TFT_ILI9341_H_
#define _TFT_ILI9341_H_
#include "ssd1306_hal/io.h"
#include "lcd/lcd_common.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @ingroup LCD_INTERFACE_API
* @{
*/
/**
* @brief Sets GDRAM autoincrement mode
*
* Sets GDRAM autoincrement mode. By default, to make
* ssd1306_xxx functions compatible with RGB oled display,
* RGB oled is initialized in vertical auto-increment mode.
* But for pure rbg oled operations horizontal auto-increment mode is more suitable.
* So, if you're going to use NanoCanvas8 functions, please call
* ili9341_setMode(0) prior to using pure RGB methods.
*
* @param mode 0 or 1
* @deprecated Use ssd1306_setMode() instead.
*/
void ili9341_setMode(lcd_mode_t mode);
/**
* @brief Inits 240x320 RGB OLED display (based on ili9341 controller).
*
* Inits 240x320 RGB OLED display (based on ili9341 controller).
* User must init communication interface (i2c, spi) prior to calling this function.
* @see ssd1306_i2cInit()
* @see ssd1306_spiInit()
*/
void ili9341_240x320_init(void);
/**
* @brief Inits 240x320 RGB TFT display over spi (based on ili9341 controller).
*
* Inits 240x320 RGB TFT display over spi (based on ili9341 controller)
* @param rstPin - pin controlling LCD reset (-1 if not used)
* @param cesPin - chip enable pin to LCD slave (-1 if not used)
* @param dcPin - data/command pin to control LCD dc (required)
*/
void ili9341_240x320_spi_init(int8_t rstPin, int8_t cesPin, int8_t dcPin);
/**
* @}
*/
/**
* @defgroup ili9341_API ili9341: ili9341 control functions
* @{
*/
/**
* @brief Sets screen orientation (rotation)
*
* Sets screen orientation (rotation): 0 - normal, 1 - 90 CW, 2 - 180 CW, 3 - 270 CW
* @param rotation - screen rotation 0 - normal, 1 - 90 CW, 2 - 180 CW, 3 - 270 CW
* @note works only with ili9341 display
*/
void ili9341_setRotation(uint8_t rotation);
/**
* @brief Sets rotation of all output functions
*
* Sets rotation of all output functions. 0 - no rotation, 1 - change by 90 degrees
* Actually doesn't change screen orientation, only rotates primitives being output
*
* @param on enable (1) of disable (0)
* @warning experimental feature, may work incorrectly
*/
void ili9341_rotateOutput(uint8_t on);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
// ----------------------------------------------------------------------------
#endif // _TFT_ILI9141_H_
+108
View File
@@ -0,0 +1,108 @@
/*
MIT License
Copyright (c) 2017-2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "lcd_pcd8544.h"
#include "lcd_common.h"
#include "pcd8544_commands.h"
#include "intf/ssd1306_interface.h"
#include "intf/spi/ssd1306_spi.h"
#include "ssd1306_hal/io.h"
#ifdef SDL_EMULATION
#include "sdl_core.h"
#endif
static const uint8_t PROGMEM s_lcd84x48_initData[] =
{
#ifdef SDL_EMULATION
SDL_LCD_PCD8544,
0x00,
#endif
PCD8544_FUNCTIONSET | PCD8544_EXTENDEDINSTRUCTION, // switch to extented commands
PCD8544_SETVOP | 0x16, // Set vop contrast
PCD8544_SETTEMP,
PCD8544_SETBIAS | 0x04, // Set bias mode
PCD8544_FUNCTIONSET, // switch to basic commands
PCD8544_DISPLAYCONTROL | PCD8544_DISPLAYNORMAL
};
static uint8_t s_column;
static uint8_t s_page;
static uint8_t s_width;
static void pcd8544_setBlock(lcduint_t x, lcduint_t y, lcduint_t w)
{
s_width = w;
s_column = x;
s_page = y;
ssd1306_intf.start();
ssd1306_spiDataMode(0);
if (w == 1) ssd1306_intf.send( 0x22 ); else ssd1306_intf.send( 0x20 );
ssd1306_intf.send(0x80 | x);
ssd1306_intf.send(0x40 | y);
ssd1306_spiDataMode(1);
}
static void pcd8544_nextPage(void)
{
if ( s_width != 1)
{
ssd1306_intf.stop();
pcd8544_setBlock(s_column, s_page+1, s_width);
}
}
static void pcd8544_setMode(lcd_mode_t mode)
{
}
void pcd8544_84x48_init()
{
ssd1306_lcd.type = LCD_TYPE_PCD8544;
ssd1306_lcd.width = 84;
ssd1306_lcd.height = 48;
ssd1306_intf.start();
ssd1306_spiDataMode(0);
ssd1306_lcd.set_block = pcd8544_setBlock;
ssd1306_lcd.next_page = pcd8544_nextPage;
ssd1306_lcd.send_pixels1 = ssd1306_intf.send;
ssd1306_lcd.send_pixels_buffer1 = ssd1306_intf.send_buffer;
ssd1306_lcd.set_mode = pcd8544_setMode;
for( uint8_t i=0; i<sizeof(s_lcd84x48_initData); i++)
{
ssd1306_intf.send(pgm_read_byte(&s_lcd84x48_initData[i]));
}
ssd1306_intf.stop();
}
void pcd8544_84x48_spi_init(int8_t rstPin, int8_t cesPin, int8_t dcPin)
{
if (rstPin >=0)
{
ssd1306_resetController( rstPin, 1 );
}
ssd1306_spiInit(cesPin, dcPin);
pcd8544_84x48_init();
}
+72
View File
@@ -0,0 +1,72 @@
/*
MIT License
Copyright (c) 2017-2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* @file lcd_pcd8544.h support for LED 84x48 display (PCD8544)
*/
#ifndef _LCD_PCD8544_H_
#define _LCD_PCD8544_H_
#include "ssd1306_hal/io.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @ingroup LCD_INTERFACE_API
* @{
*/
/**
* @brief Inits 84x48 LED display (based on PCD8544 controller).
*
* Inits 84x48 LED display (based on PCD8544 controller).
* User must init communication interface (i2c, spi) prior to calling this function.
* @see ssd1306_i2cInit()
* @see ssd1306_spiInit()
*/
void pcd8544_84x48_init(void);
/**
* Inits 84x48 LED display over spi (based on PCD8544 controller)
* @param rstPin - pin controlling LCD reset (-1 if not used)
* @param cesPin - chip enable pin to LCD slave (-1 if not used)
* @param dcPin - data/command pin to control LCD dc (required)
*/
void pcd8544_84x48_spi_init(int8_t rstPin, int8_t cesPin, int8_t dcPin);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
// ----------------------------------------------------------------------------
#endif // _LCD_PCD8544_H_
+127
View File
@@ -0,0 +1,127 @@
/*
MIT License
Copyright (c) 2017-2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "oled_sh1106.h"
#include "lcd_common.h"
#include "ssd1306_commands.h"
#include "intf/ssd1306_interface.h"
#include "intf/i2c/ssd1306_i2c.h"
#include "intf/spi/ssd1306_spi.h"
#include "ssd1306_hal/io.h"
#ifdef SDL_EMULATION
#include "sdl_core.h"
#endif
static const uint8_t PROGMEM s_oled128x64_initData[] =
{
#ifdef SDL_EMULATION
SDL_LCD_SH1106,
0x00,
#endif
SSD1306_DISPLAYOFF, // display off
SSD1306_COMSCANDEC, // Scan from 127 to 0 (Reverse scan)
SSD1306_SETSTARTLINE | 0x00, // First line to start scanning from
SSD1306_SETCONTRAST, 0x7F, // contast value to 0x7F according to datasheet
SSD1306_SEGREMAP | 0x01, // Use reverse mapping. 0x00 - is normal mapping
SSD1306_NORMALDISPLAY,
SSD1306_SETMULTIPLEX, 63, // Reset to default MUX. See datasheet
SSD1306_SETDISPLAYOFFSET, 0x00, // no offset
SSD1306_SETDISPLAYCLOCKDIV, 0x80,// set to default ratio/osc frequency
SSD1306_SETPRECHARGE, 0x22, // switch precharge to 0x22 // 0xF1
SSD1306_SETCOMPINS, 0x12, // set divide ratio
SSD1306_SETVCOMDETECT, 0x20, // vcom deselect to 0x20 // 0x40
SSD1306_CHARGEPUMP, 0x14, // Enable charge pump
SSD1306_DISPLAYALLON_RESUME,
SSD1306_DISPLAYON
};
static uint8_t s_column;
static uint8_t s_page;
static void sh1106_setBlock(lcduint_t x, lcduint_t y, lcduint_t w)
{
s_column = x;
s_page = y;
ssd1306_intf.start();
if (ssd1306_intf.spi)
ssd1306_spiDataMode(0);
else
ssd1306_intf.send(0x00);
ssd1306_intf.send(SSD1306_SETPAGE | y);
ssd1306_intf.send(((x+2)>>4) | SSD1306_SETHIGHCOLUMN);
ssd1306_intf.send(((x+2) & 0x0f) | SSD1306_SETLOWCOLUMN);
if (ssd1306_intf.spi)
{
ssd1306_spiDataMode(1);
}
else
{
ssd1306_intf.stop();
ssd1306_intf.start();
ssd1306_intf.send(0x40);
}
}
static void sh1106_nextPage(void)
{
ssd1306_intf.stop();
sh1106_setBlock(s_column,s_page+1,0);
}
static void sh1106_setMode(lcd_mode_t mode)
{
}
void sh1106_128x64_init()
{
ssd1306_lcd.type = LCD_TYPE_SH1106;
ssd1306_lcd.height = 64;
ssd1306_lcd.width = 128;
ssd1306_lcd.set_block = sh1106_setBlock;
ssd1306_lcd.next_page = sh1106_nextPage;
ssd1306_lcd.send_pixels1 = ssd1306_intf.send;
ssd1306_lcd.send_pixels_buffer1 = ssd1306_intf.send_buffer;
ssd1306_lcd.set_mode = sh1106_setMode;
for( uint8_t i=0; i<sizeof(s_oled128x64_initData); i++)
{
ssd1306_sendCommand(pgm_read_byte(&s_oled128x64_initData[i]));
}
}
void sh1106_128x64_i2c_init()
{
ssd1306_i2cInit();
sh1106_128x64_init();
}
void sh1106_128x64_spi_init(int8_t rstPin, int8_t cesPin, int8_t dcPin)
{
if (rstPin >=0)
{
ssd1306_resetController( rstPin, 10 );
}
ssd1306_spiInit(cesPin, dcPin);
sh1106_128x64_init();
}
+81
View File
@@ -0,0 +1,81 @@
/*
MIT License
Copyright (c) 2017-2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* @file oled_sh1106.h support for OLED 128x64 display
*/
#ifndef _OLED_SH1106_H_
#define _OLED_SH1106_H_
#include "ssd1306_hal/io.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @ingroup LCD_INTERFACE_API
* @{
*/
/**
* @brief Inits 128x64 OLED display (based on SH1106 controller).
*
* Inits 128x64 OLED display (based on SH1106 controller).
* User must init communication interface (i2c or spi) prior to calling this function.
*/
void sh1106_128x64_init(void);
/**
* @brief Inits 128x64 OLED display over i2c (based on SH1106 controller).
*
* Inits 128x64 OLED display over i2c (based on SH1106 controller)
* This function uses hardcoded pins for i2c communication, depending on your hardware.
* If you use non-standard pins in your project, please perform call ssd1306_i2cInitEx() and
* sh1106_128x64_init().
*/
void sh1106_128x64_i2c_init(void);
/**
* @brief Inits 128x64 OLED display over spi (based on SH1106 controller).
*
* Inits 128x64 OLED display over spi (based on SH1106 controller)
* @param rstPin - pin controlling LCD reset (-1 if not used)
* @param cesPin - chip enable pin to LCD slave (-1 if not used)
* @param dcPin - data/command pin to control LCD dc (required)
*/
void sh1106_128x64_spi_init(int8_t rstPin, int8_t cesPin, int8_t dcPin);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
// ----------------------------------------------------------------------------
#endif // _OLED_SH1106_H_
+259
View File
@@ -0,0 +1,259 @@
/*
MIT License
Copyright (c) 2017-2019, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "oled_ssd1306.h"
#include "lcd_common.h"
#include "ssd1306_commands.h"
#include "intf/ssd1306_interface.h"
#include "intf/i2c/ssd1306_i2c.h"
#include "intf/spi/ssd1306_spi.h"
#include "ssd1306_hal/io.h"
#ifdef SDL_EMULATION
#include "sdl_core.h"
#endif
uint8_t s_ssd1306_startLine = 0;
static const uint8_t PROGMEM s_oled128x64_initData[] =
{
#ifdef SDL_EMULATION
SDL_LCD_SSD1306,
0x00,
#endif
SSD1306_DISPLAYOFF, // display off
SSD1306_MEMORYMODE, HORIZONTAL_ADDRESSING_MODE, // Page Addressing mode
SSD1306_COMSCANDEC, // Scan from 127 to 0 (Reverse scan)
SSD1306_SETSTARTLINE | 0x00, // First line to start scanning from
SSD1306_SETCONTRAST, 0x7F, // contast value to 0x7F according to datasheet
SSD1306_SEGREMAP | 0x01, // Use reverse mapping. 0x00 - is normal mapping
SSD1306_NORMALDISPLAY,
SSD1306_SETMULTIPLEX, 63, // Reset to default MUX. See datasheet
SSD1306_SETDISPLAYOFFSET, 0x00, // no offset
SSD1306_SETDISPLAYCLOCKDIV, 0x80,// set to default ratio/osc frequency
SSD1306_SETPRECHARGE, 0x22, // switch precharge to 0x22 // 0xF1
SSD1306_SETCOMPINS, 0x12, // set divide ratio
SSD1306_SETVCOMDETECT, 0x20, // vcom deselect to 0x20 // 0x40
SSD1306_CHARGEPUMP, 0x14, // Enable charge pump
SSD1306_DISPLAYALLON_RESUME,
SSD1306_DISPLAYON,
};
static const uint8_t PROGMEM s_oled128x32_initData[] =
{
#ifdef SDL_EMULATION
SDL_LCD_SSD1306,
0x00,
#endif
SSD1306_DISPLAYOFF, // display off
SSD1306_SETDISPLAYCLOCKDIV, 0x80,
SSD1306_SETMULTIPLEX, 31,
SSD1306_SETDISPLAYOFFSET, 0x00, // --no offset
SSD1306_SETSTARTLINE | 0x00,
SSD1306_CHARGEPUMP, 0x14, // 0x10
SSD1306_SEGREMAP | 0x01, // Reverse mapping
SSD1306_COMSCANDEC,
SSD1306_SETCOMPINS, 0x02,
SSD1306_SETCONTRAST, 0x7F, // contast value
SSD1306_SETPRECHARGE, 0x22, // 0x1F
SSD1306_SETVCOMDETECT, 0x40,
SSD1306_MEMORYMODE, HORIZONTAL_ADDRESSING_MODE,
SSD1306_DISPLAYALLON_RESUME,
SSD1306_NORMALDISPLAY,
SSD1306_DISPLAYON,
};
static void ssd1306_setBlock(lcduint_t x, lcduint_t y, lcduint_t w)
{
ssd1306_intf.start();
if (ssd1306_intf.spi)
ssd1306_spiDataMode(0);
else
ssd1306_intf.send(0x00);
ssd1306_intf.send(SSD1306_COLUMNADDR);
ssd1306_intf.send(x);
ssd1306_intf.send(w ? (x + w - 1) : (ssd1306_lcd.width - 1));
ssd1306_intf.send(SSD1306_PAGEADDR);
ssd1306_intf.send(y);
ssd1306_intf.send((ssd1306_lcd.height >> 3) - 1);
if (ssd1306_intf.spi)
{
ssd1306_spiDataMode(1);
}
else
{
ssd1306_intf.stop();
ssd1306_intf.start();
ssd1306_intf.send(0x40);
}
}
static void ssd1306_nextPage(void)
{
}
static void ssd1306_setMode_int(lcd_mode_t mode)
{
}
void ssd1306_displayOff()
{
ssd1306_sendCommand(SSD1306_DISPLAYOFF);
}
void ssd1306_displayOn()
{
ssd1306_sendCommand(SSD1306_DISPLAYON);
}
void ssd1306_setContrast(uint8_t contrast)
{
ssd1306_commandStart();
ssd1306_intf.send(SSD1306_SETCONTRAST);
ssd1306_intf.send(contrast);
ssd1306_intf.stop();
}
void ssd1306_invertMode()
{
ssd1306_sendCommand(SSD1306_INVERTDISPLAY);
}
void ssd1306_normalMode()
{
ssd1306_sendCommand(SSD1306_NORMALDISPLAY);
}
void ssd1306_flipHorizontal(uint8_t mode)
{
ssd1306_sendCommand( SSD1306_SEGREMAP | (mode ? 0x00: 0x01 ) );
}
void ssd1306_flipVertical(uint8_t mode)
{
ssd1306_sendCommand( mode ? SSD1306_COMSCANINC : SSD1306_COMSCANDEC );
}
void ssd1306_setStartLine(uint8_t line)
{
s_ssd1306_startLine = line;
ssd1306_sendCommand( SSD1306_SETSTARTLINE | (line & 0x3F) );
}
uint8_t ssd1306_getStartLine(void)
{
return s_ssd1306_startLine;
}
///////////////////////////////////////////////////////////////////////////////
// I2C SSD1306 128x64
///////////////////////////////////////////////////////////////////////////////
void ssd1306_init()
{
ssd1306_128x64_i2c_init();
}
void ssd1306_128x64_init()
{
ssd1306_lcd.type = LCD_TYPE_SSD1306;
ssd1306_lcd.height = 64;
ssd1306_lcd.width = 128;
ssd1306_lcd.set_block = ssd1306_setBlock;
ssd1306_lcd.next_page = ssd1306_nextPage;
ssd1306_lcd.send_pixels1 = ssd1306_intf.send;
ssd1306_lcd.send_pixels_buffer1 = ssd1306_intf.send_buffer;
ssd1306_lcd.set_mode = ssd1306_setMode_int;
for( uint8_t i=0; i<sizeof(s_oled128x64_initData); i++)
{
ssd1306_sendCommand(pgm_read_byte(&s_oled128x64_initData[i]));
}
}
void ssd1306_128x64_i2c_init()
{
ssd1306_i2cInit();
ssd1306_128x64_init();
}
void ssd1306_128x64_i2c_initEx(int8_t scl, int8_t sda, int8_t sa)
{
ssd1306_i2cInitEx(scl, sda, sa);
ssd1306_128x64_init();
}
///////////////////////////////////////////////////////////////////////////////
// SPI SSD1306 128x64
///////////////////////////////////////////////////////////////////////////////
void ssd1306_128x64_spi_init(int8_t rstPin, int8_t cesPin, int8_t dcPin)
{
if (rstPin >=0)
{
ssd1306_resetController( rstPin, 10 );
}
ssd1306_spiInit(cesPin, dcPin);
ssd1306_128x64_init();
}
///////////////////////////////////////////////////////////////////////////////
// I2C SSD1306 128x32
///////////////////////////////////////////////////////////////////////////////
void ssd1306_128x32_init()
{
ssd1306_lcd.type = LCD_TYPE_SSD1306;
ssd1306_lcd.height = 32;
ssd1306_lcd.width = 128;
ssd1306_lcd.set_block = ssd1306_setBlock;
ssd1306_lcd.next_page = ssd1306_nextPage;
ssd1306_lcd.send_pixels1 = ssd1306_intf.send;
ssd1306_lcd.set_mode = ssd1306_setMode_int;
for( uint8_t i=0; i < sizeof(s_oled128x32_initData); i++)
{
ssd1306_sendCommand(pgm_read_byte(&s_oled128x32_initData[i]));
}
}
void ssd1306_128x32_i2c_init()
{
ssd1306_i2cInit();
ssd1306_128x32_init();
}
///////////////////////////////////////////////////////////////////////////////
// SPI SSD1306 128x32
///////////////////////////////////////////////////////////////////////////////
void ssd1306_128x32_spi_init(int8_t rstPin, int8_t cesPin, int8_t dcPin)
{
if (rstPin >=0)
{
ssd1306_resetController( rstPin, 10 );
}
ssd1306_spiInit(cesPin, dcPin);
ssd1306_128x32_init();
}
+198
View File
@@ -0,0 +1,198 @@
/*
MIT License
Copyright (c) 2017-2019, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* @file oled_ssd1306.h support for OLED ssd1306-based displays
*/
#ifndef _OLED_SSD1306_H_
#define _OLED_SSD1306_H_
#include "ssd1306_hal/io.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @ingroup LCD_INTERFACE_API
* @{
*/
/**
* @brief Inits 128x64 OLED display (based on SSD1306 controller).
*
* Inits 128x64 OLED display (based on SSD1306 controller).
* User must init communication interface (i2c, spi) prior to calling this function.
* @see ssd1306_i2cInit()
* @see ssd1306_spiInit()
*/
void ssd1306_128x64_init(void);
/**
* @brief Inits 128x64 OLED display over i2c (based on SSD1306 controller).
*
* Inits 128x64 OLED display over i2c (based on SSD1306 controller)
* This function uses hardcoded pins for i2c communication, depending on your hardware.
* If you use non-standard pins in your project, please perform call ssd1306_i2cInitEx() and
* ssd1306_128x64_init(), or you can use ssd1306_128x64_i2c_initEx().
*/
void ssd1306_128x64_i2c_init(void);
/**
* @brief Inits 128x64 OLED display over i2c (based on SSD1306 controller).
*
* Inits 128x64 OLED display over i2c (based on SSD1306 controller)
* This function uses hardcoded pins for i2c communication, depending on your hardware.
*
* @param scl - i2c clock pin. Use -1 if you don't need to change default pin number
* @param sda - i2c data pin. Use -1 if you don't need to change default pin number
* @param sa - i2c address of lcd display. Use 0 to leave default
*
* @note scl and sda parameters depend on used hardware. For many hardware boards these
* parameters do not have any effect. ESP8266 allows to specify these parameters
*
* @note scl and sda for Linux systems should be the same, and should contain i2c bus id.
*/
void ssd1306_128x64_i2c_initEx(int8_t scl, int8_t sda, int8_t sa);
/**
* @brief Inits 128x64 OLED display over spi (based on SSD1306 controller).
*
* Inits 128x64 OLED display over spi (based on SSD1306 controller)
* @param rstPin - pin controlling LCD reset (-1 if not used)
* @param cesPin - chip enable pin to LCD slave (-1 if not used)
* @param dcPin - data/command pin to control LCD dc (required)
*/
void ssd1306_128x64_spi_init(int8_t rstPin, int8_t cesPin, int8_t dcPin);
/**
* @brief Inits 128x32 OLED display over spi (based on SSD1306 controller).
*
* Inits 128x32 OLED display over spi (based on SSD1306 controller)
* @param rstPin - pin controlling LCD reset (-1 if not used)
* @param cesPin - chip enable pin to LCD slave (-1 if not used)
* @param dcPin - data/command pin to control LCD dc (required)
*/
void ssd1306_128x32_spi_init(int8_t rstPin, int8_t cesPin, int8_t dcPin);
/**
* @copydoc ssd1306_128x64_i2c_init
* @deprecated Use ssd1306_128x64_i2c_init() instead.
*/
void ssd1306_init(void) __attribute__((deprecated));
/**
* @brief Inits 128x32 OLED display over i2c (based on SSD1306 controller).
*
* Inits 128x32 OLED display over i2c (based on SSD1306 controller)
* This function uses hardcoded pins for i2c communication, depending on your hardware.
* If you use non-standard pins in your project, please perform call ssd1306_i2cInitEx() and
* ssd1306_128x32_init().
*/
void ssd1306_128x32_i2c_init(void);
/**
* @brief Inits 128x32 OLED display (based on ssd1306 controller).
*
* Inits 128x32 OLED display (based on ssd1306 controller)
* spi or i2c bus must be initialized prior to calling this function.
* @see ssd1306_i2cInit()
* @see ssd1306_spiInit()
*/
void ssd1306_128x32_init(void);
/**
* Turns off display
*/
void ssd1306_displayOff(void);
/**
* Turns on display
*/
void ssd1306_displayOn(void);
/**
* Set display contrast, ie light intensity
* @param contrast - contrast value to see, refer to ssd1306 datasheet
*/
void ssd1306_setContrast(uint8_t contrast);
/**
* Switches display to inverse mode.
* LCD will display 0-pixels as white, and 1-pixels as black.
* @note Not supported for SSD1331
*/
void ssd1306_invertMode(void);
/**
* Switches display to normal mode.
* @note Not supported for SSD1331
*/
void ssd1306_normalMode(void);
/**
* @brief performs horizontal flip
*
* Performs horizontal flip. If you need to turn display by 180 degree,
* please use both ssd1306_flipHorizontal() and ssd1306_flipVertical().
*
* @param mode - 0 to disable horizontal flip
* 1 to enable horizontal flip
*/
void ssd1306_flipHorizontal(uint8_t mode);
/**
* @brief performs vertical flip
*
* Performs vertical flip. If you need to turn display by 180 degree,
* please use both ssd1306_flipHorizontal() and ssd1306_flipVertical().
*
* @param mode - 0 to disable vertical flip
* 1 to enable vertical flip
*/
void ssd1306_flipVertical(uint8_t mode);
/**
* Sets start line in gdram to start display content with
*
* @param line start line in range 0 - 63
*/
void ssd1306_setStartLine(uint8_t line);
/**
* returns start line in gdram.
*/
uint8_t ssd1306_getStartLine(void);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
// ----------------------------------------------------------------------------
#endif // _OLED_SSD1306_H_
+182
View File
@@ -0,0 +1,182 @@
/*
MIT License
Copyright (c) 2018-2019, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "oled_ssd1325.h"
#include "lcd_common.h"
#include "intf/ssd1306_interface.h"
#include "intf/spi/ssd1306_spi.h"
#include "ssd1306_hal/io.h"
#ifdef SDL_EMULATION
#include "sdl_core.h"
#endif
extern uint16_t ssd1306_color;
static const PROGMEM uint8_t s_oled_128x64_initData[] =
{
#ifdef SDL_EMULATION
SDL_LCD_SSD1325,
SDL_LCD_SSD1325_GENERIC,
#endif
0xAE, // OFF /* display off */
0xB3, 0x91, // CLK
0xA8, 0x3F, // multiplex 64
0xA2, 0x00, // Display offset
0xA1, 0x00, // Start line
0xAD, 0x02, // VCOMH
0xA0, 0x40 | 0x10 | 0x04 | 0x02 | 0x01, // REMAP: vertical increment mode
0x86, // CURRENT
0x81, 0x70, // CONTRAST
0xB2, 0x51, // FREQ
0xB1, 0x55, // PHASE
0xBC, 0x10, // PRECHARGE
0xBE, 0x1C, // VCOMH voltage
0xA4, // NORMAL
};
///////////// ssd1325 functions below are for SPI display ////////////
///////////// in ssd1306 compatible mode ////////////
//////////////////////// SSD1306 COMPATIBLE MODE ///////////////////////////////
static uint8_t __s_column;
static uint8_t __s_w;
static uint8_t __s_w2;
static uint8_t __s_page;
static uint8_t __s_leftPixel;
static uint8_t __s_pos;
static void set_block_compat(lcduint_t x, lcduint_t y, lcduint_t w)
{
uint8_t rx = w ? (x + w - 1) : (ssd1306_lcd.width - 1);
rx = rx < ssd1306_lcd.width ? rx : (ssd1306_lcd.width - 1);
__s_column = x;
__s_page = y;
__s_w = w;
__s_w2 = rx - x + 1;
__s_leftPixel = 0;
__s_pos = __s_column;
ssd1306_intf.start();
ssd1306_spiDataMode(0);
ssd1306_intf.send(0x15);
ssd1306_intf.send(x / 2);
ssd1306_intf.send(rx / 2);
ssd1306_intf.send(0x75);
ssd1306_intf.send(y<<3);
ssd1306_intf.send(((y<<3) + 7) < ssd1306_lcd.height ? ((y<<3) + 7) : (ssd1306_lcd.height - 1));
ssd1306_spiDataMode(1);
}
static void next_page_compat(void)
{
ssd1306_intf.stop();
set_block_compat(__s_column,__s_page + 1, __s_w);
}
static void ssd1325_sendPixels(uint8_t data)
{
if (!(__s_pos & 0x01))
{
__s_leftPixel = data;
data = 0x00;
}
if ((__s_pos & 0x01) || (__s_pos == __s_column + __s_w2 - 1))
{
for (uint8_t i=8; i>0; i--)
{
uint8_t color = (__s_leftPixel & 0x01) ? (ssd1306_color & 0x0F) : 0;
color |= (((data & 0x01) ? (ssd1306_color & 0x0F): 0) << 4);
ssd1306_intf.send(color);
data >>= 1;
__s_leftPixel >>= 1;
}
}
__s_pos++;
}
static void ssd1325_sendPixelsBuffer(const uint8_t *buffer, uint16_t len)
{
while (len--)
{
ssd1325_sendPixels(*buffer);
buffer++;
}
}
//////////////////////// SSD1331 NATIVE MODE ///////////////////////////////////
CONTROLLER_NATIVE_SPI_BLOCK_8BIT_CMDS( 0x15, 0x75 );
///////////// ssd1325 functions below are for SPI display ////////////
///////////// in native/normal mode ////////////
void ssd1325_setMode(lcd_mode_t mode)
{
if (mode == LCD_MODE_NORMAL)
{
ssd1306_lcd.set_block = set_block_native;
ssd1306_lcd.next_page = next_page_native;
}
else if (mode == LCD_MODE_SSD1306_COMPAT )
{
ssd1306_lcd.set_block = set_block_compat;
ssd1306_lcd.next_page = next_page_compat;
}
ssd1306_intf.start();
ssd1306_spiDataMode(0);
ssd1306_intf.send( 0xA0 );
ssd1306_intf.send( 0x10 | (mode == LCD_MODE_NORMAL ? 0x00 : 0x04) );
ssd1306_intf.stop();
return;
}
void ssd1325_128x64_init()
{
ssd1306_lcd.type = LCD_TYPE_CUSTOM;
ssd1306_lcd.width = 128; // specify width
ssd1306_lcd.height = 64; // specify height
// Set functions for compatible mode
ssd1306_lcd.set_block = set_block_compat;
ssd1306_lcd.next_page = next_page_compat;
ssd1306_lcd.send_pixels1 = ssd1325_sendPixels;
ssd1306_lcd.send_pixels_buffer1 = ssd1325_sendPixelsBuffer;
// Set function for 8-bit mode
ssd1306_lcd.send_pixels8 = ssd1306_intf.send;
ssd1306_lcd.set_mode = ssd1325_setMode;
// Use one of 2 functions for initialization below
// Please, read help on this functions and read datasheet before you decide, which
// one needs to be used. For example, ssd1331 is OK with ssd1306_configureI2cDisplay(),
// while st7735 can be initialized only with ssd1306_configureSpiDisplay().
ssd1306_configureI2cDisplay(s_oled_128x64_initData, sizeof(s_oled_128x64_initData));
}
void ssd1325_128x64_spi_init(int8_t rstPin, int8_t cesPin, int8_t dcPin)
{
if (rstPin >=0)
{
ssd1306_resetController( rstPin, 10 );
}
ssd1306_spiInit(cesPin, dcPin);
ssd1325_128x64_init();
}
+98
View File
@@ -0,0 +1,98 @@
/*
MIT License
Copyright (c) 2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* @file oled_ssd1325.h support for SSD1325 OLED 128x64 display
*/
#ifndef _OLED_SSD1325_H_
#define _OLED_SSD1325_H_
#include "ssd1306_hal/io.h"
#include "lcd/lcd_common.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup SSD1325_OLED_API SSD1325: ssd1325 control functions
* @{
*/
/**
* @}
*/
/**
* @ingroup LCD_INTERFACE_API
* @{
*/
/**
* @brief Sets GDRAM autoincrement mode
*
* Sets GDRAM autoincrement mode. By default, to make
* ssd1306_xxx functions compatible with SSD1325 oled display,
* SSD1325 oled is initialized in vertical auto-increment mode.
* But for pure SSD1325 oled operations horizontal auto-increment mode is more suitable.
* So, if you're going to use NanoCanvas8 functions, please call
* ssd1325_setMode(0) prior to using pure SSD1325 oled methods.
*
* @param mode 0 or 1
* @deprecated Use ssd1306_setMode() instead.
*/
void ssd1325_setMode(lcd_mode_t mode);
/**
* @brief Inits 128x64 SSD1325 OLED display (based on SSD1325 controller).
*
* Inits 128x64 SSD1325 OLED display (based on SSD1325 controller).
* User must init communication interface (i2c, spi) prior to calling this function.
* @see ssd1306_i2cInit()
* @see ssd1306_spiInit()
*/
void ssd1325_128x64_init(void);
/**
* @brief Inits 128x64 SSD1325 OLED display over spi (based on SSD1325 controller).
*
* Inits 128x64 SSD1325 OLED display over spi (based on SSD1325 controller)
* @param rstPin - pin controlling LCD reset (-1 if not used)
* @param cesPin - chip enable pin to LCD slave (-1 if not used)
* @param dcPin - data/command pin to control LCD dc (required)
*/
void ssd1325_128x64_spi_init(int8_t rstPin, int8_t cesPin, int8_t dcPin);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
// ----------------------------------------------------------------------------
#endif // _OLED_SSD1325_H_
+195
View File
@@ -0,0 +1,195 @@
/*
MIT License
Copyright (c) 2019, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "oled_ssd1327.h"
#include "lcd_common.h"
#include "intf/ssd1306_interface.h"
#include "intf/spi/ssd1306_spi.h"
#include "ssd1306_hal/io.h"
#ifdef SDL_EMULATION
#include "sdl_core.h"
#endif
extern uint16_t ssd1306_color;
static const PROGMEM uint8_t s_oled_128x128_initData[] =
{
#ifdef SDL_EMULATION
SDL_LCD_SSD1327,
SDL_LCD_SSD1327_GENERIC,
#endif
0xFD, 0x12, // Unlock OLED
0xAE, // OFF /* display off */
0xA8, 0x7F, // multiplex 128
0xA1, 0x00, // Start line
0xA2, 0x00, // Display offset
0xA0, 0x40 | 0x10 | 0x04 | (0x02 | 0x01), // REMAP: vertical increment mode
0xAB, 0x01, // VDD internal
0x81, 0x70, // CONTRAST
0xB1, 0x55, // PHASE 0x51
0xB3, 0x01, // CLK
// 0xB9, //Reload grey scale
0xBC, 0x08, // PRECHARGE
0xBE, 0x07, // VCOMH voltage
0xB6, 0x01, // Second pre-charge
0xA4, // NORMAL
0x2E, // Deactivate scroll
0xAF, // Display ON
};
///////////// ssd1327 functions below are for SPI display ////////////
///////////// in ssd1306 compatible mode ////////////
//////////////////////// SSD1306 COMPATIBLE MODE ///////////////////////////////
static uint8_t __s_column;
static uint8_t __s_w;
static uint8_t __s_w2;
static uint8_t __s_page;
static uint8_t __s_leftPixel;
static uint8_t __s_pos;
static void set_block_compat(lcduint_t x, lcduint_t y, lcduint_t w)
{
uint8_t rx = w ? (x + w - 1) : (ssd1306_lcd.width - 1);
rx = rx < ssd1306_lcd.width ? rx : (ssd1306_lcd.width - 1);
__s_column = x;
__s_page = y;
__s_w = w;
__s_w2 = rx - x + 1;
__s_leftPixel = 0;
__s_pos = __s_column;
ssd1306_intf.start();
ssd1306_spiDataMode(0);
ssd1306_intf.send(0x15);
ssd1306_intf.send(x / 2);
ssd1306_intf.send(rx / 2);
ssd1306_intf.send(0x75);
ssd1306_intf.send(y<<3);
ssd1306_intf.send(((y<<3) + 7) < ssd1306_lcd.height ? ((y<<3) + 7) : (ssd1306_lcd.height - 1));
ssd1306_spiDataMode(1);
}
static void ssd1327_sendPixels(uint8_t data);
static void next_page_compat(void)
{
ssd1306_intf.stop();
set_block_compat(__s_column,__s_page + 1, __s_w);
}
//SSD1306_COMPAT_SPI_BLOCK_8BIT_CMDS( 0x15, 0x75 );
static void ssd1327_sendPixels(uint8_t data)
{
if (!(__s_pos & 0x01))
{
__s_leftPixel = data;
data = 0x00;
}
if ((__s_pos & 0x01) || (__s_pos == __s_column + __s_w2 - 1))
{
for (uint8_t i=8; i>0; i--)
{
uint8_t color = (__s_leftPixel & 0x01) ? (ssd1306_color & 0x0F) : 0;
color |= (((data & 0x01) ? (ssd1306_color & 0x0F): 0) << 4);
ssd1306_intf.send(color);
data >>= 1;
__s_leftPixel >>= 1;
}
}
__s_pos++;
}
static void ssd1327_sendPixels8(uint8_t data)
{
ssd1306_intf.send( data );
}
static void ssd1327_sendPixelsBuffer(const uint8_t *buffer, uint16_t len)
{
while (len--)
{
ssd1327_sendPixels(*buffer);
buffer++;
}
}
//////////////////////// SSD1331 NATIVE MODE ///////////////////////////////////
CONTROLLER_NATIVE_SPI_BLOCK_8BIT_CMDS( 0x15, 0x75 );
///////////// ssd1325 functions below are for SPI display ////////////
///////////// in native/normal mode ////////////
static void ssd1327_setMode(lcd_mode_t mode)
{
if (mode == LCD_MODE_NORMAL)
{
ssd1306_lcd.set_block = set_block_native;
ssd1306_lcd.next_page = next_page_native;
}
else if (mode == LCD_MODE_SSD1306_COMPAT )
{
ssd1306_lcd.set_block = set_block_compat;
ssd1306_lcd.next_page = next_page_compat;
}
ssd1306_intf.start();
ssd1306_spiDataMode(0);
ssd1306_intf.send( 0xA0 );
ssd1306_intf.send( 0x10 | (mode == LCD_MODE_NORMAL ? 0x00 : 0x04) );
ssd1306_intf.stop();
return;
}
void ssd1327_128x128_init()
{
ssd1306_lcd.type = LCD_TYPE_CUSTOM;
ssd1306_lcd.width = 128; // specify width
ssd1306_lcd.height = 128; // specify height
// Set functions for compatible mode
ssd1306_lcd.set_block = set_block_compat;
ssd1306_lcd.next_page = next_page_compat;
ssd1306_lcd.send_pixels1 = ssd1327_sendPixels;
ssd1306_lcd.send_pixels_buffer1 = ssd1327_sendPixelsBuffer;
// Set function for 8-bit mode
ssd1306_lcd.send_pixels8 = ssd1327_sendPixels8;
ssd1306_lcd.set_mode = ssd1327_setMode;
// Use one of 2 functions for initialization below
// Please, read help on this functions and read datasheet before you decide, which
// one needs to be used. For example, ssd1331 is OK with ssd1306_configureI2cDisplay(),
// while st7735 can be initialized only with ssd1306_configureSpiDisplay().
ssd1306_configureI2cDisplay(s_oled_128x128_initData, sizeof(s_oled_128x128_initData));
delay(100);
}
void ssd1327_128x128_spi_init(int8_t rstPin, int8_t cesPin, int8_t dcPin)
{
if (rstPin >=0)
{
ssd1306_resetController( rstPin, 10 );
}
ssd1306_spiInit(cesPin, dcPin);
ssd1327_128x128_init();
}
+83
View File
@@ -0,0 +1,83 @@
/*
MIT License
Copyright (c) 2019, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* @file oled_ssd1325.h support for SSD1325 OLED 128x64 display
*/
#ifndef _OLED_SSD1327_H_
#define _OLED_SSD1327_H_
#include "ssd1306_hal/io.h"
#include "lcd/lcd_common.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup SSD1327_OLED_API SSD1327: ssd1327 control functions
* @{
*/
/**
* @}
*/
/**
* @ingroup LCD_INTERFACE_API
* @{
*/
/**
* @brief Inits 128x128 SSD1327 OLED display (based on SSD1327 controller).
*
* Inits 128x128 SSD1327 OLED display (based on SSD1327 controller).
* User must init communication interface (i2c, spi) prior to calling this function.
* @see ssd1306_i2cInit()
* @see ssd1306_spiInit()
*/
void ssd1327_128x128_init(void);
/**
* @brief Inits 128x128 SSD1327 OLED display over spi (based on SSD1327 controller).
*
* Inits 128x128 SSD1327 OLED display over spi (based on SSD1327 controller)
* @param rstPin - pin controlling LCD reset (-1 if not used)
* @param cesPin - chip enable pin to LCD slave (-1 if not used)
* @param dcPin - data/command pin to control LCD dc (required)
*/
void ssd1327_128x128_spi_init(int8_t rstPin, int8_t cesPin, int8_t dcPin);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
// ----------------------------------------------------------------------------
#endif // _OLED_SSD1327_H_
+287
View File
@@ -0,0 +1,287 @@
/*
MIT License
Copyright (c) 2018-2019, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "oled_ssd1331.h"
#include "lcd_common.h"
#include "ssd1331_commands.h"
#include "intf/ssd1306_interface.h"
#include "intf/spi/ssd1306_spi.h"
#include "ssd1306_hal/io.h"
#ifdef SDL_EMULATION
#include "sdl_core.h"
#endif
#include "nano_gfx_types.h"
extern uint16_t ssd1306_color;
static const PROGMEM uint8_t s_oled96x64_initData[] =
{
#ifdef SDL_EMULATION
SDL_LCD_SSD1331_X8,
0x00,
#endif
SSD1331_DISPLAYOFF, // display off
SSD1331_SEGREMAP, 0x00 | 0x20 | 0x10 | 0x02 | 0x01, /* 8-bit rgb color mode */
SSD1331_SETSTARTLINE, 0x00, // First line to start scanning from
SSD1331_SETDISPLAYOFFSET, 0x00, // Set display offset
SSD1331_NORMALDISPLAY,
SSD1331_SETMULTIPLEX, 63, // Reset to default MUX. See datasheet
SSD1331_SETMASTER, 0x8E, // Set master mode
SSD1331_POWERMODE, 0x0B, // Disable power-safe mode
SSD1331_SETPRECHARGE, 0x31, // Phase 1 and Phase 2 periods
SSD1331_CLOCKDIV, 0xF0, // 7:4 = Oscillator Frequency, 3:0 = CLK Div Ratio (A[3:0]+1 = 1..16)
SSD1331_PRECHARGEA, 0x64,
SSD1331_PRECHARGEB, 0x78,
SSD1331_PRECHARGELEVEL, 0x3A,
SSD1331_VCOMH, 0x3E,
SSD1331_MASTERCURRENT, 0x09,
SSD1331_CONTRASTA, 0x91, // RED
SSD1331_CONTRASTB, 0x50, // GREEN
SSD1331_CONTRASTC, 0x7D, // BLUE
SSD1331_DISPLAYON,
};
static const PROGMEM uint8_t s_oled96x64_initData16[] =
{
#ifdef SDL_EMULATION
SDL_LCD_SSD1331_X16,
0x00,
#endif
SSD1331_DISPLAYOFF, // display off
SSD1331_SEGREMAP, 0x40 | 0x20 | 0x10 | 0x02 | 0x01, /* 16-bit rgb color mode */
SSD1331_SETSTARTLINE, 0x00, // First line to start scanning from
SSD1331_SETDISPLAYOFFSET, 0x00, // Set display offset
SSD1331_NORMALDISPLAY,
SSD1331_SETMULTIPLEX, 63, // Reset to default MUX. See datasheet
SSD1331_SETMASTER, 0x8E, // Set master mode
SSD1331_POWERMODE, 0x0B, // Disable power-safe mode
SSD1331_SETPRECHARGE, 0x31, // Phase 1 and Phase 2 periods
SSD1331_CLOCKDIV, 0xF0, // 7:4 = Oscillator Frequency, 3:0 = CLK Div Ratio (A[3:0]+1 = 1..16)
SSD1331_PRECHARGEA, 0x64,
SSD1331_PRECHARGEB, 0x78,
SSD1331_PRECHARGELEVEL, 0x3A,
SSD1331_VCOMH, 0x3E,
SSD1331_MASTERCURRENT, 0x09,
SSD1331_CONTRASTA, 0x91, // RED
SSD1331_CONTRASTB, 0x50, // GREEN
SSD1331_CONTRASTC, 0x7D, // BLUE
SSD1331_DISPLAYON,
};
static uint8_t s_rotation = 0x04;
//////////////////////// SSD1306 COMPATIBLE MODE ///////////////////////////////
SSD1306_COMPAT_SPI_BLOCK_8BIT_CMDS(
(s_rotation & 1) ? SSD1331_ROWADDR: SSD1331_COLUMNADDR,
(s_rotation & 1) ? SSD1331_COLUMNADDR: SSD1331_ROWADDR );
SSD1306_COMPAT_SEND_PIXELS_RGB8_CMDS();
SSD1306_COMPAT_SEND_PIXELS_RGB16_CMDS();
//////////////////////// SSD1331 NATIVE MODE ///////////////////////////////////
CONTROLLER_NATIVE_SPI_BLOCK_8BIT_CMDS(
(s_rotation & 1) ? SSD1331_ROWADDR: SSD1331_COLUMNADDR,
(s_rotation & 1) ? SSD1331_COLUMNADDR: SSD1331_ROWADDR );
//////////////////////////// GENERIC FUNCTIONS ////////////////////////////
void ssd1331_setMode(lcd_mode_t mode)
{
if (mode == LCD_MODE_NORMAL)
{
s_rotation &= ~0x04;
ssd1306_lcd.set_block = set_block_native;
ssd1306_lcd.next_page = next_page_native;
}
else if (mode == LCD_MODE_SSD1306_COMPAT )
{
s_rotation |= 0x04;
ssd1306_lcd.set_block = set_block_compat;
ssd1306_lcd.next_page = next_page_compat;
}
ssd1331_setRotation( s_rotation );
return;
}
void ssd1331_setRotation(uint8_t rotation)
{
uint8_t ram_mode;
if ((rotation^s_rotation) & 0x01)
{
uint16_t t = ssd1306_lcd.width;
ssd1306_lcd.width = ssd1306_lcd.height;
ssd1306_lcd.height = t;
}
s_rotation = (rotation & 0x03) | (s_rotation & 0x04);
ssd1306_intf.start();
ssd1306_spiDataMode(0);
ssd1306_intf.send( SSD1331_SEGREMAP );
switch (s_rotation)
{
// NORMAL FULL COLOR MODE
case 0:
ram_mode = 0b00110010;
break;
case 1: // 90 degree CW
ram_mode = 0b00110001;
break;
case 2: // 180 degree CW
ram_mode = 0b00100000;
break;
case 3: // 270 degree CW
ram_mode = 0b00100011;
break;
// SSD1306_COMPATIBLE mode
case 4:
ram_mode = 0b00110011;
break;
case 5: // 90 degree CW
ram_mode = 0b00110000;
break;
case 6: // 180 degree CW
ram_mode = 0b00100001;
break;
case 7: // 270 degree CW
ram_mode = 0b00100010;
break;
default: // 270 degree CW
ram_mode = 0b00100000;
break;
}
ssd1306_intf.send( ram_mode );
ssd1306_intf.stop();
}
// 16-bit color in 8-bit display mode
static void ssd1331_sendPixel16_8(uint16_t data)
{
uint8_t color = RGB16_TO_RGB8(data);
ssd1306_intf.send( color );
}
// 8-bit color in 16-bit display mode
static void ssd1331_sendPixel8_16(uint8_t data)
{
uint16_t color = RGB8_TO_RGB16(data);
ssd1306_intf.send( color >> 8 );
ssd1306_intf.send( color & 0xFF );
}
// 16-bit color in 16-bit display mode
static void ssd1331_sendPixel16(uint16_t color)
{
ssd1306_intf.send( color >> 8 );
ssd1306_intf.send( color & 0xFF );
}
void ssd1331_96x64_init()
{
ssd1306_lcd.type = LCD_TYPE_SSD1331;
ssd1306_lcd.height = 64;
ssd1306_lcd.width = 96;
ssd1306_lcd.set_block = set_block_compat;
ssd1306_lcd.next_page = next_page_compat;
ssd1306_lcd.send_pixels1 = send_pixels_compat;
ssd1306_lcd.send_pixels_buffer1 = send_pixels_buffer_compat;
ssd1306_lcd.send_pixels8 = ssd1306_intf.send;
ssd1306_lcd.send_pixels16 = ssd1331_sendPixel16_8;
ssd1306_lcd.set_mode = ssd1331_setMode;
for( uint8_t i=0; i<sizeof(s_oled96x64_initData); i++)
{
ssd1306_sendCommand(pgm_read_byte(&s_oled96x64_initData[i]));
}
}
void ssd1331_96x64_init16()
{
ssd1306_lcd.type = LCD_TYPE_SSD1331;
ssd1306_lcd.height = 64;
ssd1306_lcd.width = 96;
ssd1306_lcd.set_block = set_block_compat;
ssd1306_lcd.next_page = next_page_compat;
ssd1306_lcd.send_pixels1 = send_pixels_compat16;
ssd1306_lcd.send_pixels_buffer1 = send_pixels_buffer_compat16;
ssd1306_lcd.send_pixels8 = ssd1331_sendPixel8_16;
ssd1306_lcd.send_pixels16 = ssd1331_sendPixel16;
ssd1306_lcd.set_mode = ssd1331_setMode;
for( uint8_t i=0; i<sizeof(s_oled96x64_initData16); i++)
{
ssd1306_sendCommand(pgm_read_byte(&s_oled96x64_initData16[i]));
}
}
void ssd1331_96x64_spi_init(int8_t rstPin, int8_t cesPin, int8_t dcPin)
{
if (rstPin >=0)
{
ssd1306_resetController( rstPin, 10 );
}
ssd1306_spiInit(cesPin, dcPin);
ssd1331_96x64_init();
}
void ssd1331_96x64_spi_init16(int8_t rstPin, int8_t cesPin, int8_t dcPin)
{
if (rstPin >=0)
{
ssd1306_resetController( rstPin, 10 );
}
ssd1306_spiInit(cesPin, dcPin);
ssd1331_96x64_init16();
}
void ssd1331_drawLine(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, uint16_t color)
{
ssd1306_intf.start();
ssd1306_spiDataMode(0);
ssd1306_intf.send(SSD1331_DRAWLINE);
ssd1306_intf.send(x1);
ssd1306_intf.send(y1);
ssd1306_intf.send(x2);
ssd1306_intf.send(y2);
ssd1306_intf.send( (color & 0x03) << 4 );
ssd1306_intf.send( (color & 0x1C) << 2 );
ssd1306_intf.send( (color & 0xE0) >> 2 );
ssd1306_intf.stop();
}
void ssd1331_copyBlock(uint8_t left, uint8_t top, uint8_t right, uint8_t bottom, uint8_t newLeft, uint8_t newTop)
{
ssd1306_intf.start();
ssd1306_spiDataMode(0);
ssd1306_intf.send(0x23);
ssd1306_intf.send(left);
ssd1306_intf.send(top);
ssd1306_intf.send(right);
ssd1306_intf.send(bottom);
ssd1306_intf.send(newLeft);
ssd1306_intf.send(newTop);
ssd1306_intf.stop();
}
+146
View File
@@ -0,0 +1,146 @@
/*
MIT License
Copyright (c) 2018-2019, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* @file oled_ssd1331.h support for RGB OLED 96x64 display
*/
#ifndef _OLED_SSD1331_H_
#define _OLED_SSD1331_H_
#include "ssd1306_hal/io.h"
#include "lcd/lcd_common.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup SSD1331_API SSD1331: ssd1331 control functions
* @{
*/
/**
* @brief Sets screen orientation (rotation)
*
* Sets screen orientation (rotation): 0 - normal, 1 - 90 CW, 2 - 180 CW, 3 - 270 CW
* @param rotation - screen rotation 0 - normal, 1 - 90 CW, 2 - 180 CW, 3 - 270 CW
* @note works only with ssd1331 display
*/
void ssd1331_setRotation(uint8_t rotation);
/**
* @}
*/
/**
* @ingroup LCD_INTERFACE_API
* @{
*/
/**
* @brief Sets GDRAM autoincrement mode
*
* Sets GDRAM autoincrement mode. By default, to make
* ssd1306_xxx functions compatible with RGB oled display,
* RGB oled is initialized in vertical auto-increment mode.
* But for pure rbg oled operations horizontal auto-increment mode is more suitable.
* So, if you're going to use NanoCanvas8 functions, please call
* ssd1331_setMode(0) prior to using pure RGB methods.
*
* @param mode 0 or 1
* @deprecated Use ssd1306_setMode() instead.
*/
void ssd1331_setMode(lcd_mode_t mode);
/**
* @brief Inits 96x64 RGB OLED display (based on SSD1331 controller).
*
* Inits 96x64 RGB OLED display (based on SSD1331 controller).
* User must init communication interface (i2c, spi) prior to calling this function.
* @see ssd1306_i2cInit()
* @see ssd1306_spiInit()
*/
void ssd1331_96x64_init(void);
/**
* @brief Inits 96x64 RGB OLED display over spi in 8-bit mode (based on SSD1331 controller).
*
* Inits 96x64 RGB OLED display over spi in 8-bit mode (based on SSD1331 controller)
* @param rstPin - pin controlling LCD reset (-1 if not used)
* @param cesPin - chip enable pin to LCD slave (-1 if not used)
* @param dcPin - data/command pin to control LCD dc (required)
*/
void ssd1331_96x64_spi_init(int8_t rstPin, int8_t cesPin, int8_t dcPin);
/**
* @brief Inits 96x64 RGB OLED display over spi in 16-bit mode (based on SSD1331 controller).
*
* Inits 96x64 RGB OLED display over spi in 16-bit mode (based on SSD1331 controller)
* @param rstPin - pin controlling LCD reset (-1 if not used)
* @param cesPin - chip enable pin to LCD slave (-1 if not used)
* @param dcPin - data/command pin to control LCD dc (required)
*/
void ssd1331_96x64_spi_init16(int8_t rstPin, int8_t cesPin, int8_t dcPin);
/**
* Draws line
* @param x1 - x position in pixels of start point
* @param y1 - y position in pixels of start point
* @param x2 - x position in pixels of end point
* @param y2 - y position in pixels of end point
* @param color - color of the line, refer to RGB_COLOR8 macros
*
* @note This API can be used only with ssd1331 RGB oled displays
*/
void ssd1331_drawLine(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, uint16_t color);
/**
* Copies block in GDRAM to new position
* @param left column start of block to copy
* @param top row start of block to copy
* @param right column end of block to copy
* @param bottom row end of block to copy
* @param newLeft new column start
* @param newTop new row start
*
* @note This API can be used only with ssd1331 RGB oled displays
* @note after copy command is sent, it takes some time from oled
* controller to complete operation. So, it is HIGHLY recommended
* to wait for reasonable time before send other graphics operations
* (for example, use 250us delay). This time is required for
* oled display to become ready to accept new commands.
*/
void ssd1331_copyBlock(uint8_t left, uint8_t top, uint8_t right, uint8_t bottom, uint8_t newLeft, uint8_t newTop);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
// ----------------------------------------------------------------------------
#endif // _OLED_SSD1331_H_
+226
View File
@@ -0,0 +1,226 @@
/*
MIT License
Copyright (c) 2018-2019, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "oled_ssd1351.h"
#include "lcd_common.h"
#include "ssd1351_commands.h"
#include "intf/ssd1306_interface.h"
#include "intf/spi/ssd1306_spi.h"
#include "ssd1306_hal/io.h"
#include "nano_gfx_types.h"
#ifdef SDL_EMULATION
#include "sdl_core.h"
#endif
#define CMD_ARG 0xFF
extern uint16_t ssd1306_color;
extern uint32_t s_ssd1306_spi_clock;
static const PROGMEM uint8_t s_oled128x128_initData[] =
{
#ifdef SDL_EMULATION
SDL_LCD_SSD1351,
0x00,
#endif
SSD1351_UNLOCK, CMD_ARG, 0x12,
SSD1351_UNLOCK, CMD_ARG, 0xB1,
SSD1351_SLEEP_ON,
SSD1351_CLOCKDIV, CMD_ARG, 0xF1, // 7:4 = Oscillator Frequency, 3:0 = CLK Div Ratio (A[3:0]+1 = 1..16)
SSD1351_SETMULTIPLEX, CMD_ARG, 127, // Reset to default MUX. See datasheet
SSD1351_SEGREMAP, CMD_ARG, 0B00110101, // 16-bit rgb color mode
SSD1351_SETSTARTLINE, CMD_ARG, 0x00, // First line to start scanning from
SSD1351_SETDISPLAYOFFSET, CMD_ARG, 0x00, // Set display offset
SSD1351_SETGPIO, CMD_ARG, 0x00, // GPIO OFF
SSD1351_SETFUNCTION, CMD_ARG, 0x01,
SSD1351_SETPRECHARGE, CMD_ARG, 0x32, // Phase 1 and Phase 2 periods
SSD1351_VCOMH, CMD_ARG, 0x05, //
SSD1351_PRECHARGELEVEL, CMD_ARG, 0x17,
SSD1351_NORMALDISPLAY,
SSD1351_CONTRAST, CMD_ARG, 0xC8, // RED
CMD_ARG, 0x80, // GREEN
CMD_ARG, 0xC8, // BLUE
SSD1351_MASTERCURRENT, CMD_ARG, 0x0F, //
SSD1351_EXTVSL, CMD_ARG, 0xA0, CMD_ARG, 0xB5, CMD_ARG, 0x55,
SSD1351_PRECHARGESECOND, CMD_ARG, 0x01, //
SSD1351_SLEEP_OFF, // Disable power-safe mode
SSD1351_NORMALDISPLAY,
};
static uint8_t s_column;
static uint8_t s_page;
static void ssd1351_setBlock(lcduint_t x, lcduint_t y, lcduint_t w)
{
uint8_t rx = w ? (x + w - 1) : (ssd1306_lcd.width - 1);
s_column = x;
s_page = y;
ssd1306_intf.start();
ssd1306_spiDataMode(0);
ssd1306_intf.send(SSD1351_COLUMNADDR);
ssd1306_spiDataMode(1); // According to datasheet all args must be passed in data mode
ssd1306_intf.send(x);
ssd1306_intf.send(rx < ssd1306_lcd.width ? rx : (ssd1306_lcd.width - 1));
ssd1306_spiDataMode(0);
ssd1306_intf.send(SSD1351_ROWADDR);
ssd1306_spiDataMode(1); // According to datasheet all args must be passed in data mode
ssd1306_intf.send(y<<3);
ssd1306_intf.send(((y<<3) + 7) < ssd1306_lcd.height ? ((y<<3) + 7) : (ssd1306_lcd.height - 1));
ssd1306_spiDataMode(0);
ssd1306_intf.send(SSD1331_WRITEDATA);
ssd1306_spiDataMode(1);
}
static void ssd1351_setBlock2(lcduint_t x, lcduint_t y, lcduint_t w)
{
uint8_t rx = w ? (x + w - 1) : (ssd1306_lcd.width - 1);
ssd1306_intf.start();
ssd1306_spiDataMode(0);
ssd1306_intf.send(SSD1351_COLUMNADDR);
ssd1306_spiDataMode(1); // According to datasheet all args must be passed in data mode
ssd1306_intf.send(x);
ssd1306_intf.send(rx < ssd1306_lcd.width ? rx : (ssd1306_lcd.width - 1));
ssd1306_spiDataMode(0);
ssd1306_intf.send(SSD1351_ROWADDR);
ssd1306_spiDataMode(1); // According to datasheet all args must be passed in data mode
ssd1306_intf.send(y);
ssd1306_intf.send(ssd1306_lcd.height - 1);
ssd1306_spiDataMode(0);
ssd1306_intf.send(SSD1331_WRITEDATA);
ssd1306_spiDataMode(1);
}
static void ssd1351_nextPage(void)
{
ssd1306_intf.stop();
ssd1351_setBlock(s_column,s_page+1,0);
}
static void ssd1351_nextPage2(void)
{
}
void ssd1351_setMode(lcd_mode_t mode)
{
ssd1306_intf.start();
ssd1306_spiDataMode(0);
ssd1306_intf.send( SSD1351_SEGREMAP );
ssd1306_spiDataMode(1);
ssd1306_intf.send( 0B00110100 | mode );
ssd1306_intf.stop();
if (mode == LCD_MODE_SSD1306_COMPAT)
{
ssd1306_lcd.set_block = ssd1351_setBlock;
ssd1306_lcd.next_page = ssd1351_nextPage;
}
else if (mode == LCD_MODE_NORMAL )
{
ssd1306_lcd.set_block = ssd1351_setBlock2;
ssd1306_lcd.next_page = ssd1351_nextPage2;
}
}
static void ssd1351_sendPixels(uint8_t data)
{
for (uint8_t i=8; i>0; i--)
{
if ( data & 0x01 )
{
ssd1306_intf.send( (uint8_t)(ssd1306_color>>8) );
ssd1306_intf.send( (uint8_t)(ssd1306_color) );
}
else
{
ssd1306_intf.send( 0B00000000 );
ssd1306_intf.send( 0B00000000 );
}
data >>= 1;
}
}
static void ssd1351_sendPixelsBuffer(const uint8_t *buffer, uint16_t len)
{
while(len--)
{
ssd1351_sendPixels(*buffer);
buffer++;
}
}
static void ssd1351_sendPixel8(uint8_t data)
{
uint16_t color = RGB8_TO_RGB16(data);
ssd1306_intf.send( color >> 8 );
ssd1306_intf.send( color & 0xFF );
}
static void ssd1351_sendPixel16(uint16_t color)
{
ssd1306_intf.send( color >> 8 );
ssd1306_intf.send( color & 0xFF );
}
void ssd1351_128x128_init()
{
ssd1306_lcd.type = LCD_TYPE_SSD1331;
ssd1306_lcd.height = 128;
ssd1306_lcd.width = 128;
ssd1306_lcd.set_block = ssd1351_setBlock;
ssd1306_lcd.next_page = ssd1351_nextPage;
ssd1306_lcd.send_pixels1 = ssd1351_sendPixels;
ssd1306_lcd.send_pixels_buffer1 = ssd1351_sendPixelsBuffer;
ssd1306_lcd.send_pixels8 = ssd1351_sendPixel8;
ssd1306_lcd.send_pixels16 = ssd1351_sendPixel16;
ssd1306_lcd.set_mode = ssd1351_setMode;
ssd1306_intf.start();
ssd1306_spiDataMode(0);
for( uint8_t i=0; i<sizeof(s_oled128x128_initData); i++)
{
uint8_t data = pgm_read_byte(&s_oled128x128_initData[i]);
if (data == CMD_ARG)
{
data = pgm_read_byte(&s_oled128x128_initData[++i]);
ssd1306_spiDataMode(1);
ssd1306_intf.send(data);
ssd1306_spiDataMode(0);
}
else
{
ssd1306_intf.send(data);
}
}
ssd1306_intf.stop();
}
void ssd1351_128x128_spi_init(int8_t rstPin, int8_t cesPin, int8_t dcPin)
{
if (rstPin >=0)
{
ssd1306_resetController( rstPin, 20 );
}
/* ssd1351 cannot work faster than at 4MHz per datasheet */
s_ssd1306_spi_clock = 4400000;
ssd1306_spiInit(cesPin, dcPin);
ssd1351_128x128_init();
}
+88
View File
@@ -0,0 +1,88 @@
/*
MIT License
Copyright (c) 2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* @file oled_ssd1351.h support for RGB OLED 128x128 display
*/
#ifndef _OLED_SSD1351_H_
#define _OLED_SSD1351_H_
#include "ssd1306_hal/io.h"
#include "lcd/lcd_common.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @ingroup LCD_INTERFACE_API
* @{
*/
/**
* @brief Sets GDRAM autoincrement mode
*
* Sets GDRAM autoincrement mode. By default, to make
* ssd1306_xxx functions compatible with RGB oled display,
* RGB oled is initialized in vertical auto-increment mode.
* But for pure rbg oled operations horizontal auto-increment mode is more suitable.
* So, if you're going to use NanoCanvas8 functions, please call
* ssd1351_setMode(0) prior to using pure RGB methods.
*
* @param mode 0 or 1
* @deprecated Use ssd1306_setMode() instead.
*/
void ssd1351_setMode(lcd_mode_t mode);
/**
* @brief Inits 128x128 RGB OLED display (based on SSD1351 controller).
*
* Inits 128x128 RGB OLED display (based on SSD1351 controller).
* User must init communication interface (i2c, spi) prior to calling this function.
* @see ssd1306_i2cInit()
* @see ssd1306_spiInit()
*/
void ssd1351_128x128_init(void);
/**
* @brief Inits 128x128 RGB OLED display over spi (based on SSD1351 controller).
*
* Inits 128x128 RGB OLED display over spi (based on SSD1351 controller)
* @param rstPin - pin controlling LCD reset (-1 if not used)
* @param cesPin - chip enable pin to LCD slave (-1 if not used)
* @param dcPin - data/command pin to control LCD dc (required)
*/
void ssd1351_128x128_spi_init(int8_t rstPin, int8_t cesPin, int8_t dcPin);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
// ----------------------------------------------------------------------------
#endif // _OLED_SSD1351_H_
+173
View File
@@ -0,0 +1,173 @@
/*
MIT License
Copyright (c) 2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "oled_template.h"
#include "lcd_common.h"
#include "intf/ssd1306_interface.h"
#include "intf/spi/ssd1306_spi.h"
#include "ssd1306_hal/io.h"
#ifdef SDL_EMULATION
#include "sdl_core.h"
#endif
extern uint16_t ssd1306_color;
static const PROGMEM uint8_t s_oled_WxH_initData[] =
{
#ifdef SDL_EMULATION
SDL_LCD_TEMPLATE,
0x00,
#endif
// Specify display initialization commands here
// The commands should be in format, required by
// ssd1306_configureI2cDisplay() or ssd1306_configureSpiDisplay()
// functions. Refer to their documenation.
0x00, 0x00,
};
///////////// template functions below are for SPI display ////////////
///////////// in ssd1306 compatible mode ////////////
static uint8_t s_column;
static uint8_t s_page;
// The function must set block to draw data
static void template_setBlock_compat(lcduint_t x, lcduint_t y, lcduint_t w)
{
uint8_t rx = w ? (x + w - 1) : (ssd1306_lcd.width - 1);
s_column = x;
s_page = y;
ssd1306_intf.start();
ssd1306_spiDataMode(0);
ssd1306_intf.send(0x00); // Send column addr command to controller
ssd1306_intf.send(x);
ssd1306_intf.send(rx < ssd1306_lcd.width ? rx : (ssd1306_lcd.width - 1));
ssd1306_intf.send(0x00); // Replace with row addr command to controller
ssd1306_intf.send(y<<3);
ssd1306_intf.send(((y<<3) + 7) < ssd1306_lcd.height ? ((y<<3) + 7) : (ssd1306_lcd.height - 1));
ssd1306_spiDataMode(1);
}
static void template_nextPage_compat(void)
{
ssd1306_intf.stop();
template_setBlock_compat(s_column,s_page+1,0);
}
static void template_sendPixels(uint8_t data)
{
for (uint8_t i=8; i>0; i--)
{
if ( data & 0x01 )
{
ssd1306_intf.send( (uint8_t)ssd1306_color );
}
else
{
ssd1306_intf.send( 0B00000000 );
}
data >>= 1;
}
}
static void template_sendPixelsBuffer(const uint8_t *buffer, uint16_t len)
{
while(len--)
{
template_sendPixels(*buffer);
buffer++;
}
}
///////////// template functions below are for SPI display ////////////
///////////// in native/normal mode ////////////
static void template_setBlock(lcduint_t x, lcduint_t y, lcduint_t w)
{
uint8_t rx = w ? (x + w - 1) : (ssd1306_lcd.width - 1);
ssd1306_intf.start();
ssd1306_spiDataMode(0);
ssd1306_intf.send(0x00); // Send column address command here
ssd1306_intf.send(x);
ssd1306_intf.send(rx < ssd1306_lcd.width ? rx : (ssd1306_lcd.width - 1));
ssd1306_intf.send(0x00); // Send row address command here
ssd1306_intf.send(y);
ssd1306_intf.send(ssd1306_lcd.height - 1);
ssd1306_spiDataMode(1);
}
static void template_nextPage(void)
{
}
void template_setMode(lcd_mode_t mode)
{
if (mode == LCD_MODE_NORMAL)
{
ssd1306_lcd.set_block = template_setBlock;
ssd1306_lcd.next_page = template_nextPage;
}
else if (mode == LCD_MODE_SSD1306_COMPAT)
{
ssd1306_lcd.set_block = template_setBlock_compat;
ssd1306_lcd.next_page = template_nextPage_compat;
}
// Send command to update controller
// ssd1306_intf.start();
// ssd1306_spiDataMode(0);
// ssd1306_intf.send( SSD1331_SEGREMAP );
// ssd1306_intf.stop();
return;
}
void template_WxH_init()
{
ssd1306_lcd.type = LCD_TYPE_CUSTOM;
ssd1306_lcd.width = 96; // specify width
ssd1306_lcd.height = 64; // specify height
// Set functions for compatible mode
ssd1306_lcd.set_block = template_setBlock_compat;
ssd1306_lcd.next_page = template_nextPage_compat;
ssd1306_lcd.send_pixels1 = template_sendPixels;
ssd1306_lcd.send_pixels_buffer1 = template_sendPixelsBuffer;
// Set function for 8-bit mode
ssd1306_lcd.send_pixels8 = ssd1306_intf.send;
ssd1306_lcd.set_mode = template_setMode;
// Use one of 2 functions for initialization below
// Please, read help on this functions and read datasheet before you decide, which
// one needs to be used. For example, ssd1331 is OK with ssd1306_configureI2cDisplay(),
// while st7735 can be initialized only with ssd1306_configureSpiDisplay().
ssd1306_configureI2cDisplay(s_oled_WxH_initData, sizeof(s_oled_WxH_initData));
// ssd1306_configureSpiDisplay(s_oled_WxH_initData, sizeof(s_oled_WxH_initData));
}
void template_WxH_spi_init(int8_t rstPin, int8_t cesPin, int8_t dcPin)
{
if (rstPin >=0)
{
ssd1306_resetController( rstPin, 10 );
}
ssd1306_spiInit(cesPin, dcPin);
template_WxH_init();
}
+99
View File
@@ -0,0 +1,99 @@
/*
MIT License
Copyright (c) 2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* @file oled_template.h support for TEMPLATE OLED WxH display
*/
#ifndef _OLED_TEMPLATE_H_
#define _OLED_TEMPLATE_H_
#include "ssd1306_hal/io.h"
#include "lcd/lcd_common.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup TEMPLATE_OLED_API TEMPLATE: template control functions
* @{
*/
// PLACE ANY OLED SPECIFIC FUNCTIONS HERE
/**
* @}
*/
/**
* @ingroup LCD_INTERFACE_API
* @{
*/
/**
* @brief Sets GDRAM autoincrement mode
*
* Sets GDRAM autoincrement mode. By default, to make
* ssd1306_xxx functions compatible with TEMPLATE oled display,
* TEMPLATE oled is initialized in vertical auto-increment mode.
* But for pure TEMPLATE oled operations horizontal auto-increment mode is more suitable.
* So, if you're going to use NanoCanvas8 functions, please call
* template_setMode(0) prior to using pure TEMPLATE oled methods.
*
* @param mode 0 or 1
* @deprecated Use ssd1306_setMode() instead.
*/
void template_setMode(lcd_mode_t mode);
/**
* @brief Inits WxH TEMPLATE OLED display (based on TEMPLATE controller).
*
* Inits WxH TEMPLATE OLED display (based on TEMPLATE controller).
* User must init communication interface (i2c, spi) prior to calling this function.
* @see ssd1306_i2cInit()
* @see ssd1306_spiInit()
*/
void template_WxH_init(void);
/**
* @brief Inits WxH TEMPLATE OLED display over spi (based on TEMPLATE controller).
*
* Inits WxH TEMPLATE OLED display over spi (based on TEMPLATE controller)
* @param rstPin - pin controlling LCD reset (-1 if not used)
* @param cesPin - chip enable pin to LCD slave (-1 if not used)
* @param dcPin - data/command pin to control LCD dc (required)
*/
void template_WxH_spi_init(int8_t rstPin, int8_t cesPin, int8_t dcPin);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
// ----------------------------------------------------------------------------
#endif // _OLED_TEMPLATE_H_
+76
View File
@@ -0,0 +1,76 @@
/*
MIT License
Copyright (c) 2017-2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* @file pcd8544_commands.h PCD8544 commands definitions
*/
#ifndef _PCD8544_COMMANDS_H_
#define _PCD8544_COMMANDS_H_
#ifdef __cplusplus
extern "C" {
#endif
/** PCD8544 LCD driver commands */
enum ESsd1306Commands
{
PCD8544_NOP = 0x00,
// Regular functions
PCD8544_FUNCTIONSET = 0x20,
PCD8544_DISPLAYCONTROL = 0x08,
PCD8544_SETYADDR = 0x40,
PCD8544_SETXADDR = 0x80,
// Extended functions
PCD8544_SETTEMP = 0x04,
PCD8544_SETBIAS = 0x10,
PCD8544_SETVOP = 0x80,
};
/** PCD8544 supported function modes. */
enum EPcd8544FunctionMode
{
PCD8544_POWERDOWN = 0x04,
PCD8544_VERTICAL_ADDR_MODE = 0x02,
PCD8544_EXTENDEDINSTRUCTION = 0x01,
};
/** PCD8544 supported display modes. */
enum EPcd8544DisplayMode
{
PCD8544_DISPLAYBLANK = 0x0,
PCD8544_DISPLAYALLON = 0x1,
PCD8544_DISPLAYNORMAL = 0x4,
PCD8544_DISPLAYINVERTED = 0x5,
};
#ifdef __cplusplus
}
#endif
// ----------------------------------------------------------------------------
#endif // _PCD8544_COMMANDS_H_
+82
View File
@@ -0,0 +1,82 @@
/*
MIT License
Copyright (c) 2017-2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* @file ssd1306_commands.h SSD1306 commands definitions
*/
#ifndef _SSD1306_COMMANDS_H_
#define _SSD1306_COMMANDS_H_
#ifdef __cplusplus
extern "C" {
#endif
/** SSD1306 LCD driver commands */
enum ESsd1306Commands
{
SSD1306_SETLOWCOLUMN = 0x00,
SSD1306_SETHIGHCOLUMN = 0x10,
SSD1306_MEMORYMODE = 0x20,
SSD1306_COLUMNADDR = 0x21,
SSD1306_PAGEADDR = 0x22,
SSD1306_SETSTARTLINE = 0x40,
SSD1306_DEFAULT_ADDRESS = 0x78,
SSD1306_SETCONTRAST = 0x81,
SSD1306_CHARGEPUMP = 0x8D,
SSD1306_SEGREMAP = 0xA0,
SSD1306_DISPLAYALLON_RESUME = 0xA4,
SSD1306_DISPLAYALLON = 0xA5,
SSD1306_NORMALDISPLAY = 0xA6,
SSD1306_INVERTDISPLAY = 0xA7,
SSD1306_SETMULTIPLEX = 0xA8,
SSD1306_DISPLAYOFF = 0xAE,
SSD1306_DISPLAYON = 0xAF,
SSD1306_SETPAGE = 0xB0,
SSD1306_COMSCANINC = 0xC0,
SSD1306_COMSCANDEC = 0xC8,
SSD1306_SETDISPLAYOFFSET = 0xD3,
SSD1306_SETDISPLAYCLOCKDIV = 0xD5,
SSD1306_SETPRECHARGE = 0xD9,
SSD1306_SETCOMPINS = 0xDA,
SSD1306_SETVCOMDETECT = 0xDB,
SSD1306_SWITCHCAPVCC = 0x02,
SSD1306_NOP = 0xE3,
};
/** SSD1306 supported memory modes. */
enum ESsd1306MemoryMode
{
HORIZONTAL_ADDRESSING_MODE = 0x00,
VERTICAL_ADDRESSING_MODE = 0x01,
PAGE_ADDRESSING_MODE = 0x02,
};
#ifdef __cplusplus
}
#endif
// ----------------------------------------------------------------------------
#endif // _SSD1306_COMMANDS_H_
+69
View File
@@ -0,0 +1,69 @@
/*
MIT License
Copyright (c) 2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* @file ssd1331_commands.h SSD1331 commands definitions
*/
#ifndef _SSD1331_COMMANDS_H_
#define _SSD1331_COMMANDS_H_
#ifdef __cplusplus
extern "C" {
#endif
/** SSD1331 LCD driver commands */
enum ESsd1331Commands
{
SSD1331_COLUMNADDR = 0x15,
SSD1331_DRAWLINE = 0x21,
SSD1331_ROWADDR = 0x75,
SSD1331_CONTRASTA = 0x81,
SSD1331_CONTRASTB = 0x82,
SSD1331_CONTRASTC = 0x83,
SSD1331_MASTERCURRENT = 0x87,
SSD1331_PRECHARGEA = 0x8A,
SSD1331_PRECHARGEB = 0x8B,
SSD1331_SEGREMAP = 0xA0,
SSD1331_SETSTARTLINE = 0xA1,
SSD1331_SETDISPLAYOFFSET = 0xA2,
SSD1331_NORMALDISPLAY = 0xA4,
SSD1331_SETMULTIPLEX = 0xA8,
SSD1331_SETMASTER = 0xAD,
SSD1331_DISPLAYOFF = 0xAE,
SSD1331_DISPLAYON = 0xAF,
SSD1331_POWERMODE = 0xB0,
SSD1331_SETPRECHARGE = 0xB1,
SSD1331_CLOCKDIV = 0xB3,
SSD1331_PRECHARGELEVEL = 0xBB,
SSD1331_VCOMH = 0xBE,
SSD1331_NOP = 0xE3,
};
#ifdef __cplusplus
}
#endif
// ----------------------------------------------------------------------------
#endif // _SSD1331_COMMANDS_H_
+75
View File
@@ -0,0 +1,75 @@
/*
MIT License
Copyright (c) 2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* @file ssd1351_commands.h SSD1331 commands definitions
*/
#ifndef _SSD1351_COMMANDS_H_
#define _SSD1351_COMMANDS_H_
#ifdef __cplusplus
extern "C" {
#endif
/** SSD1351 LCD driver commands */
enum ESsd1351Commands
{
SSD1351_COLUMNADDR = 0x15,
SSD1331_WRITEDATA = 0x5C,
SSD1351_ROWADDR = 0x75,
SSD1351_SEGREMAP = 0xA0,
SSD1351_SETSTARTLINE = 0xA1,
SSD1351_SETDISPLAYOFFSET = 0xA2,
SSD1351_SETFUNCTION = 0xAB,
SSD1351_NOP = 0xAD,
SSD1351_ALLOFF = 0xA4,
SSD1351_DISPLAYON = 0xA5,
SSD1351_NORMALDISPLAY = 0xA6,
SSD1351_DISPLAYINVERSE = 0xA7,
SSD1351_SLEEP_ON = 0xAE,
SSD1351_SLEEP_OFF = 0xAF,
SSD1351_NOP2 = 0xB0,
SSD1351_SETPRECHARGE = 0xB1,
SSD1351_CLOCKDIV = 0xB3,
SSD1351_EXTVSL = 0xB4,
SSD1351_SETGPIO = 0xB5,
SSD1351_PRECHARGESECOND = 0xB6,
SSD1351_PRECHARGELEVEL = 0xBB,
SSD1351_VCOMH = 0xBE,
SSD1351_CONTRAST = 0xC1,
SSD1351_MASTERCURRENT = 0xC7,
SSD1351_SETMULTIPLEX = 0xCA,
SSD1351_PRECHARGEA = 0x8A,
SSD1351_PRECHARGEB = 0x8B,
SSD1351_NOP3 = 0xE3,
SSD1351_UNLOCK = 0xFD,
};
#ifdef __cplusplus
}
#endif
// ----------------------------------------------------------------------------
#endif // _SSD1351_COMMANDS_H_
+71
View File
@@ -0,0 +1,71 @@
/*
MIT License
Copyright (c) 2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* @file vga_commands.h VGA library commands definitions
*/
#ifndef _VGA_COMMANDS_H_
#define _VGA_COMMANDS_H_
#ifdef __cplusplus
extern "C" {
#endif
/** VGA driver commands */
enum EVgaCommands
{
/**
* VGA_SET_BLOCK command sets rectangle in VGA ram to send pixels to.
* The command needs 4 byte-arguments:
* left boundary in pixels,
* right boundary in pixels,
* top boundary in pixels,
* bottom boundary in pixels, (last arg in not implemented yet)
*/
VGA_SET_BLOCK = 0x01,
/**
* VGA_SET_MODE command sets memory addressing mode: there are 2 modes
* available: 0 - normal addressing mode, 1 - ssd1306 compatible mode.
* After sending each pixel in normal addressing mode, x position shifts
* right by 1 pixel until end of block is reached, then y position shifts
* down by 1 pixel, and x position move to the start of block.
* After sending each pixel in ssd1306 compatible mode, y position shifts
* down by 1 pixel until 8 vertical pixels are printed, then y position changes
* to top of block, and x position shifts right by 1 pixel.
*/
VGA_SET_MODE = 0x02,
VGA_SET_RESOLUTION = 0x03,
VGA_DISPLAY_ON = 0x04,
};
#ifdef __cplusplus
}
#endif
// ----------------------------------------------------------------------------
#endif
+145
View File
@@ -0,0 +1,145 @@
/*
MIT License
Copyright (c) 2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "vga_monitor.h"
#include "vga_commands.h"
#include "lcd_common.h"
#include "intf/ssd1306_interface.h"
#include "ssd1306_hal/io.h"
static uint8_t s_column = 0;
static uint8_t s_page = 0;
extern uint16_t ssd1306_color;
static void vga_set_block1(lcduint_t x, lcduint_t y, lcduint_t w)
{
uint8_t rx = w ? (x + w - 1) : (ssd1306_lcd.width - 1);
s_column = x;
s_page = y;
ssd1306_intf.start();
ssd1306_intf.send(0x00);
ssd1306_intf.send(VGA_SET_BLOCK);
ssd1306_intf.send(s_column);
ssd1306_intf.send(rx);
ssd1306_intf.send(s_page * 8);
ssd1306_intf.stop();
ssd1306_intf.start();
ssd1306_intf.send(0x40);
}
static void vga_next_page1(void)
{
ssd1306_intf.stop();
vga_set_block1(s_column,s_page+1,0);
}
static void vga_set_block2(lcduint_t x, lcduint_t y, lcduint_t w)
{
uint8_t rx = w ? (x + w - 1) : (ssd1306_lcd.width - 1);
ssd1306_intf.start();
ssd1306_intf.send(0x00);
ssd1306_intf.send(VGA_SET_BLOCK); // set block
ssd1306_intf.send(x);
ssd1306_intf.send(rx);
ssd1306_intf.send(y);
ssd1306_intf.stop();
ssd1306_intf.start();
ssd1306_intf.send(0x40);
}
static void vga_next_page2(void)
{
}
static void vga_send_pixels(uint8_t data)
{
for (uint8_t i=8; i>0; i--)
{
if ( data & 0x01 )
{
ssd1306_intf.send( (uint8_t)ssd1306_color );
}
else
{
ssd1306_intf.send( 0B00000000 );
}
data >>= 1;
}
}
static void vga_send_pixels_buffer(const uint8_t *buffer, uint16_t len)
{
while(len--)
{
vga_send_pixels(*buffer);
buffer++;
}
}
static void vga_set_mode(lcd_mode_t mode)
{
if (mode == LCD_MODE_NORMAL)
{
ssd1306_lcd.set_block = vga_set_block2;
ssd1306_lcd.next_page = vga_next_page2;
}
else if (mode == LCD_MODE_SSD1306_COMPAT)
{
ssd1306_lcd.set_block = vga_set_block1;
ssd1306_lcd.next_page = vga_next_page1;
}
ssd1306_intf.start();
ssd1306_intf.send( 0x00 );
ssd1306_intf.send( VGA_SET_MODE );
ssd1306_intf.send( (uint8_t)mode );
ssd1306_intf.stop();
// empty for a while
}
void vga_96x40_8colors_init(void)
{
ssd1306_lcd.type = LCD_TYPE_SSD1331;
ssd1306_lcd.width = 96;
ssd1306_lcd.height = 40;
ssd1306_lcd.set_block = vga_set_block1;
ssd1306_lcd.next_page = vga_next_page1;
ssd1306_lcd.send_pixels1 = vga_send_pixels;
ssd1306_lcd.send_pixels_buffer1 = vga_send_pixels_buffer;
ssd1306_lcd.send_pixels8 = ssd1306_intf.send;
ssd1306_lcd.set_mode = vga_set_mode;
}
void vga_128x64_mono_init(void)
{
ssd1306_lcd.type = LCD_TYPE_SSD1306;
ssd1306_lcd.width = 128;
ssd1306_lcd.height = 64;
ssd1306_lcd.set_block = vga_set_block2;
ssd1306_lcd.next_page = vga_next_page2;
ssd1306_lcd.send_pixels1 = ssd1306_intf.send;
ssd1306_lcd.send_pixels_buffer1 = ssd1306_intf.send_buffer;
ssd1306_lcd.set_mode = vga_set_mode;
}
+75
View File
@@ -0,0 +1,75 @@
/*
MIT License
Copyright (c) 2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* @file vga_monitor.h Interface to vga_monitor
*/
#ifndef _SSD1306_VGA_MONITOR_H_
#define _SSD1306_VGA_MONITOR_H_
#include "ssd1306_hal/io.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @ingroup LCD_INTERFACE_API
* @{
*/
/**
* @brief Inits 96x40 color VGA display.
*
* Inits 96x40 color VGA display. This mode supports 8 colors: 3 bits per pixel.
* User must init communication interface (uart) for vga client mode or init vga
* interface for host mode prior to calling this function.
*
* @see ssd1306_uartInit_Builtin()
* @see ssd1306_vga_controller_init()
*/
void vga_96x40_8colors_init(void);
/**
* @brief Inits 128x64 monochrome VGA display.
*
* Inits 128x64 monochrome VGA display. This mode supports 2 colors: black and white.
* User must init communication interface (uart) for vga client mode or init vga
* interface for host mode prior to calling this function.
*
* @see ssd1306_uartInit_Builtin()
* @see ssd1306_vga_controller_init()
*/
void vga_128x64_mono_init(void);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif
+134
View File
@@ -0,0 +1,134 @@
/*
MIT License
Copyright (c) 2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* @file nano_engine.h Small graphics engine, based on SSD1331 functions
*/
#ifndef _NANO_ENGINE_H_
#define _NANO_ENGINE_H_
#include "nano_engine/sprite.h"
#include "nano_engine/canvas.h"
#include "nano_engine/adafruit.h"
#include "nano_engine/tiler.h"
#include "nano_engine/core.h"
// DO NOT DECLARE NanoEngine8, NanoEngine16, NanoEngine1 as class NAME: public NanoEngine<T>
// This causes flash and RAM memory consumption in compiled ELF
/**
* @defgroup NANO_ENGINE_API NANO_ENGINE: Nano Engine description
* @{
* @brief Nano Engine description
*
* @details This group contains API functions for developing Graphics engines.
*/
/**
* NanoEngine1 is simple graphics engine, that implements double buffering work
* for the systems with very low resources. That is, memory buffer for SSD1306 oled
* display needs at least 128x64/8 bytes (1024 bytes), and this is inacceptable for
* microcontrollers like attiny85 (it has only 512B of RAM). So, to workaround
* issue with low resources, NanoEngine1 uses small tile buffer (NE_TILE_SIZE x NE_TILE_SIZE)
* and updates only part of oled screen at once. It makes system slow, but it is
* possible to run NanoEngine1 on simple controllers.
* If tile size is 32x32, then 128x64 oled display is devided into 8 tiles: <br>
* [0,0] [1,0] [2,0], [3,0] <br>
* [0,1] [1,1] [2,1], [3,1] <br>
* In your application you can choose, if you want to refresh whole screen (refresh()), or you
* need to refresh only part of oled display.
*
* @warning Works only in SSD1306 compatible mode
*/
#define NanoEngine1 NanoEngine<TILE_16x16_MONO>
#ifndef DOXYGEN_SHOULD_SKIP_THIS
#define NanoEngineArduboy NanoEngine<TILE_8x8_MONO>
#endif
/**
* NanoEngine8 is simple graphics engine, that implements double buffering work
* for the systems with very low resources. That is, memory buffer for SSD1331 oled
* display needs at least 96x64x1 bytes (6144 bytes), and this is inacceptable for
* microcontrollers like atmega328p (it has only 2KiB of RAM). So, to workaround
* issue with low resources, NanoEngine8 uses small tile buffer (NE_TILE_SIZE x NE_TILE_SIZE)
* and updates only part of oled screen at once. It makes system slow, but it is
* possible to run NanoEngine8 on simple controllers.
* If tile size is 32x32, then 96x64 oled display is devided into 6 tiles: <br>
* [0,0] [1,0] [2,0] <br>
* [0,1] [1,1] [2,1] <br>
* In your application you can choose, if you want to refresh whole screen (refresh()), or you
* need to refresh only part of oled display.
*/
#define NanoEngine8 NanoEngine<TILE_16x16_RGB8>
/**
* NanoEngine1 is simple graphics engine, that implements double buffering work
* for the systems with very low resources. That is, memory buffer for SSD1306 oled
* display needs at least 128x64/8 bytes (1024 bytes), and this is inacceptable for
* microcontrollers like attiny85 (it has only 512B of RAM). So, to workaround
* issue with low resources, NanoEngine1 uses small tile buffer (NE_TILE_SIZE x NE_TILE_SIZE)
* and updates only part of oled screen at once. It makes system slow, but it is
* possible to run NanoEngine1 on simple controllers.
* If tile size is 32x32, then 128x64 oled display is devided into 8 tiles: <br>
* [0,0] [1,0] [2,0], [3,0] <br>
* [0,1] [1,1] [2,1], [3,1] <br>
* In your application you can choose, if you want to refresh whole screen (refresh()), or you
* need to refresh only part of oled display.
*
* @warning Works only in RGB 8-bit color mode
*/
class NanoEngine1_8: public NanoEngine<TILE_8x8_MONO_8>
{
public:
/**
* Creates new Graphics Engine object.
*/
NanoEngine1_8(): NanoEngine() {};
};
/**
* NanoEngine16 is simple graphics engine, that implements double buffering work
* for the systems with very low resources. That is, memory buffer for SSD1351 oled
* display needs at least 128x128x2 bytes (32768 bytes), and this is inacceptable for
* microcontrollers like atmega328p (it has only 2KiB of RAM). So, to workaround
* issue with low resources, NanoEngine16 uses small tile buffer (NE_TILE_SIZE x NE_TILE_SIZE)
* and updates only part of oled screen at once. It makes system slow, but it is
* possible to run NanoEngine16 on simple controllers.
* If tile size is 16x16, then 128x128 oled display is devided into 64 tiles: <br>
* [0,0] [1,0] [2,0] [3,0] [4,0] [5,0] [6,0] [7,0] <br>
* [0,1] [1,1] [2,1] [3,1] [4,1] [5,1] [6,1] [7,1] <br>
* etc. <br>
* In your application you can choose, if you want to refresh whole screen (refresh()), or you
* need to refresh only part of oled display.
*/
#define NanoEngine16 NanoEngine<TILE_8x8_RGB16>
/**
* @}
*/
#endif
+299
View File
@@ -0,0 +1,299 @@
# Using NanoEngine for systems with low resources
***
[tocstart]: # (toc start)
* [Introduction](#introduction)
* [Main idea of NanoEngine](#main-idea-of-nanoengine)
* [Simple NanoEngine demo](#simple-nanoengine-demo)
* [Reading keys with NanoEngine](#reading-keys-with-nanoengine)
* [Draw monochrome bitmap](#draw-monochrome-bitmap)
* [Draw moving bitmap](#draw-moving-bitmap)
* [What if not to use draw callbacks](#what-if-not-to-use-draw-callbacks)
* [Using Adafruit GFX with NanoEngine](#using-adafruit-gfx-with-nanoengine)
* [To upper level](@ref index)
[tocend]: # (toc end)
<a name="introduction"></a>
## Introduction
Many applications use double-buffered output to physical display to avoid flickering effect, when a user observed non-completed picture for a short time. When working with color OLED/LCD displays like ssd1331, some micro-controllers do not have enough RAM to fit display buffer in. For example, in 8-bit mode ssd1331 OLED display needs 6144 bytes (`96*64`). But simple micro-controller like Atmega328 has only 2KiB, and Attiny85 has only 512B of RAM. But with ssd1306 library you still can create applications for those ones with good graphics.
ssd1306 library represents NanoEngine8, intended to be used with color OLED displays. Digit 8 means that engine implements 8-bit color mode. Refer to arkanoid8 as example, which can be run even on small Attiny85 with color ssd1331 display. The system supports NanoEngine1 for monochrome OLED displays, NanoEngine8 for 8-bit RGB OLED displays, NanoEngine16 for 16-bit RGB OLED displays.
<a name="main-idea-of-nanoengine"></a>
## Main idea of NanoEngine
There are 2 issues with tiny controllers:
* they have a little RAM
* they support low frequencies
The first problem is solved in NanoEngine by using double-buffer to redraw only part of display content at once. By default NanoEngine uses 8x8 small buffer (64 bytes) and 24 bytes to store information on areas, which need to be refreshed.
The second problem is solved almost the same way: refresh only those part of display content, which were changed since last frame update. For example, ssd1331 oled display work on SPI at 8MHz frequency, that means in ideal conditions the screen content can be refreshed 162 times per second (`8000000/(96*64*8)`). But with the data, you need to send also commands to the display and to do some other stuff. And real tests with Atmega328p show that `ssd1306_clearScreen()` can run only at 58 FPS, coping data from buffer to OLED memory runs slower.
There is no such issue for Arduboy, since it uses monochrome OLED ssd1306 with only 1KiB of RAM buffer, and theoretical fps can be up to 976. For color display and small controllers the main solution is to refresh only part of display content. Arkanoid8 can give easily 60 fps with NanoEngine8
<a name="simple-nanoengine-demo"></a>
## Simple NanoEngine demo
```cpp
#include "ssd1306.h"
#include "nano_engine.h"
NanoEngine8 engine;
bool drawAll()
{
engine.canvas.clear();
engine.canvas.setColor(RGB_COLOR8(255,255,0));
engine.canvas.drawRect(15,12,70,55);
return true; // if to return false, the engine will skip this part of screen update
}
void setup()
{
/* Init SPI 96x64 RBG oled. 3 - RESET, 4 - CS (can be omitted, oled CS must be pulled down), 5 - D/C */
ssd1331_96x64_spi_init(3, 4, 5);
engine.begin();
engine.setFrameRate(30);
/* Set callback to draw parts, when NanoEngine8 asks */
engine.drawCallback( drawAll );
}
void loop()
{
if (!engine.nextFrame()) return;
engine.refresh(); // Makes engine to refresh whole display content
engine.display();
}
```
<a name="reading-keys-with-nanoengine"></a>
## Reading keys with NanoEngine
What, if we want to move yellow rectangle. There is easy way to do this with NanoEngine8. The engine supports up-to 6 keys: `BUTTON_DOWN`, `BUTTON_LEFT`, `BUTTON_RIGHT`, `BUTTON_UP`, `BUTTON_A`, `BUTTON_B`. All you need is to say the engine how it can get buttons state on your board. There are already 2 built-in implementations: `connectArduboyKeys()` allows using Arduboy platform hardware (remember that you need to replace ssd1306 oled with color ssd1331 oled), and `connectZKeypad()` allows using standard 5-keys Z-keypad (you can find it on E-bay). Or you can set custom key processing handler via `connectCustomKeys()` and implement your own hardware driver.
Example of using Z-keypad to move rectangle.
```cpp
#include "ssd1306.h"
#include "nano_engine.h"
NanoEngine8 engine;
NanoRect rect = { {15,12}, {60,35} }; // Lets make rect smaller than in previous example
bool drawAll()
{
engine.canvas.clear();
engine.canvas.setColor(RGB_COLOR8(255,255,0));
engine.canvas.drawRect(rect); // draw rect in buffer
return true;
}
void setup()
{
/* Init SPI 96x64 RBG oled. 3 - RESET, 4 - CS (can be omitted, oled CS must be pulled down), 5 - D/C */
ssd1331_96x64_spi_init(3, 4, 5);
engine.begin();
engine.setFrameRate(30);
engine.drawCallback( drawAll ); // Set callback to draw parts, when NanoEngine8 asks
engine.connectZKeypad(0); // Connect ADC-buttons Z-keypad to analog A0 pin
engine.refresh(); // Makes engine to refresh whole display content at start-up
}
void loop()
{
if (!engine.nextFrame()) return;
NanoPoint point = {0,0};
if (engine.pressed( BUTTON_RIGHT )) point.x = +1;
if (engine.pressed( BUTTON_LEFT )) point.x = -1;
if (engine.pressed( BUTTON_UP )) point.y = -1;
if (engine.pressed( BUTTON_DOWN )) point.y = +1;
engine.refresh(rect); // Update screen content at old rect position
rect += point; // Move rect according to pressed keys
engine.refresh(rect); // Update screen content at new rect position
engine.display(); // refresh display content
}
```
<a name="draw-monochrome-bitmap"></a>
## Draw monochrome bitmap
```cpp
#include "ssd1306.h"
#include "nano_engine.h"
NanoEngine8 engine;
const uint8_t heartSprite[8] PROGMEM =
{
0B00001110,
0B00011111,
0B00111111,
0B01111110,
0B01111110,
0B00111101,
0B00011001,
0B00001110
};
bool drawAll()
{
engine.canvas.clear();
engine.canvas.setMode(0); // We want to draw non-transparent bitmap
engine.canvas.setColor(RGB_COLOR8(255,0,0)); // draw with red color
engine.canvas.drawBitmap1(10, 20, 8, 8, heartSprite);
return true;
}
void setup()
{
/* Init SPI 96x64 RBG oled. 3 - RESET, 4 - CS (can be omitted, oled CS must be pulled down), 5 - D/C */
ssd1331_96x64_spi_init(3, 4, 5);
engine.begin();
engine.drawCallback( drawAll ); // Set callback to draw parts, when NanoEngine8 asks
engine.refresh(); // Makes engine to refresh whole display content at start-up
}
void loop()
{
if (!engine.nextFrame()) return;
engine.display(); // refresh display content
}
```
<a name="draw-moving-bitmap"></a>
## Draw moving bitmap
In some applications like games, there is need to move bitmaps. It is easy to do this with ssd1306 library using NanoSprite objects. NanoSprite object is responsible for refreshing areas, touched by sprite. So, you need only to move sprite, where you want, the engine will take care of updating display content.
```cpp
#include "ssd1306.h"
#include "nano_engine.h"
const uint8_t heartSprite[8] PROGMEM =
{
0B00001110,
0B00011111,
0B00111111,
0B01111110,
0B01111110,
0B00111101,
0B00011001,
0B00001110
};
NanoEngine8 engine;
NanoSprite<NanoEngine8, engine> sprite( {0, 0}, {8, 8}, heartSprite );
bool drawAll()
{
engine.canvas.clear();
engine.canvas.setMode(0); // We want to draw non-transparent bitmap
engine.canvas.setColor(RGB_COLOR8(255,0,0)); // draw with red color
sprite.draw();
return true;
}
void setup()
{
/* Init SPI 96x64 RBG oled. 3 - RESET, 4 - CS (can be omitted, oled CS must be pulled down), 5 - D/C */
ssd1331_96x64_spi_init(3, 4, 5);
engine.begin();
engine.drawCallback( drawAll ); // Set callback to draw parts, when NanoEngine8 asks
engine.refresh(); // Makes engine to refresh whole display content at start-up
}
void loop()
{
if (!engine.nextFrame()) return;
// You will see horizontal flying heart
sprite.moveBy( { 1, 0 } );
engine.display(); // refresh display content
}
```
<a name="what-if-not-to-use-draw-callbacks"></a>
## What if not to use draw callbacks
If you don't want to use draw callbacks in your application, but still need a power of NanoEngine, then there is one way for you: to use full-screen double-buffering with NanoEngine. The example, you will find below, shows how to use full-screen double buffering for monochrome 128x64 ssd1306 oled display. This example can be run on Atmega328p and more powerful micro controllers. It clears back-buffer every time engine says to redraw the frame. But you can preserve previously prepared image by removing call to `engine.canvas.clear()`.
```cpp
#include "ssd1306.h"
#include "nano_engine.h"
NanoEngine<BUFFER_128x64_MONO> engine;
void setup()
{
// Init SPI 128x64 monochrome oled.
// 3 - RESET, 4 - CS (can be omitted, oled CS must be pulled down), 5 - D/C
ssd1306_128x64_spi_init(3, 4, 5);
engine.begin();
engine.setFrameRate(30);
}
void loop()
{
if (!engine.nextFrame()) return;
engine.canvas.clear(); // This step can be removed, if you don't want to clear buffer
engine.canvas.drawRect(15,12,70,55);
engine.display();
}
```
<a name="using-adafruit-gfx-with-nanoengine"></a>
## Using Adafruit GFX with NanoEngine
Many developers are familiar with nice AdafruitGFX library. It provides rich set of graphics functions. Starting with 1.7.0 ssd1306 library it is possible to use AdafruiGFX api in combination with NanoEngine. And it is really easy.
You need to remember only, that AdafruitGFX uses different approach, when working with rectangles and monochrome images. NanoCanvas expects monochrome bitmaps in native ssd1306 format, while Adafruit uses more native format for human. If you compare an example below with examples above you will understand, what's the difference (heartImage). Refer to AdafruitGFX documentation.
```cpp
// Define this before including library header, this will give Adafruit GFX support
// !!! Don't forget to install AdafruitGFX library to your Arduino IDE !!!
#define CONFIG_ADAFRUIT_GFX_ENABLE
#include "ssd1306.h"
#include "nano_engine.h"
// Now you can use AdafruitGFX by referencing engine.canvas
NanoEngine<ADATILE_8x8_RGB8> engine;
const PROGMEM uint8_t heartImage[8] =
{
0B01100110,
0B11111001,
0B11111101,
0B11111111,
0B01111110,
0B00111100,
0B00011000,
0B00000000
};
bool drawAll()
{
engine.canvas.fillScreen( 0 );
engine.canvas.drawBitmap(10, 20, heartSprite, 8, 8, RGB_COLOR8(255,0,0)); // draw bitmap with red color
return true;
}
void setup()
{
/* Init SPI 96x64 RBG oled. 3 - RESET, 4 - CS (can be omitted, oled CS must be pulled down), 5 - D/C */
ssd1331_96x64_spi_init(3, 4, 5);
engine.begin();
engine.drawCallback( drawAll ); // Set callback to draw parts, when NanoEngine8 asks
engine.refresh(); // Makes engine to refresh whole display content at start-up
}
void loop()
{
if (!engine.nextFrame()) return;
engine.display(); // refresh display content
}
```
+335
View File
@@ -0,0 +1,335 @@
/*
MIT License
Copyright (c) 2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* @file adafruit.h Adafruit related canvas implementation
*
* @brief Canvas implementation, based on Adafruit GFX.
*
* @details If you like canvas implementation by Adafruit, you can easily use it with
* ssd1306 library, including NanoEngine support. You will be able to use
* all features of AdafruitGFX, and output result to any OLED display, supported
* by ssd1306 library. If you want to use this feature, define CONFIG_ADAFRUIT_GFX_ENABLE
* in the beginning of your sketch, and include "nano_engine.h" header.
*/
#ifndef _SSD1306_ADAFRUIT_H_
#define _SSD1306_ADAFRUIT_H_
#include "ssd1306_hal/io.h"
#if defined(CONFIG_ADAFRUIT_GFX_ENABLE)
#include "ssd1306.h"
#include "ssd1306_hal/Print_internal.h"
#include "nano_gfx_types.h"
#ifndef DOXYGEN_SHOULD_SKIP_THIS
/* This is special case for non-Arduino platforms, since Adafruit requires *
* Arduino libraries support */
#ifndef ARDUINO
#define ARDUINO 100
#include "Adafruit_GFX.h"
#undef ARDUINO
#else
#include "Adafruit_GFX.h"
#endif
#endif // DOXYGEN_SHOULD_SKIP_THIS
/**
* @ingroup NANO_ENGINE_API
* @{
*/
/**
* This is basic template class for all canvas classes,
* based on Adafruit_GFX. This base class provides functionality
* compatible with native NanoCanvas implementation of ssd1306
* library
*/
template <uint8_t BPP>
class AdafruitCanvasOps: public Adafruit_GFX
{
public:
/** Fixed offset for all operation of NanoCanvasOps in pixels. */
NanoPoint offset;
/** number of bits per single pixel in buffer */
static const uint8_t BITS_PER_PIXEL = BPP;
/**
* Initializes canvas, based on Adafruit GFX.
* @param w width of canvas
* @param h height of canvas area
* @param buffer buffer to use for pixels
*
* @note the size of buffer must be enough to store (w*h*bpp/8) bytes.
*/
AdafruitCanvasOps(lcduint_t w, lcduint_t h, uint8_t *buffer)
: Adafruit_GFX(w, h)
, offset{0}
, m_buffer(buffer)
{
}
/**
* draw single pixel in canvas area
*
* @param x x position
* @param y y position
* @param color color of pixel: for monochrome it can be 0 (black),
* 1 (white), 2 (invert)
*/
void drawPixel(int16_t x, int16_t y, uint16_t color) override;
/**
* Sets offset
* @param ox - X offset in pixels
* @param oy - Y offset in pixels
*/
void setOffset(lcdint_t ox, lcdint_t oy) { offset.x = ox; offset.y = oy; };
#ifndef DOXYGEN_SHOULD_SKIP_THIS
// We need to override Adafruit GFX implementation of fillScreen, because
// NanoEngine uses offsets, when refreshing screen content.
void fillScreen(uint16_t color) override
{
fillRect(offset.x, offset.y, _width, _height, color);
}
#endif
protected:
/** pixels buffer */
uint8_t *m_buffer;
private:
inline void rotatePosition(int16_t &x, int16_t &y)
{
switch (getRotation()) {
case 1:
ssd1306_swap_data(x, y, int16_t);
x = WIDTH - x - 1;
break;
case 2:
x = WIDTH - x - 1;
y = HEIGHT - y - 1;
break;
case 3:
ssd1306_swap_data(x, y, int16_t);
y = HEIGHT - y - 1;
break;
}
}
};
/**
* Base class for all AdafruitCanvas childs
*/
template <uint8_t BPP>
class AdafruitCanvasBase: public AdafruitCanvasOps<BPP>
{
public:
using AdafruitCanvasOps<BPP>::AdafruitCanvasOps;
/**
* Draws canvas on the LCD display
* @param x - horizontal position in pixels
* @param y - vertical position in blocks (pixels/8)
*/
virtual void blt(lcdint_t x, lcdint_t y) = 0;
/**
* Draws canvas on the LCD display using offset values.
*/
virtual void blt() = 0;
};
/////////////////////////////////////////////////////////////////////////////////
//
// 1-BIT GRAPHICS
//
/////////////////////////////////////////////////////////////////////////////////
/**
* AdafruitCanvas1 represents objects for drawing in memory buffer
* AdafruitCanvas1 represents each pixel as single bit: 0/1
* For details refer to SSD1306 datasheet
*/
class AdafruitCanvas1 : public AdafruitCanvasBase<1>
{
public:
using AdafruitCanvasBase::AdafruitCanvasBase;
/**
* Draws canvas on the LCD display
* @param x - horizontal position in pixels
* @param y - vertical position in pixels
*/
void blt(lcdint_t x, lcdint_t y) override
{
ssd1306_drawBufferFast(x, y, WIDTH, HEIGHT, m_buffer);
}
/**
* Draws canvas on the LCD display using offset values.
*/
void blt() override
{
ssd1306_drawBufferFast(offset.x, offset.y, WIDTH, HEIGHT, m_buffer);
}
};
#ifndef DOXYGEN_SHOULD_SKIP_THIS
template <>
void AdafruitCanvasOps<1>::drawPixel(int16_t x, int16_t y, uint16_t color)
{
x -= offset.x;
y -= offset.y;
if ((x < 0) || (x >= width()) || (y < 0) || (y >= height()))
{
return;
}
rotatePosition(x, y);
switch (color)
{
case 1: m_buffer[x+ (y/8)*WIDTH] |= (1 << (y&7)); break;
case 0: m_buffer[x+ (y/8)*WIDTH] &= ~(1 << (y&7)); break;
case 2: m_buffer[x+ (y/8)*WIDTH] ^= (1 << (y&7)); break;
}
}
#endif // DOXYGEN_SHOULD_SKIP_THIS
/////////////////////////////////////////////////////////////////////////////////
//
// 8-BIT GRAPHICS
//
/////////////////////////////////////////////////////////////////////////////////
/**
* AdafruitCanvas8 represents objects for drawing in memory buffer
* AdafruitCanvas8 represents each pixel as single byte with RGB bits: RRRGGGBB
* For details refer to SSD1331 datasheet.
*/
class AdafruitCanvas8 : public AdafruitCanvasBase<8>
{
public:
using AdafruitCanvasBase::AdafruitCanvasBase;
/**
* Draws canvas on the LCD display
* @param x - horizontal position in pixels
* @param y - vertical position in pixels
*/
void blt(lcdint_t x, lcdint_t y) override
{
ssd1306_drawBufferFast8(x, y, WIDTH, HEIGHT, m_buffer);
}
/**
* Draws canvas on the LCD display using offset values.
*/
void blt() override
{
ssd1306_drawBufferFast8(offset.x, offset.y, WIDTH, HEIGHT, m_buffer);
}
};
#ifndef DOXYGEN_SHOULD_SKIP_THIS
template <>
void AdafruitCanvasOps<8>::drawPixel(int16_t x, int16_t y, uint16_t color)
{
x -= offset.x;
y -= offset.y;
if ((x < 0) || (x >= width()) || (y < 0) || (y >= height()))
{
return;
}
rotatePosition(x, y);
m_buffer[x+y*WIDTH] = color;
}
#endif // DOXYGEN_SHOULD_SKIP_THIS
/////////////////////////////////////////////////////////////////////////////////
//
// 16-BIT GRAPHICS
//
/////////////////////////////////////////////////////////////////////////////////
/**
* AdafruitCanvas16 represents objects for drawing in memory buffer
* AdafruitCanvas16 represents each pixel as two bytes with RGB bits:
* RRRRRGGG GGGBBBBB.
* For details refer to SSD1351 datasheet.
*/
class AdafruitCanvas16 : public AdafruitCanvasBase<16>
{
public:
using AdafruitCanvasBase::AdafruitCanvasBase;
/**
* Draws canvas on the LCD display
* @param x - horizontal position in pixels
* @param y - vertical position in pixels
*/
void blt(lcdint_t x, lcdint_t y) override
{
ssd1306_drawBufferFast16(x, y, WIDTH, HEIGHT, m_buffer);
}
/**
* Draws canvas on the LCD display using offset values.
*/
void blt() override
{
ssd1306_drawBufferFast16(offset.x, offset.y, WIDTH, HEIGHT, m_buffer);
}
};
#ifndef DOXYGEN_SHOULD_SKIP_THIS
template <>
void AdafruitCanvasOps<16>::drawPixel(int16_t x, int16_t y, uint16_t color)
{
x -= offset.x;
y -= offset.y;
if ((x < 0) || (x >= width()) || (y < 0) || (y >= height()))
{
return;
}
rotatePosition(x, y);
m_buffer[(x+y*WIDTH) * 2 + 0] = color;
m_buffer[(x+y*WIDTH) * 2 + 1] = color >> 8;
}
#endif // DOXYGEN_SHOULD_SKIP_THIS
/**
* @}
*/
#endif // CONFIG_ADAFRUIT_GFX_ENABLE
#endif
File diff suppressed because it is too large Load Diff
+613
View File
@@ -0,0 +1,613 @@
/*
MIT License
Copyright (c) 2018-2019, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* @file canvas.h Drawing in memory buffer
*/
#ifndef _NANO_CANVAS_H_
#define _NANO_CANVAS_H_
#include "point.h"
#include "rect.h"
#include "ssd1306_hal/io.h"
#include "ssd1306_hal/Print_internal.h"
#include "nano_gfx_types.h"
/**
* @ingroup NANO_ENGINE_API
* @{
*/
enum
{
CANVAS_MODE_BASIC = 0x00,
/** If the flag is specified, text cursor is moved to new line when end of screen is reached */
CANVAS_TEXT_WRAP = 0x01,
/** This flag make bitmaps transparent (Black color) */
CANVAS_MODE_TRANSPARENT = 0x02,
/** If the flag is specified, text cursor is moved to new line when end of canvas is reached */
CANVAS_TEXT_WRAP_LOCAL = 0x04,
};
/**
* NanoCanvasOps provides operations for drawing in memory buffer.
* Depending on BPP argument, this class can work with 1,8,16-bit canvas areas.
*/
template <uint8_t BPP>
class NanoCanvasOps: public Print
{
public:
/** number of bits per single pixel in buffer */
static const uint8_t BITS_PER_PIXEL = BPP;
/** Fixed offset for all operation of NanoCanvasOps in pixels */
NanoPoint offset = { 0, 0 };
/**
* Creates new empty canvas object.
* If you this constructor is used, you must call begin() method before
* working with canvas.
*/
NanoCanvasOps()
{
}
/**
* Creates new canvas object.
* Width can be of any value.
* Height should be divided by 8.
* Memory buffer must be not less than w * h.
*
* @param w - width
* @param h - height
* @param bytes - pointer to memory buffer to use
*/
NanoCanvasOps(lcdint_t w, lcdint_t h, uint8_t *bytes)
{
begin(w, h, bytes);
}
/**
* Initializes canvas object.
* Width can be of any value.
* Height should be divided by 8.
* Memory buffer must be not less than w * h.
*
* @param w - width
* @param h - height
* @param bytes - pointer to memory buffer to use
*/
void begin(lcdint_t w, lcdint_t h, uint8_t *bytes);
/**
* Sets offset
* @param ox - X offset in pixels
* @param oy - Y offset in pixels
*/
void setOffset(lcdint_t ox, lcdint_t oy) { offset.x = ox; offset.y = oy; };
/**
* Returns right-bottom point of the canvas in offset terms.
* If offset is (0,0), then offsetEnd() will return (width-1,height-1).
*/
const NanoPoint offsetEnd() const
{
return offset + (NanoPoint){ (lcdint_t)(m_w-1), (lcdint_t)(m_h-1) };
}
/**
* Returns rectangle area, covered by canvas in offset terms.
* If offset is (0,0), then rect() will return ((0,0),(width-1,height-1))
*/
const NanoRect rect() const
{
return { offset, offsetEnd() };
}
/**
* Draws pixel on specified position
* @param x - position X
* @param y - position Y
* @note color can be set via setColor()
*/
void putPixel(lcdint_t x, lcdint_t y);
/**
* Draws pixel on specified position
* @param p - NanoPoint
* @note color can be set via setColor()
*/
void putPixel(const NanoPoint &p);
/**
* Draws horizontal or vertical line
* @param x1 - position X
* @param y1 - position Y
* @param y2 - position Y
* @note color can be set via setColor()
*/
void drawVLine(lcdint_t x1, lcdint_t y1, lcdint_t y2);
/**
* Draws horizontal or vertical line
* @param x1 - position X
* @param y1 - position Y
* @param x2 - position X
* @note color can be set via setColor()
*/
void drawHLine(lcdint_t x1, lcdint_t y1, lcdint_t x2);
/**
* Draws line
* @param x1 - position X
* @param y1 - position Y
* @param x2 - position X
* @param y2 - position Y
* @note color can be set via setColor()
*/
void drawLine(lcdint_t x1, lcdint_t y1, lcdint_t x2, lcdint_t y2);
/**
* Draws line
* @param rect - structure, describing rectangle area
* @note color can be set via setColor()
*/
void drawLine(const NanoRect &rect);
/**
* Draws rectangle
* @param x1 - position X
* @param y1 - position Y
* @param x2 - position X
* @param y2 - position Y
* @note color can be set via setColor()
*/
void drawRect(lcdint_t x1, lcdint_t y1, lcdint_t x2, lcdint_t y2);
/**
* Draws rectangle
* @param rect - structure, describing rectangle area
* @note color can be set via setColor()
*/
void drawRect(const NanoRect &rect);
/**
* Fills rectangle area
* @param x1 - position X
* @param y1 - position Y
* @param x2 - position X
* @param y2 - position Y
* @note color can be set via setColor()
*/
void fillRect(lcdint_t x1, lcdint_t y1, lcdint_t x2, lcdint_t y2);
/**
* Fills rectangle area
* @param rect - structure, describing rectangle area
* @note color can be set via setColor()
*/
void fillRect(const NanoRect &rect);
/**
* @brief Draws monochrome bitmap in color buffer using color, specified via setColor() method
* Draws monochrome bitmap in color buffer using color, specified via setColor() method
* The bitmap is expected in Native ssd1306 controller format.
*
* @param x - position X in pixels
* @param y - position Y in pixels
* @param w - width in pixels
* @param h - height in pixels
* @param bitmap - monochrome bitmap data, located in flash
*
* @note There are 2 modes: transparent and non-transparent mode, - and 2 colors available: black and white.
* In non-transparent mode, when black color is selected, the monochrome image just inverted.
* In transparent mode, those pixels of source monochrome image, which are black, do not overwrite pixels
* in the screen buffer.
*/
void drawBitmap1(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *bitmap);
/**
* @brief Draws monochrome bitmap in color buffer using color, specified via setColor() method
* Draws monochrome bitmap in color buffer using color, specified via setColor() method
* The bitmap is expected in XBMP format.
*
* @param x - position X in pixels
* @param y - position Y in pixels
* @param w - width in pixels
* @param h - height in pixels
* @param bitmap - monochrome bitmap data, located in flash
*
* @note There are 2 modes: transparent and non-transparent mode, - and 2 colors available: black and white.
* In non-transparent mode, when black color is selected, the monochrome image just inverted.
* In transparent mode, those pixels of source monochrome image, which are black, do not overwrite pixels
* in the screen buffer.
*/
void drawXBitmap1(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *bitmap);
/**
* @brief Draws 8-bit color bitmap in color buffer.
* Draws 8-bit color bitmap in color buffer.
* @param x - position X in pixels
* @param y - position Y in pixels
* @param w - width in pixels
* @param h - height in pixels
* @param bitmap - 8-bit color bitmap data, located in flash
*/
void drawBitmap8(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *bitmap);
/**
* Clears canvas
*/
void clear();
/**
* Writes single character to canvas
* @param c - character code to print
*/
size_t write(uint8_t c) override;
/**
* Draws single character to canvas
* @param c - character code to print
* @returns 0 if char is not printed
*/
uint8_t printChar(uint8_t c);
/**
* Print text at specified position to canvas
*
* @param xpos position in pixels
* @param y position in pixels
* @param ch pointer to NULL-terminated string.
* @param style specific font style to use
*
* @note Supports only STYLE_NORMAL and STYLE_BOLD
*/
void printFixed(lcdint_t xpos, lcdint_t y, const char *ch, EFontStyle style = STYLE_NORMAL);
/**
* Print text at specified position to canvas
*
* @param xpos position in pixels
* @param y position in pixels
* @param ch pointer to NULL-terminated string, located in flash
* @param style specific font style to use
*
* @note Supports only STYLE_NORMAL and STYLE_BOLD
*/
void printFixedPgm(lcdint_t xpos, lcdint_t y, const char *ch, EFontStyle style = STYLE_NORMAL);
/**
* @brief Sets canvas drawing mode
* Sets canvas drawing mode. The set flags define transparency of output images
* @param modeFlags - combination of flags: CANVAS_TEXT_WRAP, CANVAS_MODE_TRANSPARENT
*/
void setMode(uint8_t modeFlags) { m_textMode = modeFlags; };
/**
* Sets color for monochrome operations
* @param color - color to set (refer to RGB_COLOR8 definition)
*/
void setColor(uint16_t color) { m_color = color; };
protected:
lcduint_t m_w; ///< width of NanoCanvas area in pixels
lcduint_t m_h; ///< height of NanoCanvas area in pixels
lcduint_t m_p; ///< number of bits, used by width value: 3 equals to 8 pixels width
lcdint_t m_cursorX; ///< current X cursor position for text output
lcdint_t m_cursorY; ///< current Y cursor position for text output
uint8_t m_textMode; ///< Flags for current NanoCanvas mode
EFontStyle m_fontStyle; ///< currently active font style
uint8_t * m_buf; ///< Canvas data
uint16_t m_color; ///< current color for monochrome operations
};
/**
* Base class for all NanoCanvas childs
*/
template <uint8_t BPP>
class NanoCanvasBase: public NanoCanvasOps<BPP>
{
public:
using NanoCanvasOps<BPP>::NanoCanvasOps;
/**
* Draws canvas on the LCD display
* @param x - horizontal position in pixels
* @param y - vertical position in blocks (pixels/8)
*/
virtual void blt(lcdint_t x, lcdint_t y) = 0;
/**
* Draws canvas on the LCD display using offset values.
*/
virtual void blt() = 0;
/**
* Draws only part of canvas on the LCD display.
* This method uses Canvas offset field as top-left point of whole canvas
* content. First point of specified rectangle defines the actual top-left
* point on the screen to be refreshed.
* For example, `blt({{8,0},{15,7}});` will copy canvas area {8,0}-{15,7}
* to screen starting at {8,0} if canvas offset is {0,0}.
* If canvas offset is {12,3}, then canvas area {8,0}-{15,7} will be copied
* to screen at position {20,3}.
* @param rect rectagle describing part of canvas to move to display.
*/
virtual void blt(const NanoRect &rect) = 0;
};
/////////////////////////////////////////////////////////////////////////////////
//
// 1-BIT GRAPHICS
//
/////////////////////////////////////////////////////////////////////////////////
enum
{
BLACK = 0x00, ///< Black color
WHITE = 0xFF, ///< White color
};
/**
* NanoCanvas1 represents objects for drawing in memory buffer
* NanoCanvas1 represents each pixel as single bit: 0/1
* For details refer to SSD1306 datasheet
*/
class NanoCanvas1: public NanoCanvasBase<1>
{
public:
using NanoCanvasBase::NanoCanvasBase;
/**
* Draws canvas on the LCD display
* @param x - horizontal position in pixels
* @param y - vertical position in pixels
*/
void blt(lcdint_t x, lcdint_t y) override;
/**
* Draws canvas on the LCD display using offset values.
*/
void blt() override;
/**
* Draws only part of canvas on the LCD display.
* This method uses Canvas offset field as top-left point of whole canvas
* content. First point of specified rectangle defines the actual top-left
* point on the screen to be refreshed.
* For example, `blt({{8,0},{15,7}});` will copy canvas area {8,0}-{15,7}
* to screen starting at {8,0} if canvas offset is {0,0}.
* If canvas offset is {12,3}, then canvas area {8,0}-{15,7} will be copied
* to screen at position {20,3}.
* @param rect rectagle describing part of canvas to move to display.
*/
void blt(const NanoRect &rect) override;
};
/**
* NanoCanvas1_8 represents objects for drawing in memory buffer
* NanoCanvas1_8 represents each pixel as single bit: 0/1
* Unlike NanoCanvas1, it works with RBG color displays in normal mode.
*/
class NanoCanvas1_8: public NanoCanvasBase<1>
{
public:
using NanoCanvasBase::NanoCanvasBase;
/**
* Draws canvas on the LCD display
* @param x - horizontal position in pixels
* @param y - vertical position in pixels
*/
void blt(lcdint_t x, lcdint_t y) override;
/**
* Draws canvas on the LCD display using offset values.
*/
void blt() override;
/**
* Draws only part of canvas on the LCD display.
* This method uses Canvas offset field as top-left point of whole canvas
* content. First point of specified rectangle defines the actual top-left
* point on the screen to be refreshed.
* For example, `blt({{8,0},{15,7}});` will copy canvas area {8,0}-{15,7}
* to screen starting at {8,0} if canvas offset is {0,0}.
* If canvas offset is {12,3}, then canvas area {8,0}-{15,7} will be copied
* to screen at position {20,3}.
* @param rect rectagle describing part of canvas to move to display.
*/
void blt(const NanoRect &rect) override;
};
/**
* NanoCanvas1_16 represents objects for drawing in memory buffer
* NanoCanvas1_16 represents each pixel as single bit: 0/1
* Unlike NanoCanvas1, it works with RBG color displays in normal mode.
*/
class NanoCanvas1_16: public NanoCanvasBase<1>
{
public:
using NanoCanvasBase::NanoCanvasBase;
/**
* Draws canvas on the LCD display
* @param x - horizontal position in pixels
* @param y - vertical position in pixels
*/
void blt(lcdint_t x, lcdint_t y) override;
/**
* Draws canvas on the LCD display using offset values.
*/
void blt() override;
/**
* Draws only part of canvas on the LCD display.
* This method uses Canvas offset field as top-left point of whole canvas
* content. First point of specified rectangle defines the actual top-left
* point on the screen to be refreshed.
* For example, `blt({{8,0},{15,7}});` will copy canvas area {8,0}-{15,7}
* to screen starting at {8,0} if canvas offset is {0,0}.
* If canvas offset is {12,3}, then canvas area {8,0}-{15,7} will be copied
* to screen at position {20,3}.
* @param rect rectagle describing part of canvas to move to display.
*/
void blt(const NanoRect &rect) override;
};
/////////////////////////////////////////////////////////////////////////////////
//
// 4-BIT GRAPHICS
//
/////////////////////////////////////////////////////////////////////////////////
/**
* NanoCanvas1_4 represents objects for drawing in memory buffer
* NanoCanvas1_4 represents each pixel as 4-bits in GRAYscale: 11112222
* For details refer to ssd1327/ssd1325 datasheet
*/
class NanoCanvas1_4: public NanoCanvasBase<4>
{
public:
using NanoCanvasBase::NanoCanvasBase;
/**
* Draws canvas on the LCD display
* @param x - horizontal position in pixels
* @param y - vertical position in pixels
*/
void blt(lcdint_t x, lcdint_t y) override;
/**
* Draws canvas on the LCD display using offset values.
*/
void blt() override;
/**
* Draws only part of canvas on the LCD display.
* This method uses Canvas offset field as top-left point of whole canvas
* content. First point of specified rectangle defines the actual top-left
* point on the screen to be refreshed.
* For example, `blt({{8,0},{15,7}});` will copy canvas area {8,0}-{15,7}
* to screen starting at {8,0} if canvas offset is {0,0}.
* If canvas offset is {12,3}, then canvas area {8,0}-{15,7} will be copied
* to screen at position {20,3}.
* @param rect rectagle describing part of canvas to move to display.
*/
void blt(const NanoRect &rect) override;
};
/////////////////////////////////////////////////////////////////////////////////
//
// 8-BIT GRAPHICS
//
/////////////////////////////////////////////////////////////////////////////////
/**
* NanoCanvas8 represents objects for drawing in memory buffer
* NanoCanvas8 represents each pixel as single byte with RGB bits: RRRGGGBB
* For details refer to SSD1331 datasheet
*/
class NanoCanvas8: public NanoCanvasBase<8>
{
public:
using NanoCanvasBase::NanoCanvasBase;
/**
* Draws canvas on the LCD display
* @param x - horizontal position in pixels
* @param y - vertical position in pixels
*/
void blt(lcdint_t x, lcdint_t y) override;
/**
* Draws canvas on the LCD display using offset values.
*/
void blt() override;
/**
* Draws only part of canvas on the LCD display.
* This method uses Canvas offset field as top-left point of whole canvas
* content. First point of specified rectangle defines the actual top-left
* point on the screen to be refreshed.
* For example, `blt({{8,0},{15,7}});` will copy canvas area {8,0}-{15,7}
* to screen starting at {8,0} if canvas offset is {0,0}.
* If canvas offset is {12,3}, then canvas area {8,0}-{15,7} will be copied
* to screen at position {20,3}.
* @param rect rectagle describing part of canvas to move to display.
*/
void blt(const NanoRect &rect) override;
};
/////////////////////////////////////////////////////////////////////////////////
//
// 16-BIT GRAPHICS
//
/////////////////////////////////////////////////////////////////////////////////
/**
* NanoCanvas16 represents objects for drawing in memory buffer
* NanoCanvas16 represents each pixel as 2-bytes with RGB bits: RRRRRGGG-GGGBBBBB
* For details refer to SSD1351 datasheet
*/
class NanoCanvas16: public NanoCanvasBase<16>
{
public:
using NanoCanvasBase::NanoCanvasBase;
/**
* Draws canvas on the LCD display
* @param x - horizontal position in pixels
* @param y - vertical position in pixels
*/
void blt(lcdint_t x, lcdint_t y) override;
/**
* Draws canvas on the LCD display using offset values.
*/
void blt() override;
/**
* Draws only part of canvas on the LCD display.
* This method uses Canvas offset field as top-left point of whole canvas
* content. First point of specified rectangle defines the actual top-left
* point on the screen to be refreshed.
* For example, `blt({{8,0},{15,7}});` will copy canvas area {8,0}-{15,7}
* to screen starting at {8,0} if canvas offset is {0,0}.
* If canvas offset is {12,3}, then canvas area {8,0}-{15,7} will be copied
* to screen at position {20,3}.
* @param rect rectagle describing part of canvas to move to display.
*/
void blt(const NanoRect &rect) override;
};
/**
* @}
*/
#endif
+193
View File
@@ -0,0 +1,193 @@
/*
MIT License
Copyright (c) 2018-2021, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "core.h"
#ifdef SDL_EMULATION
#include "sdl_core.h"
#endif
///////////////////////////////////////////////////////////////////////////////
////// NANO ENGINE INPUTS CLASS ///////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
/** Callback to call if buttons state needs to be updated */
TNanoEngineGetButtons NanoEngineInputs::m_onButtons = nullptr;
uint8_t NanoEngineInputs::s_ky40_clk;
uint8_t NanoEngineInputs::s_ky40_dt;
uint8_t NanoEngineInputs::s_ky40_sw;
bool NanoEngineInputs::pressed(uint8_t buttons)
{
return (m_onButtons() & buttons) == buttons;
}
bool NanoEngineInputs::notPressed(uint8_t buttons)
{
return (m_onButtons() & buttons) == 0;
}
void NanoEngineInputs::connectCustomKeys(TNanoEngineGetButtons handler)
{
m_onButtons = handler;
}
void NanoEngineInputs::connectArduboyKeys()
{
m_onButtons = arduboyButtons;
}
uint8_t NanoEngineInputs::s_zkeypadPin;
uint8_t NanoEngineInputs::zkeypadButtons()
{
int buttonValue = analogRead(s_zkeypadPin);
if (buttonValue < 100) return BUTTON_RIGHT;
if (buttonValue < 200) return BUTTON_UP;
if (buttonValue < 400) return BUTTON_DOWN;
if (buttonValue < 600) return BUTTON_LEFT;
if (buttonValue < 800) return BUTTON_A;
/** Z-keypad has only 5 analog buttons: no button B */
return BUTTON_NONE;
}
void NanoEngineInputs::connectZKeypad(uint8_t analogPin)
{
NanoEngineInputs::s_zkeypadPin = analogPin;
m_onButtons = zkeypadButtons;
}
uint8_t NanoEngineInputs::arduboyButtons()
{
uint8_t buttons;
/* Arduboy buttons available only for Atmega32U4 platform */
#if defined(__AVR_ATmega32U4__)
// down, up, left right
buttons = (((~PINF) & 0B11110000)>>4);
// A (left)
buttons |= (((~PINE) & 0B01000000) >> 2);
// B (right)
buttons |= (((~PINB) & 0B00010000) << 1);
#else
buttons = 0;
#endif
return buttons;
}
const uint8_t * NanoEngineInputs::s_gpioKeypadPins;
void NanoEngineInputs::connectGpioKeypad(const uint8_t * gpioKeys)
{
NanoEngineInputs::s_gpioKeypadPins = gpioKeys;
#ifdef SDL_EMULATION
sdl_set_gpio_keys(gpioKeys);
#endif
m_onButtons = gpioButtons;
}
uint8_t NanoEngineInputs::gpioButtons()
{
uint8_t buttons = BUTTON_NONE;
if ((s_gpioKeypadPins[0]) && (digitalRead(s_gpioKeypadPins[0]) == HIGH)) buttons |= BUTTON_DOWN;
if ((s_gpioKeypadPins[1]) && (digitalRead(s_gpioKeypadPins[1]) == HIGH)) buttons |= BUTTON_LEFT;
if ((s_gpioKeypadPins[2]) && (digitalRead(s_gpioKeypadPins[2]) == HIGH)) buttons |= BUTTON_RIGHT;
if ((s_gpioKeypadPins[3]) && (digitalRead(s_gpioKeypadPins[3]) == HIGH)) buttons |= BUTTON_UP;
if ((s_gpioKeypadPins[4]) && (digitalRead(s_gpioKeypadPins[4]) == HIGH)) buttons |= BUTTON_A;
if ((s_gpioKeypadPins[5]) && (digitalRead(s_gpioKeypadPins[5]) == HIGH)) buttons |= BUTTON_B;
return buttons;
}
void NanoEngineInputs::connectKY40encoder(uint8_t pina_clk, uint8_t pinb_dt, int8_t pinc_sw)
{
s_ky40_clk = pina_clk;
s_ky40_dt = pinb_dt;
s_ky40_sw = pinc_sw;
m_onButtons = ky40Buttons;
}
uint8_t NanoEngineInputs::ky40Buttons()
{
static uint8_t last_clk = digitalRead( s_ky40_clk );
uint8_t buttons = BUTTON_NONE;
uint8_t clk = digitalRead( s_ky40_clk );
if ( clk != last_clk )
{
if ( clk == HIGH )
{
buttons = digitalRead( s_ky40_dt ) == LOW ? BUTTON_DOWN : BUTTON_UP;
}
else
{
buttons = digitalRead( s_ky40_dt ) == HIGH ? BUTTON_DOWN : BUTTON_UP;
}
}
last_clk = clk;
if ( digitalRead( s_ky40_sw ) == LOW )
{
buttons |= BUTTON_A;
}
return buttons;
}
///////////////////////////////////////////////////////////////////////////////
////// NANO ENGINE CORE CLASS /////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
/** Defaut frame rate for all engines */
static const uint8_t ENGINE_DEFAULT_FPS = 30;
/** Duration between frames in milliseconds */
uint8_t NanoEngineCore::m_frameDurationMs = 1000/ENGINE_DEFAULT_FPS;
/** Current fps */
uint8_t NanoEngineCore::m_fps = ENGINE_DEFAULT_FPS;
/** Current cpu load in percents */
uint8_t NanoEngineCore::m_cpuLoad = 0;
/** Last timestamp in milliseconds the frame was updated on oled display */
uint32_t NanoEngineCore::m_lastFrameTs;
/** Callback to call before starting oled update */
TLoopCallback NanoEngineCore::m_loop = nullptr;
void NanoEngineCore::begin()
{
m_lastFrameTs = millis();
}
void NanoEngineCore::setFrameRate(uint8_t fps)
{
if ( fps > 0 )
{
m_fps = fps;
m_frameDurationMs = 1000/fps;
}
}
bool NanoEngineCore::nextFrame()
{
bool needUpdate = (uint32_t)(millis() - m_lastFrameTs) >= m_frameDurationMs;
if (needUpdate && m_loop) m_loop();
return needUpdate;
}
+301
View File
@@ -0,0 +1,301 @@
/*
MIT License
Copyright (c) 2018-2019, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* @file core.h Small graphics engine, based on SSD1331 functions
*/
#ifndef _NANO_ENGINE_CORE_H_
#define _NANO_ENGINE_CORE_H_
#include "tiler.h"
#include "canvas.h"
/**
* @ingroup NANO_ENGINE_API
* @{
*/
/** Type of user-specified keyboard callback */
typedef uint8_t (*TNanoEngineGetButtons)(void);
/** Type of user-specified loop callback */
typedef void (*TLoopCallback)(void);
///////////////////////////////////////////////////////////////////////////////
////// NANO ENGINE INPUTS CLASS ///////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
enum
{
BUTTON_NONE = 0B00000000,
BUTTON_DOWN = 0B00000001,
BUTTON_LEFT = 0B00000010,
BUTTON_RIGHT = 0B00000100,
BUTTON_UP = 0B00001000,
BUTTON_A = 0B00010000,
BUTTON_B = 0B00100000,
};
/**
* Class for keys processing functionality
*/
class NanoEngineInputs
{
protected:
/**
* Initializes Nano Engine Inputs object.
*/
NanoEngineInputs() {};
public:
/**
* @brief Returns true if button or specific combination of buttons is not pressed.
* Returns true if button or specific combination of buttons is pressed.
* @param buttons - buttons to check
* @return true or false
*/
static bool pressed(uint8_t buttons);
/**
* @brief Returns true if button or specific combination of buttons is not pressed.
* Returns true if button or specific combination of buttons is not pressed.
* @param buttons - buttons to check
* @return true of false
*/
static bool notPressed(uint8_t buttons);
/**
* @brief Returns bits of all pressed buttons
*
* Returns bits of all pressed buttons. For example, to check if Down button is pressed
* you need to write `if (result & BUTTON_DOWN) {}`. Available constants are:
* BUTTON_DOWN, BUTTON_LEFT, BUTTON_RIGHT, BUTTON_UP, BUTTON_A, BUTTON_B.
*
*/
static uint8_t buttonsState()
{
return m_onButtons();
}
/**
* Configures NanoEngine8 to use custom key handler.
* You can implement in your handler any keyboard layout, you use in your schematics.
*/
static void connectCustomKeys(TNanoEngineGetButtons handler);
/**
* @brief Enables engine to use Z-Keypad.
* Enables engine to use Z-Keypad. Please refer to arkanoid example for schematics.
* @param analogPin - pin, which Z-Keypad is connected to.
*/
static void connectZKeypad(uint8_t analogPin);
/**
* @brief Configures NanoEngine8 to use Arduboy keys layout.
* Configures NanoEngine8 to use Arduboy keys layout.
*/
static void connectArduboyKeys();
#ifndef DOXYGEN_SHOULD_SKIP_THIS
/**
* @brief Configures NanoEngine to use KY40 Rotary Encoder.
* Configures NanoEngine to use KY40 Rotary Encoder.
* @param pina_clk pin number to use as clk (see KY40 docs).
* @param pinb_dt pin number to use as direction pin (see KY40 docs).
* @param pinc_sw optional pin number ot use as push button.
* @warning do not use, not tested
*/
static void connectKY40encoder(uint8_t pina_clk, uint8_t pinb_dt, int8_t pinc_sw = -1);
#endif
/**
* @brief Enables engine to use GPIO keys
*
* Enables engine to use gpio-keys. You need to pass globally defined array,
* containing GPIO pin numbers for the 6 buttons in the following order:
* Down, Left, Right, Up, A, B. If you don't want to use some specific button,
* then just set not used button to 0.
* Once you call this function, you can read buttons state via buttonsState().
*
* @param gpioKeys pointer to 6-button pins array.
*
* @see buttonsState()
*/
static void connectGpioKeypad(const uint8_t *gpioKeys);
protected:
/** Callback to call if buttons state needs to be updated */
static TNanoEngineGetButtons m_onButtons;
private:
static uint8_t s_zkeypadPin;
static const uint8_t * s_gpioKeypadPins;
static uint8_t s_ky40_clk;
static uint8_t s_ky40_dt;
static uint8_t s_ky40_sw;
static uint8_t zkeypadButtons();
static uint8_t arduboyButtons();
static uint8_t gpioButtons();
static uint8_t ky40Buttons();
};
///////////////////////////////////////////////////////////////////////////////
////// NANO ENGINE CORE CLASS /////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
/**
* Nano Engine Core class, contains generic frame-rate control functions
*/
class NanoEngineCore: public NanoEngineInputs
{
protected:
NanoEngineCore(): NanoEngineInputs() {};
public:
/**
* Initializes internal timestamps.
*/
static void begin();
/**
* Sets working frame-rate for the engine
* @param fps - frame rate to set between [1-255]
*/
static void setFrameRate(uint8_t fps);
/**
* Returns current frame rate
*/
static uint8_t getFrameRate() { return m_fps; };
/**
* Returns cpu load in percents [0-255].
* 100 means maximum normal CPU load.
* 0 means, CPU has nothing to do.
* >100 means that CPU is not enough to perform all operations
*/
static uint8_t getCpuLoad() { return m_cpuLoad; };
/**
* Returns true if it is time to render next frame
*/
static bool nextFrame();
/**
* Sets user-defined loop callback. This callback will be called once every time
* new frame needs to be refreshed on oled display.
*/
static void loopCallback(TLoopCallback callback) { m_loop = callback; };
protected:
/** Duration between frames in milliseconds */
static uint8_t m_frameDurationMs;
/** Current fps */
static uint8_t m_fps;
/** Current cpu load in percents */
static uint8_t m_cpuLoad;
/** Last timestamp in milliseconds the frame was updated on oled display */
static uint32_t m_lastFrameTs;
/** Callback to call before starting oled update */
static TLoopCallback m_loop;
};
/**
* Base class for NanoEngine.
*/
template<class C, uint8_t W, uint8_t H, uint8_t B>
class NanoEngine: public NanoEngineCore,
public NanoEngineTiler<C,W,H,B>
{
public:
/**
* Initializes Nano Engine Base object.
*/
NanoEngine();
/**
* @brief refreshes content on oled display.
* Refreshes content on oled display. Call it, if you want to update the screen.
* Engine will update only those areas, which are marked by refresh()
* methods.
*/
static void display();
/**
* Initializes internal timestamps, engine state, and
* switches oled display to required mode (see ssd1306_setMode()).
*/
static void begin();
/**
* @brief shows notification to a user for 1 seconds
* Shows notification to a user for 1 seconds
* @param str - pointer to null-terminated string to show
*/
static void notify(const char *str);
protected:
};
template<class C, uint8_t W, uint8_t H, uint8_t B>
NanoEngine<C,W,H,B>::NanoEngine()
: NanoEngineCore(), NanoEngineTiler<C,W,H,B>()
{
}
template<class C, uint8_t W, uint8_t H, uint8_t B>
void NanoEngine<C,W,H,B>::display()
{
m_lastFrameTs = millis();
NanoEngineTiler<C,W,H,B>::displayBuffer();
m_cpuLoad = ((millis() - m_lastFrameTs)*100)/m_frameDurationMs;
}
template<class C, uint8_t W, uint8_t H, uint8_t B>
void NanoEngine<C,W,H,B>::begin()
{
NanoEngineCore::begin();
if (C::BITS_PER_PIXEL > 1)
{
ssd1306_setMode(LCD_MODE_NORMAL);
}
}
template<class C, uint8_t W, uint8_t H, uint8_t B>
void NanoEngine<C,W,H,B>::notify(const char *str)
{
NanoEngineTiler<C,W,H,B>::displayPopup(str);
delay(1000);
m_lastFrameTs = millis();
NanoEngineTiler<C,W,H,B>::refresh();
}
/**
* @}
*/
#endif
+183
View File
@@ -0,0 +1,183 @@
/*
MIT License
Copyright (c) 2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* @file point.h Point class
*/
#ifndef _NANO_POINT_H_
#define _NANO_POINT_H_
#include "ssd1306_hal/io.h"
/**
* @ingroup NANO_ENGINE_API
* @{
*/
/** Describes point */
typedef struct _NanoPoint
{
/** x position in pixels */
lcdint_t x;
/** y position in pixels */
lcdint_t y;
// _NanoPoint(lcdint_t px, lcdint_t py)
// {
// x = px;
// y = py;
// }
/**
* Initializes NanoPoint with specified values
* @param px - x position
* @param py - y position
*/
void setPoint(lcdint_t px, lcdint_t py) { x=px; y=py; };
/**
* Shifts right x,y value of the point by bits value.
* @param bits - number of bits to shift
*/
_NanoPoint& operator>>=(const uint8_t bits)
{
x >>= bits;
y >>= bits;
return *this;
}
/**
* Shifts left x,y value of the point by bits value.
* @param bits - number of bits to shift
*/
_NanoPoint& operator<<=(const uint8_t bits)
{
x <<= bits;
y <<= bits;
return *this;
}
/**
* Adds point.
* @param p - point values to add to the point.
*/
_NanoPoint& operator+=(const _NanoPoint &p)
{
x += p.x;
y += p.y;
return *this;
};
/**
* Subtracts point.
* @param p - point values to subtract from the point.
*/
_NanoPoint& operator-=(const _NanoPoint &p)
{
x -= p.x;
y -= p.y;
return *this;
};
/**
* Subtracts point.
* @param p - point values to subtract from the point.
*/
_NanoPoint operator-(const _NanoPoint &p)
{
return { static_cast<lcdint_t>(x - p.x),
static_cast<lcdint_t>(y - p.y) };
};
/**
* Adds point.
* @param p - point values to add to the point.
*/
_NanoPoint operator+(const _NanoPoint &p)
{
return { static_cast<lcdint_t>(x + p.x),
static_cast<lcdint_t>(y + p.y) };
};
/**
* Shifts right x,y value of the point by bits value.
* @param bits - number of bits to shift
*/
_NanoPoint operator>>(const uint8_t bits) const
{
return { static_cast<lcdint_t>(x >> bits),
static_cast<lcdint_t>(y >> bits) };
};
/**
* Shifts left x,y value of the point by bits value.
* @param bits - number of bits to shift
*/
_NanoPoint operator<<(const uint8_t bits) const
{
return { static_cast<lcdint_t>(x << bits),
static_cast<lcdint_t>(y << bits) };
};
/**
* Divides x,y value of the point by d value.
* @param d divider
*/
_NanoPoint operator/(const int16_t d) const
{
return { static_cast<lcdint_t>(x / d),
static_cast<lcdint_t>(y / d) };
};
} NanoPoint;
#ifndef DOXYGEN_SHOULD_SKIP_THIS
inline NanoPoint operator+(const NanoPoint& p1, const NanoPoint& p2)
{
return { (lcdint_t)(p1.x + p2.x), (lcdint_t)(p1.y + p2.y) };
}
inline NanoPoint operator-(const NanoPoint& p1, const NanoPoint& p2)
{
return { (lcdint_t)(p1.x - p2.x), (lcdint_t)(p1.y - p2.y) };
}
inline bool operator==(const NanoPoint& p1, const NanoPoint& p2)
{
return (p1.x == p2.x) && (p1.y == p2.y);
}
inline bool operator!=(const NanoPoint& p1, const NanoPoint& p2)
{
return !(p1 == p2);
}
#endif // DOXYGEN_SHOULD_SKIP_THIS
/**
* @}
*/
#endif
+257
View File
@@ -0,0 +1,257 @@
/*
MIT License
Copyright (c) 2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* @file rect.h Rectangle class
*/
#ifndef _NANO_RECT_H_
#define _NANO_RECT_H_
#include "point.h"
#include "ssd1306_hal/io.h"
/**
* @ingroup NANO_ENGINE_API
* @{
*/
/**
* NanoRect structure describes rectangle area.
*/
typedef struct _NanoRect
{
/** top-left point of the rectangle area */
NanoPoint p1;
/** right-bottom point of the rectangle area */
NanoPoint p2;
/** returns width of NanoRect */
lcdint_t width() const
{
return p2.x - p1.x + 1;
}
/** returns size of NanoRect */
const NanoPoint size() const
{
return {width(), height()};
}
/** returns height of NanoRect */
lcdint_t height() const
{
return p2.y - p1.y + 1;
}
/**
* Shifts rectangle area by dx;dy pixels.
* @param dx - delta on x-axis
* @param dy - delta on y-axis
*/
void move(lcdint_t dx, lcdint_t dy)
{
p1.x += dx; p2.x += dx;
p1.y += dy; p2.y += dy;
}
/**
* Shifts rectangle area by dx pixels.
* @param dx - delta on x-axis
*/
void addH(lcdint_t dx)
{
p1.x += dx; p2.x += dx;
}
/**
* Shifts rectangle area by dy pixels.
* @param dy - delta on y-axis
*/
void addV(lcdint_t dy)
{
p1.y += dy;
p2.y += dy;
}
/**
* Initializes NanoRect with specified values
* @param l - left position
* @param t - top position
* @param r - right position
* @param b - bottom position
*/
void setRect(lcdint_t l, lcdint_t t, lcdint_t r, lcdint_t b)
{
p1.x = l; p1.y = t;
p2.x = r; p2.y = b;
}
/**
* Crops rectangle to fit specified area
*
* @param rect rectangle to crop to
*/
void crop(const _NanoRect& rect)
{
if (p1.x < rect.p1.x) p1.x = rect.p1.x;
if (p1.y < rect.p1.y) p1.y = rect.p1.y;
if (p2.x > rect.p2.x) p2.x = rect.p2.x;
if (p2.y > rect.p2.y) p2.y = rect.p2.y;
}
/**
* Returns true if specified x position is between left and right borders.
* @param x - position to check
*/
bool collisionX(lcdint_t x) const
{
return (x >= p1.x) && (x <= p2.x);
}
/**
* Returns true if specified y position is between left and right borders.
* @param y - position to check
*/
bool collisionY(lcdint_t y) const { return (y >= p1.y) && (y <= p2.y); };
/**
* Returns true if specified point is inside rectangle area.
* @param p - point to check.
*/
bool collision(const NanoPoint &p) const
{
return collisionX(p.x) && collisionY(p.y);
}
/**
* Returns true of point belongs to rectangle area
*
* @param p point to check for
*/
bool contains(const NanoPoint &p) const
{
return collision(p);
}
/**
* Returns true if whole rectangle belongs to rectangle area
*
* @param r rectangle to check
*/
bool contains(const _NanoRect &r) const
{
return contains(r.p1) && contains(r.p2);
}
/**
* Returns true if rectangle topleft or rightbottom points belong to rectangle area
*
* @param r rectangle to check
*/
bool containsPartOf(const _NanoRect &r) const
{
return contains(r.p1) || contains(r.p2);
}
/**
* Returns true if specified point is above rectangle area.
* @param p - point to check.
*/
bool above(const NanoPoint &p) const { return (p.y < p1.y); };
/**
* Returns true if specified point is below rectangle area.
* @param p - point to check.
*/
bool below(const NanoPoint &p) const { return (p.y > p2.y); };
/**
* Returns true if specified point is above rectangle area.
* @param p - point to check.
*/
_NanoRect operator-(const _NanoPoint &p)
{
return { {static_cast<lcdint_t>(p1.x - p.x), static_cast<lcdint_t>(p1.y - p.y) },
{static_cast<lcdint_t>(p2.x - p.x), static_cast<lcdint_t>(p2.y - p.y) } };
}
/**
* Add point to all points of rectangle.
* @param p - point to add.
*/
_NanoRect operator+(const _NanoPoint &p)
{
return { {static_cast<lcdint_t>(p1.x + p.x), static_cast<lcdint_t>(p1.y + p.y) },
{static_cast<lcdint_t>(p2.x + p.x), static_cast<lcdint_t>(p2.y + p.y) } };
}
/**
* Subtracts point to all points of rectangle.
* @param p - point to subtract.
*/
_NanoRect& operator+=(const _NanoPoint &p)
{
p1.x += p.x;
p1.y += p.y;
p2.x += p.x;
p2.y += p.y;
return *this;
}
/**
* Shifts right x,y value of the point by bits value.
* @param bits - number of bits to shift
*/
_NanoRect operator>>(const uint8_t bits) const
{
return { p1 >> bits, p2 >> bits };
};
/**
* Shifts left x,y value of the point by bits value.
* @param bits - number of bits to shift
*/
_NanoRect operator<<(const uint8_t bits) const
{
return { p1 << bits, p2 << bits };
};
} NanoRect;
#ifndef DOXYGEN_SHOULD_SKIP_THIS
inline NanoRect operator+(const NanoRect& rect, const NanoPoint& p)
{
return { { (lcdint_t)(rect.p1.x + p.x), (lcdint_t)(rect.p1.y + p.y) },
{ (lcdint_t)(rect.p2.x + p.x), (lcdint_t)(rect.p2.y + p.y) } };
}
#endif
/**
* @}
*/
#endif
+303
View File
@@ -0,0 +1,303 @@
/*
MIT License
Copyright (c) 2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* @file sprite.h Sprite class
*/
#ifndef _NANO_SPRITE_H_
#define _NANO_SPRITE_H_
#include "point.h"
#include "rect.h"
#include "ssd1306_hal/io.h"
/**
* @ingroup NANO_ENGINE_API
* @{
*/
/**
* This is template class for user sprites implementations.
* NanoSprite can work only as part of NanoEngine, it requires
* NanoEngine type and NanoEngine instance as arguments.
*/
template<typename T, T &E>
class NanoSprite
{
public:
/**
* Creates sprite object of variable size. Such sprites can
* change their size and bitmap content.
* @param pos position of the sprite in global coordinates
* @param size size of sprite
* @param bitmap sprite content (in flash memory)
*/
NanoSprite(const NanoPoint &pos, const NanoPoint &size, const uint8_t *bitmap)
: m_rect{pos, pos + size}
, m_bitmap( bitmap )
{
}
/**
* Draws monochrome sprite on Engine canvas
*/
void draw()
{
E.canvas.drawBitmap1(m_rect.p1.x, m_rect.p1.y, m_rect.width(), m_rect.height(), m_bitmap);
}
/**
* Marks sprite locate for refreshing on the new frame
*/
void refresh()
{
E.refreshWorld( m_rect );
}
/**
* Moves sprite to new position
*/
void moveTo(const NanoPoint &p)
{
refresh();
m_rect = { p, p + m_rect.size() };
refresh();
}
/**
* Moves sprite to new position by specified offset
*/
void moveBy(const NanoPoint &p)
{
refresh();
m_rect += p;
refresh();
}
/**
* Returns bottom-center point of the sprite
*/
const NanoPoint bottom() const
{
return { (m_rect.p1.x + m_rect.p2.x) >> 1, m_rect.p2.y };
}
/**
* Returns top-center point of the sprite
*/
const NanoPoint top() const
{
return { (m_rect.p1.x + m_rect.p2.x) >> 1, m_rect.p1.y };
}
/**
* Returns left-center point of the sprite
*/
const NanoPoint left() const
{
return { m_rect.p1.x, (m_rect.p1.y + m_rect.p2.y) >> 1 };
}
/**
* Returns right-center point of the sprite
*/
const NanoPoint right() const
{
return { m_rect.p2.x, (m_rect.p1.y + m_rect.p2.y) >> 1 };
}
/**
* Returns center point of the sprite
*/
const NanoPoint center() const
{
return { (m_rect.p1.x + m_rect.p2.x) >> 1, (m_rect.p1.y + m_rect.p2.y) >> 1 };
}
/**
* Changes sprite bitmap to new one.
*/
void setBitmap( const uint8_t * bitmap )
{
m_bitmap = bitmap;
}
/**
* Returns sprite x position
*/
lcdint_t x( ) const { return m_rect.p1.x; }
/**
* Returns sprite y position
*/
lcdint_t y( ) const { return m_rect.p1.y; }
private:
NanoRect m_rect;
const uint8_t *m_bitmap;
};
/**
* This is template class for user sprites implementation.
* It requires NanoEngine type and NanoEngine instance as arguments.
*/
template<typename T, T &E>
class NanoFixedSprite
{
public:
/**
* Creates sprite object of fixed size. Such sprites can
* change their bitmap content only and position.
* @param pos position of the sprite in global coordinates
* @param size size of sprite
* @param bitmap sprite content (in flash memory)
*/
NanoFixedSprite(const NanoPoint &pos, const NanoPoint &size, const uint8_t *bitmap)
: m_pos(pos)
, m_size(size)
, m_bitmap( bitmap )
{
}
/**
* Draws monochrome sprite on Engine canvas
*/
void draw()
{
E.canvas.drawBitmap1(m_pos.x, m_pos.y, m_size.x, m_size.y, m_bitmap);
}
/**
* Marks sprite locate for refreshing on the new frame
*/
void refresh()
{
E.refreshWorld( m_pos.x, m_pos.y,
m_pos.x + m_size.x - 1, m_pos.y + m_size.y - 1 );
}
/**
* Moves sprite to new position
*/
void moveTo(const NanoPoint &p)
{
refresh();
m_pos = p;
refresh();
}
/**
* Moves sprite to new position by specified offset
*/
void moveBy(const NanoPoint &p)
{
refresh();
m_pos += p;
refresh();
}
/**
* Returns bottom-center point of the sprite
*/
const NanoPoint bottom() const
{
return { m_pos.x + (m_size.x >> 1), m_pos.y + m_size.y - 1 };
}
/**
* Returns top-center point of the sprite
*/
const NanoPoint top() const
{
return { m_pos.x + (m_size.x >> 1), m_pos.y };
}
/**
* Returns left-center point of the sprite
*/
const NanoPoint left() const
{
return { m_pos.x, m_pos.y + (m_size.y>>1) };
}
/**
* Returns right-center point of the sprite
*/
const NanoPoint right() const
{
return { m_pos.x + m_size.x - 1, m_pos.y + (m_size.y>>1) };
}
/**
* Returns center point of the sprite
*/
const NanoPoint center() const
{
return { m_pos.x + (m_size.x >> 1), m_pos.y + (m_size.y>>1) };
}
/**
* Changes sprite bitmap to new one.
*/
void setBitmap( const uint8_t * bitmap )
{
m_bitmap = bitmap;
}
/**
* Returns current sprite position (top-left corner)
*/
const NanoPoint & getPosition() const { return m_pos; }
/**
* Returns sprite x position
*/
lcdint_t x( ) const { return m_pos.x; }
/**
* Returns sprite y position
*/
lcdint_t y( ) const { return m_pos.y; }
/**
* Returns current sprite position (top-left corner)
*/
const NanoPoint & pos() const { return m_pos; }
protected:
/** fixed size of sprite */
const NanoPoint m_size;
/** Sprite position in global (world) coordinates */
NanoPoint m_pos;
private:
const uint8_t *m_bitmap;
};
/**
* @}
*/
#endif
+364
View File
@@ -0,0 +1,364 @@
/*
MIT License
Copyright (c) 2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* @file tiler.h Tiler helper for graphics processing
*/
#ifndef _NANO_ENGINE_TILER_H_
#define _NANO_ENGINE_TILER_H_
#include "canvas.h"
#include "lcd/lcd_common.h"
/**
* @ingroup NANO_ENGINE_API
* @{
*/
/**
* Structure, holding currently set font.
* @warning Only for internal use.
*/
extern "C" SFixedFontInfo s_fixedFont;
/* The table below defines arguments for NanoEngineTiler. *
* canvas width height bits */
// Tiles for monochrome displays
#define TILE_128x64_MONO NanoCanvas1, 128, 64, 7 ///< Full-screen 1-bit tile for SSD1306
#define TILE_8x8_MONO NanoCanvas1, 8, 8, 3 ///< Standard 1-bit tile 8x8 for monochrome mode
#define TILE_16x16_MONO NanoCanvas1, 16, 16, 4 ///< Standard 1-bit tile 16x16 for monochrome mode
#define TILE_32x32_MONO NanoCanvas1, 32, 32, 4 ///< Standard 1-bit tile 32x32 for monochrome mode
// Tiles for 8-bit displays
#define TILE_8x8_RGB8 NanoCanvas8, 8, 8, 3 ///< Standard 8-bit RGB tile 8x8
#define TILE_16x16_RGB8 NanoCanvas8, 16, 16, 4 ///< Standard 8-bit RGB tile 16x16
#define TILE_32x32_RGB8 NanoCanvas8, 32, 32, 5 ///< Standard 8-bit RGB tile 32x32
#define TILE_8x8_MONO_8 NanoCanvas1_8,8, 8, 3 ///< Standard 1-bit tile 8x8 for RGB mode
// Tiles for 16-bit displays
#define TILE_8x8_RGB16 NanoCanvas16, 8, 8, 3 ///< Standard 16-bit RGB tile 8x8
// Adafruit tiles
#define ADATILE_8x8_MONO AdafruitCanvas1, 8, 8, 3 ///< Use Adafruit GFX implementation as NanoEngine canvas
#define ADATILE_8x8_RGB8 AdafruitCanvas8, 8, 8, 3 ///< Use Adafruit GFX implementation as NanoEngine canvas
#define ADATILE_8x8_RGB16 AdafruitCanvas16, 8, 8, 3 ///< Use Adafruit GFX implementation as NanoEngine canvas
/**
* Type of user-specified draw callback.
*/
typedef bool (*TNanoEngineOnDraw)(void);
/**
* This class template is responsible for holding and updating data about areas to be refreshed
* on LCD display. It accepts canvas class, tile width in pixels, tile height in pixels and
* number of bits in tile width as arguments for the template.
* For example, for 8x8 8-bit RGB tiles the reference should be NanoEngineTiler<NanoCanvas8,8,8,3>,
* and 3 bits means 3^2 = 8.
* If you need to have single big buffer, holding the whole content for monochrome display,
* you can specify something like this NanoEngineTiler<NanoCanvas1,128,64,7>.
*/
template<class C, lcduint_t W, lcduint_t H, uint8_t B>
class NanoEngineTiler
{
protected:
/** Only child classes can initialize the engine */
NanoEngineTiler()
{
refresh();
};
public:
/** Number of bits in tile size. 5 corresponds to 1<<5 = 32 tile size */
static const uint8_t NE_TILE_SIZE_BITS = B;
/** Width of tile in pixels */
static const lcduint_t NE_TILE_WIDTH = W;
/** Height of tile in pixels */
static const lcduint_t NE_TILE_HEIGHT = H;
/** Max tiles supported in X */
static const uint8_t NE_MAX_TILES_NUM = 64 >> (B - 3);
/** object, representing canvas. Use it in your draw handler */
static C canvas;
/**
* Marks all tiles for update. Actual update will take place in display() method.
*/
static void refresh()
{
memset(m_refreshFlags,0xFF,sizeof(uint16_t) * NanoEngineTiler<C,W,H,B>::NE_MAX_TILES_NUM);
}
/**
* Mark specified area in pixels for redrawing by NanoEngine.
* Actual update will take place in display() method.
* @note assumes that rect is in local screen coordinates
*/
static void refresh(const NanoRect &rect)
{
refresh(rect.p1.x, rect.p1.y, rect.p2.x, rect.p2.y);
}
/**
* Mark specified area in pixels for redrawing by NanoEngine.
* Actual update will take place in display() method.
*/
static void refresh(const NanoPoint &point)
{
if ((point.y<0) || ((point.y>>B)>=NE_MAX_TILES_NUM)) return;
m_refreshFlags[(point.y>>B)] |= (1<<(point.x>>B));
}
/**
* Mark specified area in pixels for redrawing by NanoEngine.
* Actual update will take place in display() method.
*/
static void refresh(lcdint_t x1, lcdint_t y1, lcdint_t x2, lcdint_t y2)
{
if (y2 < 0) return;
if (y1 < 0) y1 = 0;
if (x1 < 0) x1 = 0;
y1 = y1>>B;
y2 = min((y2>>B), NE_MAX_TILES_NUM - 1);
for (uint8_t y=y1; y<=y2; y++)
{
for(uint8_t x=x1>>B; x<=(x2>>B); x++)
{
m_refreshFlags[y] |= (1<<x);
}
}
}
/**
* Marks for refresh lcd area, which corresponds to specified rectangle in
* global (World) coordinates. If engine offset is (0,0), then this function
* refreshes the same area as refresh().
*/
static void refreshWorld(const NanoRect &rect)
{
refreshWorld(rect.p1.x, rect.p1.y, rect.p2.x, rect.p2.y);
}
/**
* Marks for refresh lcd area, which corresponds to specified rectangle in
* global (World) coordinates. If engine offset is (0,0), then this function
* refreshes the same area as refresh().
*/
static void refreshWorld(lcdint_t x1, lcdint_t y1, lcdint_t x2, lcdint_t y2)
{
refresh(x1 - offset.x, y1 - offset.y, x2 - offset.x, y2 - offset.y);
}
/**
* Marks specified pixel area for redrawing by NanoEngine.
* @param point point in global (World) coordinates
*/
static void refreshWorld(const NanoPoint &point)
{
refresh( point - offset );
}
/**
* Switches engine canvas to local coordinates system. This method can be useful
* to ease up drawing of some static elements on lcd display.
* @warning do not call twice subsequentally.
*/
static void localCoordinates()
{
canvas.offset -= offset;
}
/**
* Switches engine canvas to global (World) coordinates system. This method can be useful
* to create screen moving animation.
* @warning do not call twice subsequentally.
*/
static void worldCoordinates()
{
canvas.offset += offset;
}
/**
* Moves engine coordinate to new position (this sets World coordinates offset).
*/
static void moveTo(const NanoPoint & position)
{
offset = position;
}
/**
* Moves engine coordinate to new position and mark whole display for refresh
* (this sets World coordinates offset).
*/
static void moveToAndRefresh(const NanoPoint & position)
{
moveTo(position);
refresh();
}
/**
* Returns current World offset
*/
const NanoPoint & getPosition() const
{
return offset;
}
/**
* Sets user-defined draw callback. This callback will be called everytime, engine needs
* to update display content. If callback returns false, engine will not update those area.
* You always have a way to find out, which area is being updated by engine via
* NanoEngine<>::canvas::getOffset() and NanoEngine<>::NE_TILE_SIZE.
* @warning By default canvas in the engine is initialized with local screen coordinates. So
* graphics object with [0,0] coordinates will be placed at topleft position on the
* display. But engine supports also global coordinates, in this case actual object
* position depends on current engine offset. Refer to worldCoordinates() and
* localCoordinates().
* @param callback - user-defined draw callback.
* @note you can change draw callback anytime you need.
* @see worldCoordinates()
* @see localCoordinates()
*/
static void drawCallback(TNanoEngineOnDraw callback)
{
m_onDraw = callback;
}
/**
* @brief Returns true if point is inside the rectangle area.
* Returns true if point is inside the rectangle area.
* @param p - point to check
* @param rect - rectangle, describing the region to check with the point
* @returns true if point is inside the rectangle area.
*/
static bool collision(NanoPoint &p, NanoRect &rect) { return rect.collision( p ); }
protected:
/**
* Contains information on tiles to be updated.
* Elements of array are rows and bits are columns.
*/
static uint16_t m_refreshFlags[NE_MAX_TILES_NUM];
/** Callback to call if specific tile needs to be updated */
static TNanoEngineOnDraw m_onDraw;
/**
* @brief refreshes content on oled display.
* Refreshes content on oled display. Call it, if you want to update the screen.
* Engine will update only those areas, which are marked by refresh()
* methods.
*/
static void displayBuffer();
/**
* @brief prints popup message over display content
* prints popup message over display content
* @param msg - message to display
*/
static void displayPopup(const char *msg);
private:
/** Buffer, used by NanoCanvas */
static uint8_t m_buffer[W * H * C::BITS_PER_PIXEL / 8];
static NanoPoint offset;
};
template<class C, lcduint_t W, lcduint_t H, uint8_t B>
uint16_t NanoEngineTiler<C,W,H,B>::m_refreshFlags[NE_MAX_TILES_NUM];
template<class C, lcduint_t W, lcduint_t H, uint8_t B>
uint8_t NanoEngineTiler<C,W,H,B>::m_buffer[W * H * C::BITS_PER_PIXEL / 8];
template<class C, lcduint_t W, lcduint_t H, uint8_t B>
C NanoEngineTiler<C,W,H,B>::canvas(W, H, m_buffer);
template<class C, lcduint_t W, lcduint_t H, uint8_t B>
NanoPoint NanoEngineTiler<C,W,H,B>::offset = {0, 0};
template<class C, lcduint_t W, lcduint_t H, uint8_t B>
TNanoEngineOnDraw NanoEngineTiler<C,W,H,B>::m_onDraw = nullptr;
template<class C, lcduint_t W, lcduint_t H, uint8_t B>
void NanoEngineTiler<C,W,H,B>::displayBuffer()
{
if (!m_onDraw) // If onDraw handler is not set, just output current canvas
{
canvas.blt();
return;
}
for (lcduint_t y = 0; y < ssd1306_lcd.height; y = y + NE_TILE_HEIGHT)
{
uint16_t flag = m_refreshFlags[y >> NE_TILE_SIZE_BITS];
m_refreshFlags[y >> NE_TILE_SIZE_BITS] = 0;
for (lcduint_t x = 0; x < ssd1306_lcd.width; x = x + NE_TILE_WIDTH)
{
if (flag & 0x01)
{
canvas.setOffset(x, y);
if (m_onDraw())
{
canvas.setOffset(x, y);
canvas.blt();
}
}
flag >>=1;
}
}
}
template<class C, lcduint_t W, lcduint_t H, uint8_t B>
void NanoEngineTiler<C,W,H,B>::displayPopup(const char *msg)
{
NanoRect rect = { {8, (ssd1306_lcd.height>>1) - 8}, {ssd1306_lcd.width - 8, (ssd1306_lcd.height>>1) + 8} };
// TODO: It would be nice to calculate message height
NanoPoint textPos = { (ssd1306_lcd.width - (lcdint_t)strlen(msg)*s_fixedFont.h.width) >> 1, (ssd1306_lcd.height>>1) - 4 };
refresh(rect);
for (lcduint_t y = 0; y < ssd1306_lcd.height; y = y + NE_TILE_HEIGHT)
{
uint16_t flag = m_refreshFlags[y >> NE_TILE_SIZE_BITS];
m_refreshFlags[y >> NE_TILE_SIZE_BITS] = 0;
for (lcduint_t x = 0; x < ssd1306_lcd.width; x = x + NE_TILE_WIDTH)
{
if (flag & 0x01)
{
canvas.setOffset(x, y);
if (m_onDraw) m_onDraw();
canvas.setOffset(x, y);
canvas.setColor(RGB_COLOR8(0,0,0));
canvas.fillRect(rect);
canvas.setColor(RGB_COLOR8(192,192,192));
canvas.drawRect(rect);
canvas.printFixed( textPos.x, textPos.y, msg);
canvas.blt();
}
flag >>=1;
}
}
}
/**
* @}
*/
#endif
+522
View File
@@ -0,0 +1,522 @@
/*
MIT License
Copyright (c) 2016-2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "nano_gfx.h"
#include "ssd1306.h"
extern const uint8_t *s_font6x8;
extern "C" SFixedFontInfo s_fixedFont;
#ifdef CONFIG_MULTIPLICATION_NOT_SUPPORTED
#define YADDR(y) (static_cast<uint16_t>((y) >> 3) << m_p)
#define BADDR(b) ((b) << m_p)
#else
#define YADDR(y) (static_cast<uint16_t>((y) >> 3) * m_w)
#define BADDR(b) ((b) * m_w)
#endif
void NanoCanvas::putPixel(uint8_t x, uint8_t y)
{
if ((x>=m_w) || (y>=m_h)) return;
if (m_invertByte)
{
m_bytes[YADDR(y) + x] &= ((1 << (y & 0x7))^m_invertByte);
}
else
{
m_bytes[YADDR(y) + x] |= (1 << (y & 0x7));
}
};
void NanoCanvas::drawHLine(uint8_t x1, uint8_t y1, uint8_t x2)
{
if (y1 >= m_h) return;
if (x2 < x1) x1 = 0;
if (x1 >= m_w) return;
if (x2 >= m_w) x2 = m_w - 1;
for(uint8_t x = x1; x<=x2; x++)
m_bytes[YADDR(y1) + x] |= (1 << (y1 & 0x7));
};
void NanoCanvas::drawVLine(uint8_t x1, uint8_t y1, uint8_t y2)
{
if (x1 >= m_w) return;
if (y2 < y1) y1 = 0;
if (y1 >= m_h) return;
if (y2 >= m_h) y2 = m_h - 1;
for(uint8_t y = y1; y<=y2; y++)
m_bytes[YADDR(y) + x1] |= (1 << (y & 0x7));
};
void NanoCanvas::drawRect(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2)
{
drawHLine(x1, y1, x2);
drawHLine(x1, y2, x2);
drawVLine(x1, y1, y2);
drawVLine(x2, y1, y2);
};
void NanoCanvas::fillRect(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, uint8_t templ)
{
templ ^= m_invertByte;
if ((x1 < x2) && (x1 >= m_w)) return;
if ((y1 < y2) && (y1 >= m_h)) return;
if (x1 > x2) x1 = 0;
if (y1 > y2) y1 = 0;
if (x2 >= m_w) x2 = m_w -1;
if (y2 >= m_h) y2 = m_h -1;
uint8_t bank1 = (y1 >> 3);
uint8_t bank2 = (y2 >> 3);
for (uint8_t bank = bank1; bank<=bank2; bank++)
{
uint8_t mask = 0xFF;
if (bank1 == bank2)
{
mask = (mask >> ((y1 & 7) + 7 - (y2 & 7))) << (y1 & 7);
}
else if (bank1 == bank)
{
mask = (mask << (y1 & 7));
}
else if (bank2 == bank)
{
mask = (mask >> (7 - (y2 & 7)));
}
for (uint8_t x=x1; x<=x2; x++)
{
m_bytes[BADDR(bank) + x] &= ~mask;
m_bytes[BADDR(bank) + x] |= (templ & mask);
}
}
};
void NanoCanvas::clear()
{
memset(m_bytes, m_invertByte, static_cast<uint16_t>(m_w) * (m_h >> 3));
}
void NanoCanvas::charF6x8(uint8_t x, uint8_t y, const char ch[], EFontStyle style)
{
uint8_t i, j, topMask, bottomMask;
if (y>=m_h) return;
j = 0;
topMask = (0xFF >> (8 - (y & 0x7)));
bottomMask = (0xFF << (y & 0x7));
while(ch[j] != '\0')
{
uint8_t c = ch[j] - 32;
uint8_t ldata = 0;
for(i=0;i<6;i++)
{
if (x>=m_w) return;
uint8_t data;
if ( style == STYLE_NORMAL )
{
data = pgm_read_byte(&s_font6x8[c*6+i]);
}
else if ( style == STYLE_BOLD )
{
data = pgm_read_byte(&s_font6x8[c*6+i]);
uint8_t temp = data | ldata;
ldata = data;
data = temp;
}
else
{
data = pgm_read_byte(&s_font6x8[c*6+i + 1]);
uint8_t temp = (data & 0xF0) | ldata;
ldata = (data & 0x0F);
data = temp;
}
m_bytes[YADDR(y) + x] &= topMask;
m_bytes[YADDR(y) + x] |= (data << (y & 0x7));
if (y+8 < m_h)
{
m_bytes[YADDR(y) + m_w + x] &= bottomMask;
m_bytes[YADDR(y) + m_w + x] |= (data >> (8 - (y & 0x7)));
}
x++;
}
j++;
}
}
void NanoCanvas::charF12x16(uint8_t xpos, uint8_t y, const char ch[], EFontStyle style)
{
uint8_t i, j = 0;
uint8_t text_index = 0;
uint8_t odd = 0;
uint8_t x = xpos;
uint8_t topMask, bottomMask;
if ( y >= m_h ) return;
topMask = (0xFF >> (8 - (y & 0x7)));
bottomMask = (0xFF << (y & 0x7));
for(;;)
{
if( ( x > m_w - 12 ) || ( ch[j] == '\0' ) )
{
x = xpos;
y += 8;
if (y > (m_h - 8))
{
break;
}
if (odd)
{
text_index = j;
if (ch[j] == '\0')
{
break;
}
}
else
{
j = text_index;
}
odd = !odd;
}
uint8_t c = ch[j] - 32;
uint8_t ldata = 0;
for( i=0; i<6; i++)
{
uint8_t data;
if ( style == STYLE_NORMAL )
{
data = pgm_read_byte(&s_font6x8[c*6+i]);
}
else if ( style == STYLE_BOLD )
{
data = pgm_read_byte(&s_font6x8[c*6+i]);
uint8_t temp = data | ldata;
ldata = data;
data = temp;
}
else
{
data = pgm_read_byte(&s_font6x8[c*6+i + 1]);
uint8_t temp = (data & 0xF0) | ldata;
ldata = (data & 0x0F);
data = temp;
}
if (odd) data >>= 4;
data = ((data & 0x01) ? 0x03: 0x00) |
((data & 0x02) ? 0x0C: 0x00) |
((data & 0x04) ? 0x30: 0x00) |
((data & 0x08) ? 0xC0: 0x00);
for (uint8_t n=2; n>0; n--)
{
m_bytes[YADDR(y) + x] &= topMask;
m_bytes[YADDR(y) + x] |= (data << (y & 0x7));
if (y+8 < m_h)
{
m_bytes[YADDR(y) + m_w + x] &= bottomMask;
m_bytes[YADDR(y) + m_w + x] |= (data >> (8 - (y & 0x7)));
}
x++;
}
}
j++;
}
}
void NanoCanvas::printFixed(uint8_t xpos, uint8_t y, const char ch[], EFontStyle style)
{
uint8_t i, j = 0;
uint8_t text_index = 0;
uint8_t page_offset = 0;
uint8_t x = xpos;
uint8_t topMask, bottomMask;
if ( y >= m_h ) return;
topMask = (0xFF >> (8 - (y & 0x7)));
bottomMask = (0xFF << (y & 0x7));
for(;;)
{
if( ( x > m_w - s_fixedFont.h.width ) || ( ch[j] == '\0' ) )
{
x = xpos;
y += 8;
if (y > (m_h - 8))
{
break;
}
page_offset++;
if (page_offset == s_fixedFont.pages)
{
text_index = j;
page_offset = 0;
if (ch[j] == '\0')
{
break;
}
}
else
{
j = text_index;
}
}
uint8_t c = ch[j] - 32;
if ( c > 224 )
{
c = 0;
}
uint8_t ldata = 0;
uint16_t offset = (c * s_fixedFont.pages + page_offset) * s_fixedFont.h.width;
for( i=0; i<s_fixedFont.h.width; i++)
{
uint8_t data;
if ( style == STYLE_NORMAL )
{
data = pgm_read_byte(&s_fixedFont.primary_table[offset]);
}
else if ( style == STYLE_BOLD )
{
data = pgm_read_byte(&s_fixedFont.primary_table[offset]);
uint8_t temp = data | ldata;
ldata = data;
data = temp;
}
else
{
data = pgm_read_byte(&s_fixedFont.primary_table[offset + 1]);
uint8_t temp = (data & 0xF0) | ldata;
ldata = (data & 0x0F);
data = temp;
}
m_bytes[YADDR(y) + x] &= topMask;
m_bytes[YADDR(y) + x] |= (data << (y & 0x7));
if (y + 8 < m_h)
{
m_bytes[YADDR(y) + m_w + x] &= bottomMask;
m_bytes[YADDR(y) + m_w + x] |= (data >> (8 - (y & 0x7)));
}
offset++;
x++;
}
j++;
}
}
void NanoCanvas::printFixed2x(uint8_t xpos, uint8_t y, const char ch[], EFontStyle style)
{
uint8_t i, j = 0;
uint8_t text_index = 0;
uint8_t page_offset = 0;
uint8_t x = xpos;
uint8_t topMask, bottomMask;
if ( y >= m_h ) return;
topMask = (0xFF >> (8 - (y & 0x7)));
bottomMask = (0xFF << (y & 0x7));
for(;;)
{
if( ( x > m_w - (s_fixedFont.h.width<<1) ) || ( ch[j] == '\0' ) )
{
x = xpos;
y += 8;
if (y > (m_h - 8))
{
break;
}
page_offset++;
if (page_offset == (s_fixedFont.pages<<1))
{
text_index = j;
page_offset = 0;
if (ch[j] == '\0')
{
break;
}
}
else
{
j = text_index;
}
}
uint8_t c = ch[j] - 32;
if ( c > 224 )
{
c = 0;
}
uint8_t ldata = 0;
uint16_t offset = (c * s_fixedFont.pages + (page_offset >> 1)) * s_fixedFont.h.width;
for( i=0; i<s_fixedFont.h.width; i++)
{
uint8_t data;
if ( style == STYLE_NORMAL )
{
data = pgm_read_byte(&s_fixedFont.primary_table[offset]);
}
else if ( style == STYLE_BOLD )
{
data = pgm_read_byte(&s_fixedFont.primary_table[offset]);
uint8_t temp = data | ldata;
ldata = data;
data = temp;
}
else
{
data = pgm_read_byte(&s_fixedFont.primary_table[offset + 1]);
uint8_t temp = (data & 0xF0) | ldata;
ldata = (data & 0x0F);
data = temp;
}
if (page_offset & 1) data >>= 4;
data = ((data & 0x01) ? 0x03: 0x00) |
((data & 0x02) ? 0x0C: 0x00) |
((data & 0x04) ? 0x30: 0x00) |
((data & 0x08) ? 0xC0: 0x00);
for (uint8_t n=2; n>0; n--)
{
m_bytes[YADDR(y) + x] &= topMask;
m_bytes[YADDR(y) + x] |= (data << (y & 0x7));
if (y+8 < m_h)
{
m_bytes[YADDR(y) + m_w + x] &= bottomMask;
m_bytes[YADDR(y) + m_w + x] |= (data >> (8 - (y & 0x7)));
}
x++;
}
offset++;
}
j++;
}
}
void NanoCanvas::drawSpritePgm(uint8_t x, uint8_t y, const uint8_t sprite[])
{
uint8_t i;
for(i=0;i<8;i++)
{
if (x >= m_w) { x++; continue; }
uint8_t d = pgm_read_byte(&sprite[i]);
if (y < m_h)
m_bytes[YADDR(y) + x] |= (d << (y & 0x7));
if ((uint8_t)(y + 8) < m_h)
m_bytes[YADDR((uint8_t)(y + 8)) + x] |= (d >> (8 - (y & 0x7)));
x++;
}
};
void NanoCanvas::drawBitmap(uint8_t startX, uint8_t startY, uint8_t w, uint8_t h, const uint8_t *buf)
{
uint8_t x,y;
for(y=0;y<h;y+=8)
{
for(x=0;x<w;x++)
{
uint8_t scrX = startX + x;
if (scrX >= m_w) continue;
uint8_t d = pgm_read_byte(&buf[x + static_cast<uint16_t>(y>>3) * w]);
uint8_t scrY = y + startY;
scrX = x + startX;
if (scrY < m_h)
m_bytes[YADDR(scrY) + scrX] |= (d << (scrY & 0x7));
scrY+=8;
if (scrY < m_h)
m_bytes[YADDR(scrY) + scrX] |= (d >> (8 - (scrY & 0x7)));
}
}
}
void NanoCanvas::drawSprite(uint8_t x, uint8_t y, const uint8_t sprite[])
{
uint8_t i;
for(i=0;i<8;i++)
{
if (x>=m_w) { x++; continue; }
uint8_t d = sprite[i];
if (uint8_t(y) < m_h)
m_bytes[YADDR(y) + x] |= (d << (y & 0x7));
if ((uint8_t)(y+8) < m_h)
m_bytes[YADDR((uint8_t)(y + 8)) + x] |= (d >> (8 - (y & 0x7)));
x++;
}
};
void NanoCanvas::drawSprite(SPRITE *sprite)
{
uint8_t i;
for(i = 0; i < sprite->w; i++)
{
if ((sprite->x + i) >= m_w) { continue; }
uint8_t d = pgm_read_byte(&sprite->data[i]);
if (sprite->y < m_h)
m_bytes[YADDR(sprite->y) + sprite->x + i] |= (d << (sprite->y & 0x7));
if (uint8_t(sprite->y + 8) < m_h)
m_bytes[YADDR(uint8_t(sprite->y + 8)) + sprite->x + i] |= (d >> (8 - (sprite->y & 0x7)));
}
}
void NanoCanvas::blt(uint8_t x, uint8_t y)
{
ssd1306_drawBuffer(x, y, m_w, m_h, m_bytes);
}
void NanoCanvas::invert()
{
for(uint16_t i=0; i< static_cast<uint16_t>(m_w) * (m_h >> 3); i++)
m_bytes[i] = ~m_bytes[i];
}
void NanoCanvas::flipH()
{
for (uint8_t y=0; y<(m_h>>3); y++)
for (uint8_t x=0; x<m_w>>1; x++)
{
uint8_t temp = m_bytes[YADDR(y) + x];
m_bytes[YADDR(y) + x] = m_bytes[YADDR(y) + m_w - x -1];
m_bytes[YADDR(y) + m_w - x -1] = temp;
}
}
////////////////////////////////////////////////////////////////////////////////
// SPRITE OBJECT
////////////////////////////////////////////////////////////////////////////////
void SPRITE::setPos(uint8_t x, uint8_t y)
{
this->x = x;
this->y = y;
}
void SPRITE::draw()
{
ssd1306_drawSprite(this);
}
void SPRITE::eraseTrace()
{
ssd1306_eraseTrace(this);
}
void SPRITE::erase()
{
ssd1306_eraseSprite(this);
}
+239
View File
@@ -0,0 +1,239 @@
/*
MIT License
Copyright (c) 2016-2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* @file nano_gfx.h Drawing in memory buffer
*/
#ifndef _NANO_GFX_H_
#define _NANO_GFX_H_
#include "nano_gfx_types.h"
#include "font6x8.h"
/**
* NanoCanvas represents objects for drawing in memory buffer
* @deprecated Use NanoCanvas1, NanoCanvas8, NanoCanvas16 instead
*/
class NanoCanvas
{
public:
/**
* Creates new canvas object.
* Width can be of any value.
* Height should be divided by 8.
* Memory buffer must be not less than w * h / 8.
*
* @param w - width
* @param h - height
* @param bytes - pointer to memory buffer to use
*/
NanoCanvas(uint8_t w, uint8_t h, uint8_t *bytes)
{
m_w = w;
m_h = h;
m_p = 3;
m_invertByte = 0;
while (w >> (m_p+1)) { m_p++; };
m_bytes = bytes;
clear();
};
/**
* Draws pixel on specified position
* @param x - position X
* @param y - position Y
* @deprecated Use putPixel() instead.
*/
inline void drawPixel(uint8_t x, uint8_t y) __attribute__ ((deprecated)) { putPixel(x,y); };
/**
* Draws pixel on specified position
* @param x - position X
* @param y - position Y
*/
void putPixel(uint8_t x, uint8_t y);
/**
* Draws rectangle
* @param x1 - left boundary
* @param y1 - top boundary
* @param x2 - right boundary
* @param y2 - bottom boundary
*/
void drawRect(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2);
/**
* Draws horizontal line
* @param x1 - left boundary
* @param y1 - position Y
* @param x2 - right boundary
*/
void drawHLine(uint8_t x1, uint8_t y1, uint8_t x2);
/**
* Draws vertical line
* @param x1 - position X
* @param y1 - top boundary
* @param y2 - bottom boundary
*/
void drawVLine(uint8_t x1, uint8_t y1, uint8_t y2);
/**
* Draws filled rectangle
* @param x1 - left boundary
* @param y1 - top boundary
* @param x2 - right boundary
* @param y2 - bottom boundary
* @param templ - template to use for filling rectangle
*/
void fillRect(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, uint8_t templ);
/**
* Clears canvas
*/
void clear();
/**
* Prints text to canvas buffer
* @param x - start position X
* @param y - start position Y
* @param ch - text to print (null-terminated)
* @param style - font style (EFontStyle), normal by default
* @deprecated use printFixed() instead.
*/
inline void char_f6x8(uint8_t x, uint8_t y, const char ch[], EFontStyle style = STYLE_NORMAL)
__attribute__ ((deprecated))
{ charF6x8(x,y,ch,style); };
/**
* Prints text to canvas buffer
* @param x - start position X
* @param y - start position Y
* @param ch - text to print (null-terminated)
* @param style - font style (EFontStyle), normal by default
* @deprecated use printFixed() instead.
*/
void charF6x8(uint8_t x, uint8_t y, const char ch[], EFontStyle style = STYLE_NORMAL);
/**
* Prints text to canvas buffer using double size font 12x16
* @param x - start position X
* @param y - start position Y
* @param ch - text to print (null-terminated)
* @param style - font style (EFontStyle), normal by default
*/
void charF12x16(uint8_t x, uint8_t y, const char ch[], EFontStyle style = STYLE_NORMAL);
/**
* Prints text to canvas buffer using fixed font.
* @param xpos - start position X
* @param y - start position Y
* @param ch - text to print (null-terminated)
* @param style - font style (EFontStyle), normal by default
* @see ssd1306_setFixedFont().
*/
void printFixed(uint8_t xpos, uint8_t y, const char ch[], EFontStyle style = STYLE_NORMAL);
/**
* Prints text to canvas buffer using fixed font double size.
* @param xpos - start position X
* @param y - start position Y
* @param ch - text to print (null-terminated)
* @param style - font style (EFontStyle), normal by default
* @see ssd1306_setFixedFont().
*/
void printFixed2x(uint8_t xpos, uint8_t y, const char ch[], EFontStyle style = STYLE_NORMAL);
/**
* Sprite is small image 8x8, sprite doesn't change background
* Reads sprite from Flash memory
*/
void drawSpritePgm(uint8_t x, uint8_t y, const uint8_t sprite[]);
/**
* Draw bitmap to the buffer from SRAM.
* @param x - horizontal position in pixels
* @param y - vertical position in pixels
* @param w - width of bitmap in pixels
* @param h - height of bitmap in pixels (must be divided by 8)
* @param buf - pointer to data, located in Flash: each byte represents 8 vertical pixels.
*/
void drawBitmap(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *buf);
/**
* Sprite is small image 8x8, sprite doesn't change background
* Reads sprite from SRAM memory
*/
void drawSprite(uint8_t x, uint8_t y, const uint8_t sprite[]);
/**
* Draws sprite in the buffer
* @param sprite - pointer to SPRITE structure containing sprite information
*/
void drawSprite(SPRITE *sprite);
/**
* Returns canvas width
*/
inline uint8_t width() const { return m_w; };
/**
* Returns canvas height
*/
inline uint8_t height() const { return m_h; };
/**
* Returns canvas buffer
*/
inline uint8_t *buffer() const { return m_bytes; };
/**
* Inverts content in the buffer.
* white becomes black and wise versa.
*/
void invert();
/**
* Flips image horizontally.
*/
void flipH();
/**
* Draws canvas on the LCD display
* @param x - horizontal position in pixels
* @param y - vertical position in blocks (pixels/8)
*/
void blt(uint8_t x, uint8_t y);
private:
uint8_t m_w;
uint8_t m_p;
uint8_t m_h;
uint8_t m_invertByte;
uint8_t *m_bytes;
};
#endif
+261
View File
@@ -0,0 +1,261 @@
/*
MIT License
Copyright (c) 2017-2019, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* @file nano_gfx_types.h Basic structures of nano gfx library
*/
#ifndef _NANO_GFX_TYPES_H_
#define _NANO_GFX_TYPES_H_
#include "ssd1306_hal/io.h"
#ifndef min
/** Macros returning minimum of 2 numbers */
#define min(a,b) ((a)<(b)?(a):(b))
#endif
#ifndef max
/** Macros returning maximum of 2 numbers */
#define max(a,b) ((a)>(b)?(a):(b))
#endif
/** Macro to generate 8-bit color for SSD1331 OLED display */
#define RGB_COLOR8(r,g,b) ( (r & 0xE0) | ((g >> 3)&0x1C) | (b>>6) )
/** Macro to generate 16-bit color for SSD1351 OLED display */
#define RGB_COLOR16(r,g,b) ( ((r<<8) & 0xF800) | ((g << 3)&0x07E0) | (b>>3) )
/** Macro to convert 3-3-2 color to 5-6-5 color */
#define RGB8_TO_RGB16(c) ( (((uint16_t)c & 0b11100000) << 8) | \
(((uint16_t)c & 0b00011100) << 6) | \
(((uint16_t)c & 0b00000011) << 3) )
/** Macro to convert 8-bit RGB to 4-bit monochrome format */
#define RGB8_TO_GRAY4(rgb) ( (rgb >> 6) + ((rgb >> 2) & 0x07) + (rgb & 0x03) )
/** Macro to generate 4-bit monochrome color from gray component */
#define GRAY_COLOR4(gray) ( ((gray >> 4) & 0x0F) | (gray & 0xF0) )
/** Macro to convert 5-6-5 color to 3-3-2 color */
#define RGB16_TO_RGB8(c) ( ((uint16_t)(c >> 8) & 0b11100000) | \
((uint16_t)(c >> 6) & 0b00011100) | \
((uint16_t)(c >> 3) & 0b00000011) )
/** Pointer type to LCD display initialization function */
typedef void (*InitFunction)(void);
/** Supported font styles */
typedef enum
{
STYLE_NORMAL,
STYLE_BOLD,
STYLE_ITALIC,
} EFontStyle;
/** Supported scale font values */
typedef enum
{
FONT_SIZE_NORMAL = 0,
FONT_SIZE_2X = 1,
FONT_SIZE_4X = 2,
FONT_SIZE_8X = 3,
} EFontSize;
#pragma pack(push, 1)
/** Structure describes font format in memory */
typedef struct
{
uint8_t type; ///< font type: 0 - Fixed Font
uint8_t width; ///< width in pixels
uint8_t height; ///< height in pixels
uint8_t ascii_offset; ///< ascii offset
} SFontHeaderRecord;
/** Structure describes unicode block in font data */
typedef struct
{
uint16_t start_code; ///< unicode start code
uint8_t count; ///< count of unicode chars in block
} SUnicodeBlockRecord;
#pragma pack(pop)
/** Structure is used for internal font presentation */
typedef struct
{
SFontHeaderRecord h; ///< record, containing information on font
uint8_t count; ///< count of characters
uint8_t pages; ///< height in pages (each page height is 8-pixels)
uint8_t glyph_size; ///< glyph size in bytes
const uint8_t *primary_table; ///< font chars bits
#ifdef CONFIG_SSD1306_UNICODE_ENABLE
const uint8_t *secondary_table; ///< font chars bits
#endif
} SFixedFontInfo;
/** Structure describes single char information */
typedef struct
{
uint8_t width; ///< char width in pixels
uint8_t height; ///< char height in pixels
uint8_t spacing; ///< additional spaces after char in pixels
const uint8_t *glyph; ///< char data, located in progmem.
} SCharInfo;
/**
* Rectangle region. not used now
*/
typedef struct
{
/// left
uint8_t left;
/// top
uint8_t top;
/// right
uint8_t right;
/// bottom
uint8_t bottom;
} SSD1306_RECT;
/**
* SPRITE structure represents logical graphics object
* @deprecated Use NanoSprite or NanoFixedSprite instead.
*/
typedef struct SPRITE
{
/// draw position X on the screen
uint8_t x;
/// draw position Y on the screen
uint8_t y;
/// sprite width
uint8_t w;
/// last draw position X on the screen
uint8_t lx;
/// last draw position Y on the screen
uint8_t ly;
/// Pointer to PROGMEM data, representing sprite image
const uint8_t * data;
/// Pointer to PROGMEM data, representing sprite transparencyMask (can be nullptr)
const uint8_t * transparentMask;
#ifdef __cplusplus
/**
* Updates active position of the sprite (doesn't redraw it)
* @param x - horizontal position
* @param y - vertical position
*/
void setPos(uint8_t x, uint8_t y);
/**
* Draws sprite on the display. Position can be changed by
* updating x and y fields of SPRITE structure.
*/
void draw();
/**
* Clears some sprite parts in old position on the display.
*/
void eraseTrace();
/**
* Clears sprite from the display leaving black rectangle.
*/
void erase();
/**
* Returns true if sprite is moved not far from previous position,
* and old and new rects have intersection.
*/
inline bool isNearMove() const
{
/* We emulate abs function for unsigned vars here */
return (((uint8_t)(x-lx)<w) || ((uint8_t)(lx-x)<w)) &&
(((uint8_t)(y-ly)<8) || ((uint8_t)(ly-y)<8));
};
/**
* Returns area in 8-pixel blocks, which is used by the sprite.
*
* For example, if sprite pixels coordinates are 10,18 and size is 8x8,
* the rect will be (left:1,top:2,right:2,bottom:3).
* if sprite pixels coordinates are 32,16 and size is 8x8,
* the rect will be (left:4,top:2,right:4,bottom:2).
*/
inline SSD1306_RECT getRect() const
{
uint8_t right = ((x + w - 1)>>3);
uint8_t bottom = ((y + 7)>>3);
uint8_t left = x>>3; left = left < right ? left: 0;
uint8_t top = y>>3; top = top < bottom ? top: 0;
return (SSD1306_RECT){ left, top, right, bottom };
};
/**
* Returns area in 8-pixel blocks, which was used by the sprite last time
* For example, if sprite pixels coordinates are 10,18 and size is 8x8,
* the rect will be (left:1,top:2,right:2,bottom:3).
* if sprite pixels coordinates are 32,16 and size is 8x8,
* the rect will be (left:4,top:2,right:4,bottom:2).
*/
inline SSD1306_RECT getLRect() const
{
uint8_t left = lx;
uint8_t top = ly;
uint8_t right = (uint8_t)(lx + w - 1);
uint8_t bottom = (uint8_t)(ly + 7);
left = left < right ? left: 0;
top = top < bottom ? top: 0;
return (SSD1306_RECT){ left, top, right, bottom };
};
/**
* Returns area in 8-pixel blocks, which includes old and new position
* For example, if sprite pixels coordinates are 12,18 and size is 8x8,
* and sprite is moved to the right by 6 pixels, the rect will be
* (left:1,top:2,right:3,bottom:3).
*/
inline SSD1306_RECT getUpdateRect() const
{
uint8_t left = min(x,lx);
uint8_t top = min(y,ly);
uint8_t right = max((uint8_t)(x + w - 1), (uint8_t)(lx + w - 1));
if (((uint8_t)(lx + w - 1) < w) && (right > 2*w))
{
right = (uint8_t)(lx + w - 1);
}
uint8_t bottom = max((uint8_t)(y + 7), (uint8_t)(ly + 7));
if (((uint8_t)(ly + 7) < 8) && (bottom > 16))
{
bottom = (uint8_t)(ly + 7);
}
if ( left > right ) left = 0;
if ( top > bottom ) top = 0;
return (SSD1306_RECT){ left, top, right, bottom };
};
#endif
} SPRITE;
// ----------------------------------------------------------------------------
#endif // _NANO_GFX_TYPES_H_
+132
View File
@@ -0,0 +1,132 @@
/*
MIT License
Copyright (c) 2017-2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "sprite_pool.h"
#include "ssd1306.h"
SpritePool::SpritePool( )
: m_canvas( 8, 8, m_canvasBuf)
, m_canvasBuf{0}
, m_sprites{0}
, m_count( 0 )
{
m_rect.left = 0;
m_rect.top = 0;
m_rect.right = (ssd1306_displayWidth() >> 3) - 1;
m_rect.bottom = (ssd1306_displayHeight() >> 3) - 1;
};
void SpritePool::drawBlock(uint8_t blockColumn, uint8_t blockRow)
{
m_canvas.clear();
};
void SpritePool::drawSprites()
{
for (uint8_t i = 0; i < m_count; i++)
{
SPRITE * sprite = m_sprites[i];
if ( sprite->isNearMove( ) )
{
updateRegion(sprite->getUpdateRect());
}
else
{
updateRegion(sprite->getRect());
updateRegion(sprite->getLRect());
}
sprite->lx = sprite->x;
sprite->ly = sprite->y;
}
}
void SpritePool::refreshScreen()
{
updateRegion( (SSD1306_RECT){ (uint8_t)(m_rect.left<<3),
(uint8_t)(m_rect.top<<3),
(uint8_t)(m_rect.right<<3),
(uint8_t)(m_rect.bottom<<3) } );
}
uint8_t SpritePool::add( SPRITE &sprite )
{
uint8_t index = m_count;
if (index >= MAX_SPRITES)
{
return SpritePool::SP_ERR_NO_SPACE;
}
m_sprites[index] = &sprite;
m_count++;
return index;
};
void SpritePool::clear()
{
m_count = 0;
};
void SpritePool::remove( SPRITE &sprite )
{
updateRegion( sprite.getLRect() );
for (uint8_t i=0; i<m_count; i++)
{
if (m_sprites[i] == &sprite)
{
m_count--;
for (uint8_t j=i; j<m_count; j++)
{
m_sprites[j] = m_sprites[j+1];
}
break;
}
}
}
void SpritePool::updateRegion(SSD1306_RECT ur)
{
ur.left >>= 3;
ur.top >>= 3;
ur.right >>= 3;
ur.bottom >>= 3;
ur.left = max(ur.left, m_rect.left);
ur.top = max(ur.top, m_rect.top);
ur.right = min(ur.right, m_rect.right);
ur.bottom = min(ur.bottom, m_rect.bottom);
for(uint8_t x = ur.left; x <= ur.right; x++)
{
for(uint8_t y = ur.top; y <= ur.bottom; y++)
{
drawBlock(x,y);
for (uint8_t i = 0; i < m_count; i++)
{
m_canvas.drawSpritePgm(m_sprites[i]->x - (x << 3),
m_sprites[i]->y - (y << 3),
m_sprites[i]->data );
}
m_canvas.blt( x << 3, y );
}
}
}
+131
View File
@@ -0,0 +1,131 @@
/*
MIT License
Copyright (c) 2017-2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* @file sprite_pool.h Controlling sprites on the display
*/
#ifndef _SPRITE_POOL_H_
#define _SPRITE_POOL_H_
#include "nano_gfx.h"
/**
* Sprites pool class automates processing of several sprites.
* It remembers pointers to SPRITE objects, and carefully
* updates only the areas, touched by the sprites. So, it
* reduces number of i2c calls to SSD1306 display.
* @warning this class is deprecated and not supported anymore.
* @deprecated use NanoEngine, NanoSprite objects.
*/
class SpritePool
{
public:
/// No free space for new sprite error
static const uint8_t SP_ERR_NO_SPACE = 0xFF;
#if defined(ESP32) || defined(ESP8266)
/// Defines max sprites number supported by SpritePool
static const uint8_t MAX_SPRITES = 32;
#else
/// Defines max sprites number supported by SpritePool
static const uint8_t MAX_SPRITES = 10;
#endif
/**
* Creates empty SpritePool object.
* It is able to hold up to 10 sprites on AVR
* platforms and up to 32 sprites on ESP platforms.
*/
SpritePool( );
/**
* Draw all areas, touched by the sprites.
* To remove flickering, the method uses NanoCanvas
* capabilities.
*/
void drawSprites();
/**
* Redraws whole area, used by the sprites.
*/
void refreshScreen();
/**
* Adds SPRITE object to the internal list of SpritePool
* @param sprite - reference to SPRITE object
* @return index of added object or SP_ERR_NO_SPACE in case of error.
*/
uint8_t add( SPRITE &sprite );
/**
* Removes all SPRITE objects from internal list of SpritePool.
*/
void clear();
/**
* Removes specific SPRITE object from the SpritePool.
*/
void remove( SPRITE &sprite );
/**
* Sets active paint area region in blocks (pixels / 8)
* @param rect - region in blocks (pixels / 8)
*/
void setRect(SSD1306_RECT rect) { m_rect = rect; };
protected:
/// Canvas used to draw sprites to avoid flickering.
NanoCanvas m_canvas;
/// Rectangle, which specifies part of the display, used by the sprites
SSD1306_RECT m_rect;
/**
* This method is call every time 8x8 pixels block is needed to be drawn.
* Use m_canvas field variable, which represents block to update.
* For example, you can draw any 8x8 image, starting at 0,0 position in m_canvas.
*
* @param blockColumn - column of the block to redraw
* @param blockRow - row of the block to redraw
* @note 128x64 display has 16 columns and 8 rows.
*/
virtual void drawBlock(uint8_t blockColumn, uint8_t blockRow);
private:
/// Internal buffer for Canvas
uint8_t m_canvasBuf[8*8/8];
/// Sprites container
SPRITE *m_sprites[MAX_SPRITES];
/// Count of registered sprites
uint8_t m_count;
void updateRegion(SSD1306_RECT ur);
};
#endif
+72
View File
@@ -0,0 +1,72 @@
/*
MIT License
Copyright (c) 2016-2019, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* @file ssd1306.h SSD1306 basic draw functions
*/
#ifndef _SSD1306_H_
#define _SSD1306_H_
#include "nano_gfx_types.h"
#include "ssd1306_generic.h"
#include "ssd1306_1bit.h"
#include "ssd1306_8bit.h"
#include "ssd1306_16bit.h"
#include "ssd1306_fonts.h"
#include "lcd/lcd_common.h"
#include "lcd/oled_ssd1306.h"
#include "lcd/oled_ssd1325.h"
#include "lcd/oled_ssd1327.h"
#include "lcd/oled_ssd1331.h"
#include "lcd/oled_ssd1351.h"
#include "lcd/oled_sh1106.h"
#include "lcd/lcd_pcd8544.h"
#include "lcd/lcd_il9163.h"
#include "lcd/lcd_ili9341.h"
#include "lcd/composite_video.h"
#include "lcd/oled_template.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @ingroup LCD_INTERFACE_API
* Returns display height in pixels
*/
lcduint_t ssd1306_displayHeight(void);
/**
* @ingroup LCD_INTERFACE_API
* Returns display width in pixels
*/
lcduint_t ssd1306_displayWidth(void);
#ifdef __cplusplus
}
#endif
#endif // _SSD1306_H_
+366
View File
@@ -0,0 +1,366 @@
/*
MIT License
Copyright (c) 2018-2019, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "ssd1306_16bit.h"
#include "ssd1306_generic.h"
#include "intf/ssd1306_interface.h"
#include "lcd/lcd_common.h"
#include "ssd1306_hal/io.h"
extern uint16_t ssd1306_color;
extern uint8_t s_ssd1306_invertByte;
extern lcduint_t ssd1306_cursorX;
extern lcduint_t ssd1306_cursorY;
extern SFixedFontInfo s_fixedFont;
#ifdef CONFIG_SSD1306_UNICODE_ENABLE
extern uint8_t g_ssd1306_unicode;
#endif
void ssd1306_setRgbColor16(uint8_t r, uint8_t g, uint8_t b)
{
ssd1306_color = RGB_COLOR16(r,g,b);
}
static void ssd1306_drawBufferPitch16(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, lcduint_t pitch, const uint8_t *data)
{
ssd1306_lcd.set_block(x, y, w);
while (h--)
{
lcduint_t line = w << 1;
while (line--)
{
ssd1306_intf.send( *data );
data++;
}
data += pitch - (w << 1);
}
ssd1306_intf.stop();
}
void ssd1306_drawBufferFast16(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *data)
{
ssd1306_drawBufferPitch16(x, y, w, h, w<<1, data);
}
void ssd1306_drawBufferEx16(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, lcduint_t pitch, const uint8_t *data)
{
ssd1306_drawBufferPitch16( x, y, w, h, pitch, data );
}
// IMPORTANT: ALL 16-BIT OLED DISPLAYS ALSO SUPPORT 8-BIT DIRECT DRAW FUNCTIONS
// REFER TO ssd1306_8bit.c
void ssd1306_drawMonoBuffer16(lcdint_t xpos, lcdint_t ypos, lcduint_t w, lcduint_t h, const uint8_t *bitmap)
{
uint8_t bit = 1;
uint16_t blackColor = s_ssd1306_invertByte ? ssd1306_color : 0x00;
uint16_t color = s_ssd1306_invertByte ? 0x00 : ssd1306_color;
ssd1306_lcd.set_block(xpos, ypos, w);
while (h--)
{
lcduint_t wx = w;
while (wx--)
{
uint8_t data = *bitmap;
if ( data & bit )
ssd1306_lcd.send_pixels16( color );
else
ssd1306_lcd.send_pixels16( blackColor );
bitmap++;
}
bit <<= 1;
if (bit == 0)
{
bit = 1;
}
else
{
bitmap -= w;
}
}
ssd1306_intf.stop();
}
void ssd1306_fillScreen16(uint16_t fill_Data)
{
ssd1306_lcd.set_block(0, 0, 0);
uint32_t count = (uint32_t)ssd1306_lcd.width * (uint32_t)ssd1306_lcd.height;
while (count--)
{
ssd1306_lcd.send_pixels16( fill_Data );
}
ssd1306_intf.stop();
}
void ssd1306_clearScreen16(void)
{
ssd1306_fillScreen16( 0x0000 );
}
void ssd1306_putPixel16(lcdint_t x, lcdint_t y)
{
ssd1306_lcd.set_block(x, y, 0);
ssd1306_lcd.send_pixels16( ssd1306_color );
ssd1306_intf.stop();
}
void ssd1306_putColorPixel16(lcdint_t x, lcdint_t y, uint16_t color)
{
ssd1306_lcd.set_block(x, y, 0);
ssd1306_lcd.send_pixels16( color );
ssd1306_intf.stop();
}
void ssd1306_drawVLine16(lcdint_t x1, lcdint_t y1, lcdint_t y2)
{
ssd1306_lcd.set_block(x1, y1, 1);
while (y1<=y2)
{
ssd1306_lcd.send_pixels16( ssd1306_color );
y1++;
}
ssd1306_intf.stop();
}
void ssd1306_drawHLine16(lcdint_t x1, lcdint_t y1, lcdint_t x2)
{
ssd1306_lcd.set_block(x1, y1, 0);
while (x1 < x2)
{
ssd1306_lcd.send_pixels16( ssd1306_color );
x1++;
}
ssd1306_intf.stop();
}
void ssd1306_drawLine16(lcdint_t x1, lcdint_t y1, lcdint_t x2, lcdint_t y2)
{
lcduint_t dx = x1 > x2 ? (x1 - x2): (x2 - x1);
lcduint_t dy = y1 > y2 ? (y1 - y2): (y2 - y1);
lcduint_t err = 0;
if (dy > dx)
{
if (y1 > y2)
{
ssd1306_swap_data(x1, x2, lcdint_t);
ssd1306_swap_data(y1, y2, lcdint_t);
}
for(; y1<=y2; y1++)
{
err += dx;
if (err >= dy)
{
err -= dy;
x1 < x2 ? x1++: x1--;
}
ssd1306_putPixel16( x1, y1 );
}
}
else
{
if (x1 > x2)
{
ssd1306_swap_data(x1, x2, lcdint_t);
ssd1306_swap_data(y1, y2, lcdint_t);
}
for(; x1<=x2; x1++)
{
err += dy;
if (err >= dx)
{
err -= dx;
if (y1 < y2) y1++; else y1--;
}
ssd1306_putPixel16( x1, y1 );
}
}
}
void ssd1306_drawRect16(lcdint_t x1, lcdint_t y1, lcdint_t x2, lcdint_t y2)
{
ssd1306_drawHLine16(x1,y1,x2);
ssd1306_drawHLine16(x1,y2,x2);
ssd1306_drawVLine16(x1,y1,y2);
ssd1306_drawVLine16(x2,y1,y2);
}
void ssd1306_fillRect16(lcdint_t x1, lcdint_t y1, lcdint_t x2, lcdint_t y2)
{
if (y1 > y2)
{
ssd1306_swap_data(y1, y2, lcdint_t);
}
if (x1 > x2)
{
ssd1306_swap_data(x1, x2, lcdint_t);
}
ssd1306_lcd.set_block(x1, y1, x2 - x1 + 1);
uint16_t count = (x2 - x1 + 1) * (y2 - y1 + 1);
while (count--)
{
ssd1306_lcd.send_pixels16( ssd1306_color );
}
ssd1306_intf.stop();
}
void ssd1306_drawMonoBitmap16(lcdint_t xpos, lcdint_t ypos, lcduint_t w, lcduint_t h, const uint8_t *bitmap)
{
uint8_t bit = 1;
uint16_t blackColor = s_ssd1306_invertByte ? ssd1306_color : 0x00;
uint16_t color = s_ssd1306_invertByte ? 0x00 : ssd1306_color;
ssd1306_lcd.set_block(xpos, ypos, w);
while (h--)
{
lcduint_t wx = w;
while ( wx-- )
{
uint8_t data = pgm_read_byte( bitmap );
if ( data & bit )
ssd1306_lcd.send_pixels16( color );
else
ssd1306_lcd.send_pixels16( blackColor );
bitmap++;
}
bit <<= 1;
if ( bit == 0 )
{
bit = 1;
}
else
{
bitmap -= w;
}
}
ssd1306_intf.stop();
}
void ssd1306_drawBitmap16(lcdint_t xpos, lcdint_t ypos, lcduint_t w, lcduint_t h, const uint8_t *bitmap)
{
ssd1306_lcd.set_block(xpos, ypos, w);
uint32_t count = (w) * (h);
while (count--)
{
ssd1306_lcd.send_pixels16( (pgm_read_byte( &bitmap[0] ) << 8) | pgm_read_byte( &bitmap[1] ) );
bitmap += 2;
}
ssd1306_intf.stop();
}
void ssd1306_clearBlock16(uint8_t x, uint8_t y, uint8_t w, uint8_t h)
{
ssd1306_lcd.set_block(x, y, w);
uint32_t count = w * h;
while (count--)
{
ssd1306_lcd.send_pixels16( 0x0000 );
}
ssd1306_intf.stop();
}
void ssd1306_setCursor16(lcduint_t x, lcduint_t y)
{
ssd1306_cursorX = x;
ssd1306_cursorY = y;
}
void ssd1306_printChar16(uint8_t c)
{
uint16_t unicode = ssd1306_unicode16FromUtf8(c);
if (unicode == SSD1306_MORE_CHARS_REQUIRED) return;
SCharInfo char_info;
ssd1306_getCharBitmap(unicode, &char_info);
ssd1306_drawMonoBitmap16(ssd1306_cursorX,
ssd1306_cursorY,
char_info.width,
char_info.height,
char_info.glyph );
}
size_t ssd1306_write16(uint8_t ch)
{
if (ch == '\r')
{
ssd1306_cursorX = 0;
return 0;
}
SCharInfo char_info;
uint8_t gotoNewLine = 1;
if (ch != '\n')
{
uint16_t unicode = ssd1306_unicode16FromUtf8(ch);
if (unicode == SSD1306_MORE_CHARS_REQUIRED) return 0;
ssd1306_getCharBitmap(unicode, &char_info);
gotoNewLine = (ssd1306_cursorX > (ssd1306_lcd.width - char_info.width));
}
if ( gotoNewLine )
{
ssd1306_cursorX = 0;
ssd1306_cursorY += s_fixedFont.h.height;
if ( ssd1306_cursorY > ssd1306_lcd.height - s_fixedFont.h.height )
{
ssd1306_cursorY = 0;
}
ssd1306_clearBlock16(0, ssd1306_cursorY, ssd1306_lcd.width, s_fixedFont.h.height);
if (ch == '\n')
{
return 0;
}
}
if ( 1 )
{
uint16_t color = ssd1306_color;
ssd1306_color = s_ssd1306_invertByte ? color : 0x0000;
ssd1306_fillRect16( ssd1306_cursorX, ssd1306_cursorY,
ssd1306_cursorX + char_info.width + char_info.spacing - 1,
ssd1306_cursorY + s_fixedFont.h.height - 1 );
ssd1306_color = color;
}
ssd1306_drawMonoBitmap16( ssd1306_cursorX,
ssd1306_cursorY,
char_info.width,
char_info.height,
char_info.glyph);
ssd1306_cursorX += char_info.width + char_info.spacing;
return 1;
}
size_t ssd1306_print16(const char ch[])
{
size_t n = 0;
while (*ch)
{
n += ssd1306_write16(*ch);
ch++;
}
return n;
}
uint8_t ssd1306_printFixed16(lcdint_t x, lcdint_t y, const char *ch, EFontStyle style)
{
ssd1306_cursorX = x;
ssd1306_cursorY = y;
return ssd1306_print16(ch);
}
+303
View File
@@ -0,0 +1,303 @@
/*
MIT License
Copyright (c) 2018-2019, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* @file ssd1306_16bit.h 16-bit specific draw functions
*/
#ifndef _SSD1306_16BIT_H_
#define _SSD1306_16BIT_H_
#include "nano_gfx_types.h"
#ifdef __cplusplus
extern "C" {
#endif
///////////////////////////////////////////////////////////////////////
// DIRECT GRAPH FUNCTIONS
///////////////////////////////////////////////////////////////////////
/**
* @defgroup LCD_16BIT_GRAPHICS DIRECT DRAW: 16-bit API functions only for color displays
* @{
*
* @brief LCD direct draw functions only for color display.
*
* @details LCD direct draw functions are applicable for color display types. These functions will NOT work
* in ssd1306 compatible mode. Use ssd1306_setMode() function to change display mode to NORMAL.
* You can combine combine NanoEngine capabilities with these functions.
* Direct draw functions draw directly in GDRAM and do not use any double-buffering.
*/
/**
* @brief Sets default color.
*
* Sets default color for monochrome operations.
* This function supports only 16-bit RGB mode.
* To work with RGB colors in 8-bit mode, please refer to ssd1306_setRgbColor8() function
* and RGB_COLOR8 macros.
* @param r - red in 0-255 range.
* @param g - green in 0-255 range.
* @param b - blue in 0-255 range.
*/
void ssd1306_setRgbColor16(uint8_t r, uint8_t g, uint8_t b);
/**
* Draws 16-bit bitmap, located in SRAM, on the display
* Each byte represents separate pixel: refer to RGB_COLOR16 to understand RGB scheme, being used.
*
* @param x - horizontal position in pixels
* @param y - vertical position in pixels
* @param w - width of bitmap in pixels
* @param h - height of bitmap in pixels
* @param data - pointer to data, located in SRAM.
*/
void ssd1306_drawBufferFast16(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *data);
#ifndef DOXYGEN_SHOULD_SKIP_THIS
static inline void ssd1331_drawBufferFast16(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *data)
{
ssd1306_drawBufferFast16(x, y, w, h, data);
}
#endif
/**
* Draws 16-bit bitmap, located in SRAM, on the display, taking into account pitch parameter.
* Each byte represents separate pixel: refer to RGB_COLOR16 to understand RGB scheme, being used.
* pitch parameter specifies, length of single line in bytes.
*
* @param x - horizontal position in pixels
* @param y - vertical position in pixels
* @param w - width of bitmap in pixels
* @param h - height of bitmap in pixels
* @param pitch length of bitmap buffer line in bytes
* @param data - pointer to data, located in SRAM.
*/
void ssd1306_drawBufferEx16(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, lcduint_t pitch, const uint8_t *data);
/**
* Draws 1-bit bitmap, located in SRAM, on the display
* Each bit represents separate pixel: refer to ssd1306 datasheet for more information.
*
* @param xpos horizontal position in pixels
* @param ypos vertical position in pixels
* @param w width of bitmap in pixels
* @param h height of bitmap in pixels
* @param bitmap pointer to data, located in SRAM.
*/
void ssd1306_drawMonoBuffer16(lcdint_t xpos, lcdint_t ypos, lcduint_t w, lcduint_t h, const uint8_t *bitmap);
/**
* Fills screen with pattern byte
*
* @param fill_Data pattern color to fill screen with
*/
void ssd1306_fillScreen16(uint16_t fill_Data);
/**
* Fills screen with zero-byte
*/
void ssd1306_clearScreen16(void);
/**
* Puts single color point directly in OLED display GDRAM.
*
* @param x - horizontal position in pixels
* @param y - vertical position in pixels
*
* @note set color with ssd1306_setColor() function.
*/
void ssd1306_putPixel16(lcdint_t x, lcdint_t y);
/**
* Puts single color point directly in OLED display GDRAM.
*
* @param x - horizontal position in pixels
* @param y - vertical position in pixels
* @param color color in 16-bit format: 5-6-5
*/
void ssd1306_putColorPixel16(lcdint_t x, lcdint_t y, uint16_t color);
/**
* Draw vertical line directly in OLED display GDRAM.
*
* @param x1 - horizontal position in pixels
* @param y1 - top vertical position in pixels
* @param y2 - bottom vertical position in pixels
*
* @note set color with ssd1306_setColor() function.
*/
void ssd1306_drawVLine16(lcdint_t x1, lcdint_t y1, lcdint_t y2);
/**
* Draw horizontal line directly in OLED display GDRAM.
*
* @param x1 - left position in pixels
* @param y1 - vertical vertical position in pixels
* @param x2 - right position in pixels
*
* @note set color with ssd1306_setColor() function.
*/
void ssd1306_drawHLine16(lcdint_t x1, lcdint_t y1, lcdint_t x2);
/**
* Draw line directly in OLED display GDRAM.
* This is software implementation. Some OLED controllers have hardware implementation.
* Refer to datasheet.
*
* @param x1 - start horizontal position in pixels
* @param y1 - start vertical position in pixels
* @param x2 - end horizontal position in pixels
* @param y2 - end vertical position in pixels
*
* @note set color with ssd1306_setColor() function.
*/
void ssd1306_drawLine16(lcdint_t x1, lcdint_t y1, lcdint_t x2, lcdint_t y2);
/**
* Draw rectangle directly in OLED display GDRAM.
* This is software implementation. Some OLED controllers have hardware implementation.
* Refer to datasheet.
*
* @param x1 - start horizontal position in pixels
* @param y1 - start vertical position in pixels
* @param x2 - end horizontal position in pixels
* @param y2 - end vertical position in pixels
*
* @note set color with ssd1306_setColor() function.
*/
void ssd1306_drawRect16(lcdint_t x1, lcdint_t y1, lcdint_t x2, lcdint_t y2);
/**
* Fill rectangle directly in OLED display GDRAM.
* This is software implementation. Some OLED controllers have hardware implementation.
* Refer to datasheet.
*
* @param x1 - start horizontal position in pixels
* @param y1 - start vertical position in pixels
* @param x2 - end horizontal position in pixels
* @param y2 - end vertical position in pixels
*
* @note set color with ssd1306_setColor() function.
*/
void ssd1306_fillRect16(lcdint_t x1, lcdint_t y1, lcdint_t x2, lcdint_t y2);
/**
* Draw monochrome bitmap, located in Flash, directly to OLED display GDRAM.
* The bitmap should be in ssd1306 format (each byte represents 8 vertical pixels)
*
* @param xpos start horizontal position in pixels
* @param ypos start vertical position in pixels
* @param w bitmap width in pixels
* @param h bitmap height in pixels
* @param bitmap pointer to Flash data, containing monochrome bitmap.
*
* @note set color with ssd1306_setColor() function.
*/
void ssd1306_drawMonoBitmap16(lcdint_t xpos, lcdint_t ypos, lcduint_t w, lcduint_t h, const uint8_t *bitmap);
/**
* Draw 16-bit color bitmap, located in Flash, directly to OLED display GDRAM.
* Each pixel of the bitmap is expected in 5-6-5 format.
*
* @param xpos start horizontal position in pixels
* @param ypos start vertical position in pixels
* @param w bitmap width in pixels
* @param h bitmap height in pixels
* @param bitmap pointer to Flash data, containing 16-bit color bitmap.
*/
void ssd1306_drawBitmap16(lcdint_t xpos, lcdint_t ypos, lcduint_t w, lcduint_t h, const uint8_t *bitmap);
/**
* Clears block, filling it with black pixels, directly in OLED display GDRAM.
*
* @param x start horizontal position in pixels
* @param y start vertical position in pixels
* @param w block width in pixels
* @param h block height in pixels
*/
void ssd1306_clearBlock16(uint8_t x, uint8_t y, uint8_t w, uint8_t h);
/**
* Set cursor position for text functions
*
* @param x horizontal position in pixels.
* @param y vertical position in pixels.
*/
void ssd1306_setCursor16(lcduint_t x, lcduint_t y);
/**
* Draws single character to canvas. Cursor position is defined
* by ssd1306_setCursor16(). Do not changes cursor position
*
* @param c - character code to print
*
* @note set color with ssd1306_setColor() function.
*/
void ssd1306_printChar16(uint8_t c);
/**
* @brief Prints single character to display at current cursor position
*
* Prints single character to display at current cursor position.
* Cursor position can be set by ssd1306_setCursor16().
*
* @param ch - character to print to the display. 'LF' and 'CR' are skipped
* @return returns number of printed characters.
*/
size_t ssd1306_write16(uint8_t ch);
/**
* @brief Prints null-terminated string to display at current cursor position
*
* Prints null-terminated string to display at current cursor position
* Cursor position can be set by ssd1306_setCursor16().
*
* @param ch - string to print to the display. 'LF' and 'CR' are skipped
* @return returns number of printed characters.
*/
size_t ssd1306_print16(const char ch[]);
/**
* Prints text to screen using fixed font.
* @param x horizontal position in pixels
* @param y vertical position in pixels
* @param ch NULL-terminated string to print
* @param style font style (EFontStyle), normal by default (not implemented).
* @returns number of chars in string
*
* @see ssd1306_setFixedFont
* @note set color with ssd1306_setColor() function.
*/
uint8_t ssd1306_printFixed16(lcdint_t x, lcdint_t y, const char *ch, EFontStyle style);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif // _SSD1306_16BIT_H_
File diff suppressed because it is too large Load Diff
+458
View File
@@ -0,0 +1,458 @@
/*
MIT License
Copyright (c) 2016-2019, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* @file ssd1306_1bit.h SSD1306 basic draw functions
*/
#ifndef _SSD1306_1BIT_H_
#define _SSD1306_1BIT_H_
#include "nano_gfx_types.h"
#ifdef __cplusplus
extern "C" {
#endif
///////////////////////////////////////////////////////////////////////
// DIRECT GRAPH FUNCTIONS
///////////////////////////////////////////////////////////////////////
/**
* @defgroup LCD_1BIT_GRAPHICS DIRECT DRAW: 1-bit graphic functions for ssd1306 compatible mode.
* @{
* @brief LCD direct draw functions for all display types: color and monochrome.
*
* @details LCD direct draw functions are applicable for all display types. These functions will work
* both for monochrome and 8-bit/16-bit color OLED displays. You need remember, that for RGB
* oled displays these functions work only in special ssd1306 compatible mode. If you're going to
* combine NanoEngine capabilities with these functions, don't forget to switch addressing
* mode via ssd1306_setMode().
* Direct draw functions draw directly in GDRAM and do not use any double-buffering.
*/
/**
* Fills screen with pattern byte
*/
void ssd1306_fillScreen(uint8_t fill_Data);
/**
* Fills screen with zero-byte
*/
void ssd1306_clearScreen(void);
/**
* All drawing functions start to work in negative mode.
* Old picture on the display remains unchanged.
*/
void ssd1306_negativeMode(void);
/**
* All drawing functions start to work in positive (default) mode.
* Old picture on the display remains unchanged.
*/
void ssd1306_positiveMode(void);
/**
* Prints text to screen using fixed font.
* @param xpos - horizontal position in pixels
* @param y - vertical position in pixels
* @param ch - NULL-terminated string to print
* @param style - font style (EFontStyle), normal by default.
* @returns number of chars in string
* @see ssd1306_setFixedFont
* @warning ssd1306_printFixed() can output chars at fixed y positions: 0, 8, 16, 24, 32, etc.
* If you specify [10,18], ssd1306_printFixed() will output text starting at [10,16] position.
* @warning Be careful with you flash space! Do not mix too many different functions in single sketch.
* ssd1306_printFixedN() uses much flash: ~396 bytes, ssd1306_printFixed() needs 388 bytes.
* Placing both of these functions to your sketch will consume almost 1KiB.
*/
uint8_t ssd1306_printFixed(uint8_t xpos, uint8_t y, const char *ch, EFontStyle style);
#ifndef DOXYGEN_SHOULD_SKIP_THIS
uint8_t ssd1306_printFixed_oldStyle(uint8_t xpos, uint8_t y, const char *ch, EFontStyle style);
#endif
/**
* Prints text to screen using double size fixed font.
* @param xpos - horizontal position in pixels
* @param y - vertical position in pixels
* @param ch - NULL-terminated string to print
* @param style - font style (EFontStyle), normal by default.
* @returns number of chars in string
* @see ssd1306_setFixedFont
* @warning ssd1306_printFixed2x() can output chars at fixed y positions: 0, 8, 16, 24, 32, etc.
* If you specify [10,18], ssd1306_printFixed2x() will output text starting at [10,16] position.
* @warning Be careful with you flash space! Do not mix too many different functions in single sketch.
* ssd1306_printFixedN() uses much flash: ~474 bytes, ssd1306_printFixed() needs 388 bytes.
* Placing both of these functions to your sketch will consume almost 1KiB.
* @deprecated Use ssd1306_printFixedN() instead.
*/
uint8_t ssd1306_printFixed2x(uint8_t xpos, uint8_t y, const char ch[], EFontStyle style) __attribute__ ((deprecated));
/**
* Prints text to screen using size fixed font, scaled by factor value. <br>
* Factor value 0 gives regular font size (6x8 for example) <br>
* Factor value 1 gives double font size (12x16 if 6x8 font is used) <br>
* Factor value 2 gives fourth font size (24x32 if 6x8 font is used) <br>
* Factor value 3 gives eighth font size (48x64 if 6x8 font is used) <br>
* @param xpos - horizontal position in pixels
* @param y - vertical position in pixels
* @param ch - NULL-terminated string to print
* @param style - font style (EFontStyle), normal by default.
* @param factor - 0, 1, 2, 3.
* @returns number of chars in string
* @see ssd1306_setFixedFont
* @warning ssd1306_printFixed2x() can output chars at fixed y positions: 0, 8, 16, 24, 32, etc.
* If you specify [10,18], ssd1306_printFixed2x() will output text starting at [10,16] position.
* @warning Be careful with you flash space! Do not mix too many different functions in single sketch.
* ssd1306_printFixedN() uses much flash: ~474 bytes, ssd1306_printFixed() needs 388 bytes.
* Placing both of these functions to your sketch will consume almost 1KiB.
*/
uint8_t ssd1306_printFixedN(uint8_t xpos, uint8_t y, const char ch[], EFontStyle style, uint8_t factor);
/**
* @brief Prints single character to display at current cursor position
*
* Prints single character to display at current cursor position
* @param ch - character to print to the display. 'LF' and 'CR' are skipped
* @return returns number of printed characters.
*/
size_t ssd1306_write(uint8_t ch);
/**
* @brief Prints null-terminated string to display at current cursor position
*
* Prints null-terminated string to display at current cursor position
* @param ch - string to print to the display. 'LF' and 'CR' are skipped
* @return returns number of printed characters.
*/
size_t ssd1306_print(const char ch[]);
/**
* Prints text to screen using font 6x8.
* @param x - horizontal position in pixels
* @param y - vertical position in blocks (pixels/8)
* @param ch - NULL-terminated string to print
* @param style - font style (EFontStyle), normal by default.
* @returns number of chars in string
* @deprecated Use ssd1306_printFixed() instead.
*/
uint8_t ssd1306_charF6x8(uint8_t x, uint8_t y,
const char ch[],
EFontStyle style
#ifdef __cplusplus
= STYLE_NORMAL
#endif
) __attribute__ ((deprecated));
/**
* Prints text to screen using double size font 12x16.
* @param xpos - horizontal position in pixels
* @param y - vertical position in blocks (pixels/8)
* @param ch - NULL-terminated string to print
* @param style - font style (EFontStyle).
* @returns number of chars in string
* @deprecated Use ssd1306_drawFixedN() instead.
*/
uint8_t ssd1306_charF12x16(uint8_t xpos,
uint8_t y,
const char ch[],
EFontStyle style) __attribute__ ((deprecated));
/**
* Prints text to screen using set font.
* If real text ends before right boundary,
* the remaining part on the display will be erased till right
* boundary.
* @param left - horizontal position in pixels
* @param y - vertical position in blocks (pixels/8)
* @param ch - NULL-terminated string to print
* @param style - font style (EFontStyle), normal by default.
* @param right - right boundary of the text to output
* @returns number of chars in string
* @deprecated This function is removed as superflouse.
*/
uint8_t ssd1306_charF6x8_eol(uint8_t left,
uint8_t y,
const char ch[],
EFontStyle style,
uint8_t right) __attribute__ ((deprecated));
/**
* Put single pixel on the LCD.
*
* @warning Please, take into account that there is no way
* to read data from ssd1306, thus since each byte contains
* 8 pixels, all other pixels in the same byte will be cleared
* on the display. Use ssd1306_putPixels() instead.
* If you need to have buffered output, please, refer to NanoCanvas.
*
* @param x - horizontal position in pixels
* @param y - vertical position in pixels
*/
void ssd1306_putPixel(uint8_t x, uint8_t y);
/**
* Puts eight vertical pixels on the LCD at once.
*
* ~~~~~~~~~~~~~~~{.c}
* // Draw 8 vertical pixels, starting at [10,16] position
* ssd1306_putPixels(10,2,0xFF);
* // Draw 4 vertical pixels, starting at [32,28] position
* ssd1306_putPixels(32,3,0x0F);
* ~~~~~~~~~~~~~~~
*
* @param x - horizontal position in pixels
* @param y - vertical position pixels. Should be multiply of 8.
* @param pixels - bit-pixels to draw on display
*/
void ssd1306_putPixels(uint8_t x, uint8_t y, uint8_t pixels);
/**
* Draws rectangle
* @param x1 - left boundary in pixel units
* @param y1 - top boundary in pixel units
* @param x2 - right boundary in pixel units
* @param y2 - bottom boundary int pixel units
*/
void ssd1306_drawRect(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2);
/**
* Fill rectangle directly in OLED display GDRAM.
* This is software implementation. Some OLED controllers have hardware implementation.
* Refer to datasheet.
*
* @param x1 - start horizontal position in pixels
* @param y1 - start vertical position in pixels
* @param x2 - end horizontal position in pixels
* @param y2 - end vertical position in pixels
*
* @note set color with ssd1306_setColor() function.
*/
void ssd1306_fillRect(lcdint_t x1, lcdint_t y1, lcdint_t x2, lcdint_t y2);
/**
* Draws line
* @param x1 - x position in pixels of start point
* @param y1 - y position in pixels of start point
* @param x2 - x position in pixels of end point
* @param y2 - y position in pixels of end point
*
* @warning Remember that this function draws line directly in GDRAM of oled controller.
* Since there is no way to detect pixels already being displayed, some pixels
* can be overwritten by black color. If you use RGB oled, based on ssd1331 controller,
* use ssd1331_drawLine() function.
*/
void ssd1306_drawLine(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2);
/**
* Draws horizontal line
* @param x1 - left boundary in pixels
* @param y1 - position Y in pixels
* @param x2 - right boundary in pixels
*/
void ssd1306_drawHLine(uint8_t x1, uint8_t y1, uint8_t x2);
/**
* Draws vertical line
* @param x1 - position X in pixels
* @param y1 - top boundary in pixels
* @param y2 - bottom boundary in pixels
*/
void ssd1306_drawVLine(uint8_t x1, uint8_t y1, uint8_t y2);
/**
* Draws bitmap, located in SRAM, on the display
* Each byte represents 8 vertical pixels.
*
* ~~~~~~~~~~~~~~~{.c}
* // Draw small rectangle 3x8 at position 10,8
* uint8_t buffer[3] = { 0xFF, 0x81, 0xFF };
* ssd1306_drawBuffer(10, 1, 3, 8, buffer);
* ~~~~~~~~~~~~~~~
*
* @param x - horizontal position in pixels
* @param y - vertical position in blocks (pixels/8)
* @param w - width of bitmap in pixels
* @param h - height of bitmap in pixels (must be divided by 8)
* @param buf - pointer to data, located in SRAM: each byte represents 8 vertical pixels.
*/
void ssd1306_drawBuffer(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *buf);
/**
* Draws bitmap, located in SRAM, on the display
* Each byte represents 2 horizontal grayscale pixels.
*
* @param x - horizontal position in pixels
* @param y - vertical position in pixels
* @param w - width of bitmap in pixels
* @param h - height of bitmap in pixels (must be divided by 8)
* @param buf - pointer to data, located in SRAM: each byte represents 2 horizontal pixels.
*/
void ssd1306_drawBuffer1_4(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *buf);
/**
* Draws bitmap, located in SRAM, on the display
* Each byte represents 8 vertical pixels.
*
* ~~~~~~~~~~~~~~~{.c}
* // Draw small rectangle 3x8 at position 10,8
* uint8_t buffer[3] = { 0xFF, 0x81, 0xFF };
* ssd1306_drawBuffer(10, 1, 3, 8, buffer);
* ~~~~~~~~~~~~~~~
*
* @param x - horizontal position in pixels
* @param y - vertical position in pixels (must be devided by 8)
* @param w - width of bitmap in pixels
* @param h - height of bitmap in pixels (must be divided by 8)
* @param buf - pointer to data, located in SRAM: each byte represents 8 vertical pixels.
*
* @note ssd1306_drawBufferFast() doesn't support negative draw mode. Use ssd1306_drawBuffer() instead.
*/
void ssd1306_drawBufferFast(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *buf);
/**
* @copydoc ssd1306_drawBuffer
*/
#define ssd1306_drawCanvas(x, y, w, h, buf) ssd1306_drawBuffer(x, y, w, h, buf)
/**
* Draws bitmap, located in Flash, on the display
* The bitmap should be in native ssd1306 format
*
* @param x - horizontal position in pixels
* @param y - vertical position in blocks (pixels/8)
* @param w - width of bitmap in pixels
* @param h - height of bitmap in pixels (must be divided by 8)
* @param buf - pointer to data, located in Flash: each byte represents 8 vertical pixels.
*/
void ssd1306_drawBitmap(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *buf);
/**
* Draws bitmap, located in Flash, on the display
* The bitmap should be in XBMP format
*
* @param x - horizontal position in pixels
* @param y - vertical position in blocks (pixels/8)
* @param w - width of bitmap in pixels
* @param h - height of bitmap in pixels (must be divided by 8)
* @param buf - pointer to data, located in Flash: each byte represents 8 vertical pixels.
*/
void ssd1306_drawXBitmap(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *buf);
/**
* Draw bitmap, located in Flash, on the display
* The bitmap should be in in grayscale 4-bit format:
* ROW 1: 222211114444333366665555...
* ROW 2: 222211114444333366665555...
* ...
* ROW N: 222211114444333366665555...
*
* @param x - horizontal position in pixels
* @param y - vertical position in pixels
* @param w - width of bitmap in pixels
* @param h - height of bitmap in pixels (must be divided by 8)
* @param buf - pointer to data, located in Flash.
*/
void ssd1306_drawBitmap1_4(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *buf);
/**
* Draws bitmap, located in Flash, on the display
*
* @param x - horizontal position in pixels
* @param y - vertical position in pixels
* @param w - width of bitmap in pixels
* @param h - height of bitmap in pixels (must be divided by 8)
* @param buf - pointer to data, located in Flash: each byte represents 8 vertical pixels.
*/
void gfx_drawMonoBitmap(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *buf);
/**
* Fills block with black pixels
* @param x - horizontal position in pixels
* @param y - vertical position in blocks (pixels/8)
* @param w - width of block in pixels
* @param h - height of block in pixels (must be divided by 8)
* @note usually this method is used to erase bitmap on the screen.
*/
void ssd1306_clearBlock(uint8_t x, uint8_t y, uint8_t w, uint8_t h);
/**
* Draws bitmap, located in Flash, on the display. This sprite must have wx8 size
* @param x - horizontal position in pixels
* @param y - vertical position in blocks (pixels/8)
* @param w - width in pixels
* @param sprite - pointer to data, located in Flash: each byte represents 8 vertical pixels.
*/
void ssd1306_drawSpriteEx(uint8_t x, uint8_t y, uint8_t w, const uint8_t *sprite);
/**
* Draws sprite on the display. Position can be changed by
* updating x and y fields of SPRITE structure.
* @param sprite - pointer to SPRITE structure
*/
void ssd1306_drawSprite(SPRITE *sprite);
/**
* Clears sprite from the display leaving black rectangle.
* @param sprite - pointer to SPRITE structure
*/
void ssd1306_eraseSprite(SPRITE *sprite);
/**
* Clears some sprite parts in old position on the display.
* @param sprite - pointer to SPRITE structure
*/
void ssd1306_eraseTrace(SPRITE *sprite);
/**
* Creates sprite object. Sprite height is fixed to 8 pixels
* @param x - horizontal position in pixels
* @param y - vertical position in pixels
* @param w - width of sprite in pixels
* @param data - pointer to data, located in Flash: each byte represents 8 vertical pixels.
* @return SPRITE structure
*/
SPRITE ssd1306_createSprite(uint8_t x, uint8_t y, uint8_t w, const uint8_t *data);
/**
* Replaces image of the sprite with different data. The width must be the same as
* the width of original sprite image
* @param sprite - pointer to SPRITE structure
* @param data - pointer to data, located in Flash: each byte represents 8 vertical pixels.
*/
void ssd1306_replaceSprite(SPRITE *sprite, const uint8_t *data);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif // _SSD1306_1BIT_H_
+378
View File
@@ -0,0 +1,378 @@
/*
MIT License
Copyright (c) 2018-2019, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "ssd1306_8bit.h"
#include "ssd1306_generic.h"
//#include "ssd1306_fonts.h"
#include "intf/ssd1306_interface.h"
#include "intf/spi/ssd1306_spi.h"
#include "ssd1306_hal/io.h"
#include "lcd/ssd1331_commands.h"
#include "lcd/lcd_common.h"
extern uint16_t ssd1306_color;
extern uint8_t s_ssd1306_invertByte;
extern lcduint_t ssd1306_cursorX;
extern lcduint_t ssd1306_cursorY;
extern SFixedFontInfo s_fixedFont;
#ifdef CONFIG_SSD1306_UNICODE_ENABLE
extern uint8_t g_ssd1306_unicode;
#endif
void ssd1306_setColor(uint16_t color)
{
ssd1306_color = color;
}
void ssd1306_setRgbColor(uint8_t r, uint8_t g, uint8_t b)
{
ssd1306_color = RGB_COLOR8(r,g,b);
}
void ssd1306_setRgbColor8(uint8_t r, uint8_t g, uint8_t b)
{
ssd1306_color = RGB_COLOR8(r,g,b);
}
void ssd1306_drawMonoBuffer8(lcdint_t xpos, lcdint_t ypos, lcduint_t w, lcduint_t h, const uint8_t *bitmap)
{
uint8_t bit = 1;
uint8_t blackColor = s_ssd1306_invertByte ? ssd1306_color : 0x00;
uint8_t color = s_ssd1306_invertByte ? 0x00 : ssd1306_color;
ssd1306_lcd.set_block(xpos, ypos, w);
while (h--)
{
lcduint_t wx = w;
while (wx--)
{
uint8_t data = *bitmap;
if ( data & bit )
ssd1306_lcd.send_pixels8( color );
else
ssd1306_lcd.send_pixels8( blackColor );
bitmap++;
}
bit <<= 1;
if (bit == 0)
{
bit = 1;
}
else
{
bitmap -= w;
}
}
ssd1306_intf.stop();
}
static void ssd1306_drawBufferPitch8(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, lcduint_t pitch, const uint8_t *data)
{
ssd1306_lcd.set_block(x, y, w);
while (h--)
{
lcduint_t line = w;
while (line--)
{
ssd1306_lcd.send_pixels8( *data );
data++;
}
data += pitch - w;
}
ssd1306_intf.stop();
}
void ssd1306_drawBufferFast8(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *data)
{
ssd1306_drawBufferPitch8( x, y, w, h, w, data );
}
void ssd1306_drawBufferEx8(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, lcduint_t pitch, const uint8_t *data)
{
ssd1306_drawBufferPitch8( x, y, w, h, pitch, data );
}
void ssd1306_fillScreen8(uint8_t fill_Data)
{
ssd1306_lcd.set_block(0, 0, 0);
uint32_t count = (uint32_t)ssd1306_lcd.width * (uint32_t)ssd1306_lcd.height;
while (count--)
{
ssd1306_lcd.send_pixels8( fill_Data );
}
ssd1306_intf.stop();
}
void ssd1306_clearScreen8(void)
{
ssd1306_fillScreen8( 0x00 );
}
void ssd1306_putPixel8(lcdint_t x, lcdint_t y)
{
ssd1306_lcd.set_block(x, y, 0);
ssd1306_lcd.send_pixels8( ssd1306_color );
ssd1306_intf.stop();
}
void ssd1306_putColorPixel8(lcdint_t x, lcdint_t y, uint8_t color)
{
ssd1306_lcd.set_block(x, y, 0);
ssd1306_lcd.send_pixels8( color );
ssd1306_intf.stop();
}
void ssd1306_drawVLine8(lcdint_t x1, lcdint_t y1, lcdint_t y2)
{
ssd1306_lcd.set_block(x1, y1, 1);
while (y1<=y2)
{
ssd1306_lcd.send_pixels8( ssd1306_color );
y1++;
}
ssd1306_intf.stop();
}
void ssd1306_drawHLine8(lcdint_t x1, lcdint_t y1, lcdint_t x2)
{
ssd1306_lcd.set_block(x1, y1, 0);
while (x1 < x2)
{
ssd1306_lcd.send_pixels8( ssd1306_color );
x1++;
}
ssd1306_intf.stop();
}
void ssd1306_drawLine8(lcdint_t x1, lcdint_t y1, lcdint_t x2, lcdint_t y2)
{
lcduint_t dx = x1 > x2 ? (x1 - x2): (x2 - x1);
lcduint_t dy = y1 > y2 ? (y1 - y2): (y2 - y1);
lcduint_t err = 0;
if (dy > dx)
{
if (y1 > y2)
{
ssd1306_swap_data(x1, x2, lcdint_t);
ssd1306_swap_data(y1, y2, lcdint_t);
}
for(; y1<=y2; y1++)
{
err += dx;
if (err >= dy)
{
err -= dy;
x1 < x2 ? x1++: x1--;
}
ssd1306_putPixel8( x1, y1 );
}
}
else
{
if (x1 > x2)
{
ssd1306_swap_data(x1, x2, lcdint_t);
ssd1306_swap_data(y1, y2, lcdint_t);
}
for(; x1<=x2; x1++)
{
err += dy;
if (err >= dx)
{
err -= dx;
if (y1 < y2) y1++; else y1--;
}
ssd1306_putPixel8( x1, y1 );
}
}
}
void ssd1306_drawRect8(lcdint_t x1, lcdint_t y1, lcdint_t x2, lcdint_t y2)
{
ssd1306_drawHLine8(x1,y1,x2);
ssd1306_drawHLine8(x1,y2,x2);
ssd1306_drawVLine8(x1,y1,y2);
ssd1306_drawVLine8(x2,y1,y2);
}
void ssd1306_fillRect8(lcdint_t x1, lcdint_t y1, lcdint_t x2, lcdint_t y2)
{
if (y1 > y2)
{
ssd1306_swap_data(y1, y2, lcdint_t);
}
if (x1 > x2)
{
ssd1306_swap_data(x1, x2, lcdint_t);
}
ssd1306_lcd.set_block(x1, y1, x2 - x1 + 1);
uint16_t count = (x2 - x1 + 1) * (y2 - y1 + 1);
while (count--)
{
ssd1306_lcd.send_pixels8( ssd1306_color );
}
ssd1306_intf.stop();
}
void ssd1306_drawMonoBitmap8(lcdint_t xpos, lcdint_t ypos, lcduint_t w, lcduint_t h, const uint8_t *bitmap)
{
uint8_t bit = 1;
uint8_t blackColor = s_ssd1306_invertByte ? ssd1306_color : 0x00;
uint8_t color = s_ssd1306_invertByte ? 0x00 : ssd1306_color;
ssd1306_lcd.set_block(xpos, ypos, w);
while (h--)
{
lcduint_t wx = w;
while ( wx-- )
{
uint8_t data = pgm_read_byte( bitmap );
if ( data & bit )
ssd1306_lcd.send_pixels8( color );
else
ssd1306_lcd.send_pixels8( blackColor );
bitmap++;
}
bit <<= 1;
if ( bit == 0 )
{
bit = 1;
}
else
{
bitmap -= w;
}
}
ssd1306_intf.stop();
}
void ssd1306_drawBitmap8(lcdint_t xpos, lcdint_t ypos, lcduint_t w, lcduint_t h, const uint8_t *bitmap)
{
ssd1306_lcd.set_block(xpos, ypos, w);
uint32_t count = (w) * (h);
while (count--)
{
ssd1306_lcd.send_pixels8( pgm_read_byte( bitmap ) );
bitmap++;
}
ssd1306_intf.stop();
}
void ssd1306_clearBlock8(uint8_t x, uint8_t y, uint8_t w, uint8_t h)
{
ssd1306_lcd.set_block(x, y, w);
uint32_t count = w * h;
while (count--)
{
ssd1306_lcd.send_pixels8( 0x00 );
}
ssd1306_intf.stop();
}
void ssd1306_setCursor8(lcduint_t x, lcduint_t y)
{
ssd1306_cursorX = x;
ssd1306_cursorY = y;
}
void ssd1306_printChar8(uint8_t c)
{
uint16_t unicode = ssd1306_unicode16FromUtf8(c);
if (unicode == SSD1306_MORE_CHARS_REQUIRED) return;
SCharInfo char_info;
ssd1306_getCharBitmap(unicode, &char_info);
ssd1306_drawMonoBitmap8(ssd1306_cursorX,
ssd1306_cursorY,
char_info.width,
char_info.height,
char_info.glyph );
}
size_t ssd1306_write8(uint8_t ch)
{
if (ch == '\r')
{
ssd1306_cursorX = 0;
return 0;
}
SCharInfo char_info;
uint8_t gotoNewLine = 1;
if (ch != '\n')
{
uint16_t unicode;
unicode = ssd1306_unicode16FromUtf8(ch);
if (unicode == SSD1306_MORE_CHARS_REQUIRED) return 0;
ssd1306_getCharBitmap(unicode, &char_info);
gotoNewLine = (ssd1306_cursorX > (ssd1306_lcd.width - char_info.width));
}
if ( gotoNewLine )
{
ssd1306_cursorX = 0;
ssd1306_cursorY += s_fixedFont.h.height;
if ( ssd1306_cursorY > ssd1306_lcd.height - s_fixedFont.h.height )
{
ssd1306_cursorY = 0;
}
ssd1306_clearBlock8(0, ssd1306_cursorY, ssd1306_lcd.width, s_fixedFont.h.height);
if (ch == '\n')
{
return 0;
}
}
if ( 1 )
{
uint8_t color = ssd1306_color;
ssd1306_color = s_ssd1306_invertByte ? color : 0x00;
ssd1306_fillRect8( ssd1306_cursorX, ssd1306_cursorY,
ssd1306_cursorX + char_info.width + char_info.spacing - 1,
ssd1306_cursorY + s_fixedFont.h.height - 1 );
ssd1306_color = color;
}
ssd1306_drawMonoBitmap8( ssd1306_cursorX,
ssd1306_cursorY,
char_info.width,
char_info.height,
char_info.glyph);
ssd1306_cursorX += char_info.width + char_info.spacing;
return 1;
}
size_t ssd1306_print8(const char ch[])
{
size_t n = 0;
while (*ch)
{
n += ssd1306_write8(*ch);
ch++;
}
return n;
}
uint8_t ssd1306_printFixed8(lcdint_t x, lcdint_t y, const char *ch, EFontStyle style)
{
ssd1306_cursorX = x;
ssd1306_cursorY = y;
return ssd1306_print8(ch);
}
+426
View File
@@ -0,0 +1,426 @@
/*
MIT License
Copyright (c) 2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* @file ssd1306_8bit.h 8-bit specific draw functions
*/
#ifndef _SSD1306_8BIT_H_
#define _SSD1306_8BIT_H_
#include "nano_gfx_types.h"
#ifdef __cplusplus
extern "C" {
#endif
///////////////////////////////////////////////////////////////////////
// DIRECT GRAPH FUNCTIONS
///////////////////////////////////////////////////////////////////////
/**
* @defgroup LCD_8BIT_GRAPHICS DIRECT DRAW: 8-bit API functions only for color displays
* @{
*
* @brief LCD direct draw functions only for color display.
*
* @details LCD direct draw functions are applicable for color display types. These functions will NOT work
* in ssd1306 compatible mode. Use ssd1306_setMode() function to change display mode to NORMAL.
* You can combine combine NanoEngine capabilities with these functions.
* Direct draw functions draw directly in GDRAM and do not use any double-buffering.
*/
/**
* @brief Sets default color, generated by RGB_COLOR8 or RGB_COLOR16 macros
*
* Sets color generated by RGB_COLOR8 or RGB_COLOR16 macros.
*
* @param color - new color to use for monochrome-specific operations on color display.
*/
void ssd1306_setColor(uint16_t color);
/**
* @brief Sets default color.
*
* Sets default color for monochrome operations.
* For now this function supports only 8-bit RGB mode.
* To work with RGB colors in 16-bit mode, please refer to ssd1306_setColor() function
* and RGB_COLOR16 macros.
* @param r - red in 0-255 range.
* @param g - green in 0-255 range.
* @param b - blue in 0-255 range.
*/
void ssd1306_setRgbColor(uint8_t r, uint8_t g, uint8_t b);
/**
* @brief Sets default color.
*
* Sets default color for monochrome operations.
* For now this function supports only 8-bit RGB mode.
* To work with RGB colors in 16-bit mode, please refer to ssd1306_setColor() function
* and RGB_COLOR16 macros.
* @param r - red in 0-255 range.
* @param g - green in 0-255 range.
* @param b - blue in 0-255 range.
*/
void ssd1306_setRgbColor8(uint8_t r, uint8_t g, uint8_t b);
/**
* Draws 1-bit bitmap, located in SRAM, on the display
* Each bit represents separate pixel: refer to ssd1306 datasheet for more information.
*
* @param xpos horizontal position in pixels
* @param ypos vertical position in pixels
* @param w width of bitmap in pixels
* @param h height of bitmap in pixels
* @param bitmap pointer to data, located in SRAM.
*/
void ssd1306_drawMonoBuffer8(lcdint_t xpos, lcdint_t ypos, lcduint_t w, lcduint_t h, const uint8_t *bitmap);
/**
* Draws 8-bit bitmap, located in SRAM, on the display
* Each byte represents separate pixel: refer to RGB_COLOR8 to understand RGB scheme, being used.
*
* @param x - horizontal position in pixels
* @param y - vertical position in pixels
* @param w - width of bitmap in pixels
* @param h - height of bitmap in pixels
* @param data - pointer to data, located in SRAM.
*/
void ssd1306_drawBufferFast8(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *data);
/**
* Draws 8-bit bitmap, located in SRAM, on the display, taking into account pitch parameter.
* Each byte represents separate pixel: refer to RGB_COLOR8 to understand RGB scheme, being used.
* pitch parameter specifies, length of single line in bytes.
*
* @param x - horizontal position in pixels
* @param y - vertical position in pixels
* @param w - width of bitmap in pixels
* @param h - height of bitmap in pixels
* @param pitch length of bitmap buffer line in bytes
* @param data - pointer to data, located in SRAM.
*/
void ssd1306_drawBufferEx8(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, lcduint_t pitch, const uint8_t *data);
/**
* Fills screen with pattern byte
*
* @param fill_Data pattern color to fill screen with
*/
void ssd1306_fillScreen8(uint8_t fill_Data);
/**
* Fills screen with zero-byte
*/
void ssd1306_clearScreen8(void);
/**
* Puts single color point directly in OLED display GDRAM.
*
* @param x - horizontal position in pixels
* @param y - vertical position in pixels
*
* @note set color with ssd1306_setColor() function.
*/
void ssd1306_putPixel8(lcdint_t x, lcdint_t y);
/**
* Puts single color point directly in OLED display GDRAM.
*
* @param x - horizontal position in pixels
* @param y - vertical position in pixels
* @param color color in RGB8 format (2-3-2)
*/
void ssd1306_putColorPixel8(lcdint_t x, lcdint_t y, uint8_t color);
/**
* Draw vertical line directly in OLED display GDRAM.
*
* @param x1 - horizontal position in pixels
* @param y1 - top vertical position in pixels
* @param y2 - bottom vertical position in pixels
*
* @note set color with ssd1306_setColor() function.
*/
void ssd1306_drawVLine8(lcdint_t x1, lcdint_t y1, lcdint_t y2);
/**
* Draw horizontal line directly in OLED display GDRAM.
*
* @param x1 - left position in pixels
* @param y1 - vertical vertical position in pixels
* @param x2 - right position in pixels
*
* @note set color with ssd1306_setColor() function.
*/
void ssd1306_drawHLine8(lcdint_t x1, lcdint_t y1, lcdint_t x2);
/**
* Draw line directly in OLED display GDRAM.
* This is software implementation. Some OLED controllers have hardware implementation.
* Refer to datasheet.
*
* @param x1 - start horizontal position in pixels
* @param y1 - start vertical position in pixels
* @param x2 - end horizontal position in pixels
* @param y2 - end vertical position in pixels
*
* @note set color with ssd1306_setColor() function.
*/
void ssd1306_drawLine8(lcdint_t x1, lcdint_t y1, lcdint_t x2, lcdint_t y2);
/**
* Draw rectangle directly in OLED display GDRAM.
* This is software implementation. Some OLED controllers have hardware implementation.
* Refer to datasheet.
*
* @param x1 - start horizontal position in pixels
* @param y1 - start vertical position in pixels
* @param x2 - end horizontal position in pixels
* @param y2 - end vertical position in pixels
*
* @note set color with ssd1306_setColor() function.
*/
void ssd1306_drawRect8(lcdint_t x1, lcdint_t y1, lcdint_t x2, lcdint_t y2);
/**
* Fill rectangle directly in OLED display GDRAM.
* This is software implementation. Some OLED controllers have hardware implementation.
* Refer to datasheet.
*
* @param x1 - start horizontal position in pixels
* @param y1 - start vertical position in pixels
* @param x2 - end horizontal position in pixels
* @param y2 - end vertical position in pixels
*
* @note set color with ssd1306_setColor() function.
*/
void ssd1306_fillRect8(lcdint_t x1, lcdint_t y1, lcdint_t x2, lcdint_t y2);
/**
* Draw monochrome bitmap, located in Flash, directly to OLED display GDRAM.
* The bitmap should be in ssd1306 format (each byte represents 8 vertical pixels)
*
* @param xpos start horizontal position in pixels
* @param ypos start vertical position in pixels
* @param w bitmap width in pixels
* @param h bitmap height in pixels
* @param bitmap pointer to Flash data, containing monochrome bitmap.
*
* @note set color with ssd1306_setColor() function.
*/
void ssd1306_drawMonoBitmap8(lcdint_t xpos, lcdint_t ypos, lcduint_t w, lcduint_t h, const uint8_t *bitmap);
/**
* Draw 8-bit color bitmap, located in Flash, directly to OLED display GDRAM.
* Each pixel of the bitmap is expected in 3-3-2 format.
*
* @param xpos start horizontal position in pixels
* @param ypos start vertical position in pixels
* @param w bitmap width in pixels
* @param h bitmap height in pixels
* @param bitmap pointer to Flash data, containing 8-bit color bitmap.
*/
void ssd1306_drawBitmap8(lcdint_t xpos, lcdint_t ypos, lcduint_t w, lcduint_t h, const uint8_t *bitmap);
/**
* Clears block, filling it with black pixels, directly in OLED display GDRAM.
*
* @param x start horizontal position in pixels
* @param y start vertical position in pixels
* @param w block width in pixels
* @param h block height in pixels
*/
void ssd1306_clearBlock8(uint8_t x, uint8_t y, uint8_t w, uint8_t h);
/**
* Set cursor position for text functions
*
* @param x horizontal position in pixels.
* @param y vertical position in pixels.
*/
void ssd1306_setCursor8(lcduint_t x, lcduint_t y);
/**
* Draws single character to canvas. Cursor position is defined
* by ssd1306_setCursor8(). Do not changes cursor position
*
* @param c - character code to print
*
* @note set color with ssd1306_setColor() function.
*/
void ssd1306_printChar8(uint8_t c);
/**
* @brief Prints single character to display at current cursor position
*
* Prints single character to display at current cursor position.
* Cursor position can be set by ssd1306_setCursor8().
*
* @param ch - character to print to the display. 'LF' and 'CR' are skipped
* @return returns number of printed characters.
*/
size_t ssd1306_write8(uint8_t ch);
/**
* @brief Prints null-terminated string to display at current cursor position
*
* Prints null-terminated string to display at current cursor position
* Cursor position can be set by ssd1306_setCursor8().
*
* @param ch - string to print to the display. 'LF' and 'CR' are skipped
* @return returns number of printed characters.
*/
size_t ssd1306_print8(const char ch[]);
/**
* Prints text to screen using fixed font.
* @param x horizontal position in pixels
* @param y vertical position in pixels
* @param ch NULL-terminated string to print
* @param style font style (EFontStyle), normal by default (not implemented).
* @returns number of chars in string
*
* @see ssd1306_setFixedFont
* @note set color with ssd1306_setColor() function.
*/
uint8_t ssd1306_printFixed8(lcdint_t x, lcdint_t y, const char *ch, EFontStyle style);
#ifndef DOXYGEN_SHOULD_SKIP_THIS
/////////////////////////////////////////////////////////////////////////////////
// FUNCTIONS BELOW ARE ONLY FOR COMPATIBILITY WITH PREVIOUSE VERSIONS OF LIBRARY
static inline void ssd1331_setColor(uint16_t color)
{
ssd1306_setColor(color);
}
static inline void ssd1331_setRgbColor(uint8_t r, uint8_t g, uint8_t b)
{
ssd1306_setRgbColor(r, g, b);
}
static inline void ssd1331_drawMonoBuffer8(lcdint_t xpos, lcdint_t ypos, lcduint_t w, lcduint_t h, const uint8_t *bitmap)
{
ssd1306_drawMonoBuffer8(xpos, ypos, w, h, bitmap);
}
static inline void ssd1331_drawBufferFast8(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *data)
{
ssd1306_drawBufferFast8(x, y, w, h, data);
}
static inline void ssd1331_fillScreen8(uint8_t fill_Data)
{
ssd1306_fillScreen8(fill_Data);
}
static inline void ssd1331_clearScreen8(void)
{
ssd1306_clearScreen8();
}
static inline void ssd1331_putPixel8(lcdint_t x, lcdint_t y)
{
ssd1306_putPixel8(x, y);
}
static inline void ssd1331_drawVLine8(lcdint_t x1, lcdint_t y1, lcdint_t y2)
{
ssd1306_drawVLine8(x1, y1, y2);
}
static inline void ssd1331_drawHLine8(lcdint_t x1, lcdint_t y1, lcdint_t x2)
{
ssd1306_drawHLine8(x1, y1, x2);
}
static inline void ssd1331_drawLine8(lcdint_t x1, lcdint_t y1, lcdint_t x2, lcdint_t y2)
{
ssd1306_drawLine8(x1, y1, x2, y2);
}
static inline void ssd1331_drawRect8(lcdint_t x1, lcdint_t y1, lcdint_t x2, lcdint_t y2)
{
ssd1306_drawRect8(x1, y1, x2, y2);
}
static inline void ssd1331_fillRect8(lcdint_t x1, lcdint_t y1, lcdint_t x2, lcdint_t y2)
{
ssd1306_fillRect8(x1, y1, x2, y2);
}
static inline void ssd1331_drawMonoBitmap8(lcdint_t xpos, lcdint_t ypos, lcduint_t w, lcduint_t h, const uint8_t *bitmap)
{
ssd1306_drawMonoBitmap8(xpos, ypos, w, h, bitmap);
}
static inline void ssd1331_drawBitmap8(lcdint_t xpos, lcdint_t ypos, lcduint_t w, lcduint_t h, const uint8_t *bitmap)
{
ssd1306_drawBitmap8(xpos, ypos, w, h, bitmap);
}
static inline void ssd1331_clearBlock8(uint8_t x, uint8_t y, uint8_t w, uint8_t h)
{
ssd1306_clearBlock8(x, y, w, h);
}
static inline void ssd1331_setCursor8(lcduint_t x, lcduint_t y)
{
ssd1306_setCursor8(x, y);
}
static inline void ssd1331_printChar8(uint8_t c)
{
ssd1306_printChar8(c);
}
static inline size_t ssd1331_write8(uint8_t ch)
{
return ssd1306_write8(ch);
}
static inline size_t ssd1331_print8(const char ch[])
{
return ssd1306_print8(ch);
}
static inline uint8_t ssd1331_printFixed8(lcdint_t x, lcdint_t y, const char *ch, EFontStyle style)
{
return ssd1306_printFixed8(x, y, ch, style);
}
#endif
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif // _SSD1306_8BIT_H_
+91
View File
@@ -0,0 +1,91 @@
/*
MIT License
Copyright (c) 2017-2019, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "ssd1306_console.h"
extern lcduint_t ssd1306_cursorX;
extern lcduint_t ssd1306_cursorY;
extern SFixedFontInfo s_fixedFont;
#define SSD1306_MAX_SCAN_LINES 64
size_t ssd1306_consoleWriter(uint8_t ch)
{
if (ch == '\r')
{
ssd1306_cursorX = 0;
return 0;
}
else if ( (ssd1306_cursorX > ssd1306_lcd.width - s_fixedFont.h.width) || (ch == '\n') )
{
ssd1306_cursorX = 0;
ssd1306_cursorY += s_fixedFont.h.height;
uint8_t bottomScanLine = ssd1306_getStartLine() + ssd1306_lcd.height;
if ( bottomScanLine > SSD1306_MAX_SCAN_LINES )
{
bottomScanLine -= SSD1306_MAX_SCAN_LINES;
}
if ( ssd1306_cursorY >= bottomScanLine )
{
uint8_t lcd_offset = ssd1306_getStartLine() + s_fixedFont.h.height;
if ( lcd_offset >= SSD1306_MAX_SCAN_LINES )
{
lcd_offset -= SSD1306_MAX_SCAN_LINES;
}
ssd1306_setStartLine( lcd_offset );
}
if ( ssd1306_cursorY >= SSD1306_MAX_SCAN_LINES )
{
ssd1306_cursorY -= SSD1306_MAX_SCAN_LINES;
}
ssd1306_clearBlock(0, ssd1306_cursorY >> 3, ssd1306_lcd.width, s_fixedFont.h.height);
if (ch == '\n')
{
return 0;
}
}
uint16_t unicode = ssd1306_unicode16FromUtf8(ch);
if (unicode == SSD1306_MORE_CHARS_REQUIRED) return 0;
SCharInfo char_info;
ssd1306_getCharBitmap(unicode, &char_info);
ssd1306_drawBitmap( ssd1306_cursorX,
ssd1306_cursorY >> 3,
char_info.width,
char_info.height,
char_info.glyph );
ssd1306_cursorX += char_info.width + char_info.spacing;
return 1;
}
void Ssd1306Console::clear()
{
ssd1306_clearScreen();
setCursor(0,0);
}
void Ssd1306Console::setCursor(lcduint_t x, lcduint_t y)
{
ssd1306_setCursor8(x,y);
}
+116
View File
@@ -0,0 +1,116 @@
/*
MIT License
Copyright (c) 2017-2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* @file ssd1306_console.h This is for console
*/
#ifndef _SSD1306_CONSOLE_H_
#define _SSD1306_CONSOLE_H_
#include "ssd1306.h"
#include "ssd1306_hal/io.h"
#include "ssd1306_hal/Print_internal.h"
/**
* Callback function to print text to the LCD display
*/
typedef size_t (*LcdWriter)(uint8_t ch);
/**
* Base template class for specific LCD console implementation
*/
template <LcdWriter W>
class LcdConsole: public Print
{
public:
/**
* Creates console object to print text information on LCD display.
*/
explicit LcdConsole( ) { };
/**
* Initializes console.
*/
void begin()
{
}
/**
* Writes single character to the display
* @param ch - character to write
*/
size_t write(uint8_t ch) override
{
return W(ch);
}
private:
};
/**
* ssd1306 console support function.
* @param ch character to print
* @warning only for SSD1306 based displays
*/
size_t ssd1306_consoleWriter(uint8_t ch);
/**
* Ssd1306Console represents object to work with LCD display.
* Easy to use:
* ~~~~~~~~~~~~~~~{.cpp}
* Ssd1306Console console;
* void setup()
* {
* ssd1306_128x64_spi_init(3, 4, 5);
* ssd1306_clearScreen();
* console.print( "Hello" );
* }
* ~~~~~~~~~~~~~~~
*/
class Ssd1306Console: public LcdConsole<ssd1306_consoleWriter>
{
public:
using LcdConsole::LcdConsole;
/**
* Fills screen with zero-byte and sets
* cursor position to top-left corner of the screen.
*/
void clear();
/**
* Set cursor position for text functions
*
* @param x horizontal position in pixels.
* @param y vertical position in pixels.
*/
void setCursor(lcduint_t x, lcduint_t y);
private:
};
#endif
File diff suppressed because it is too large Load Diff
+100
View File
@@ -0,0 +1,100 @@
/*
MIT License
Copyright (c) 2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* @file ssd1306_fonts.h Fonts for monochrome/rgb oled display
*/
#ifndef SSD1306_FONTS_H
#define SSD1306_FONTS_H
#include "ssd1306_hal/io.h"
#include "nano_gfx_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup LCD_FONTS FONTS: Supported LCD fonts
* @{
*/
/** Standard ASCII 6x8 Fixed Type font.*/
extern const PROGMEM uint8_t ssd1306xled_font6x8 [];
/** Standard ASCII 8x16 Fixed Type font */
extern const PROGMEM uint8_t ssd1306xled_font8x16[];
/** German chars for standard ASCII 6x8 Fixed Type font */
extern const PROGMEM uint8_t ssd1306xled_font6x8_German [];
/** Standard ASCII 6x8 AB Fixed Type font with only capital letters */
extern const PROGMEM uint8_t ssd1306xled_font6x8_AB [];
/** Standard ASCII 5x7 Fixed Type font */
extern const PROGMEM uint8_t ssd1306xled_font5x7 [];
/** Standard ASCII 5x7 Fixed Type font with only capital letters */
extern const PROGMEM uint8_t ssd1306xled_font5x7_AB [];
/** Digital ASCII 5x7 Fixed Type font with only digits and operation signs */
extern const PROGMEM uint8_t digital_font5x7_123[];
/** Digital ASCII 5x7 Fixed Type font with only capital letters */
extern const PROGMEM uint8_t digital_font5x7_AB[];
/** Digital ASCII 5x7 Fixed Type font */
extern const PROGMEM uint8_t digital_font5x7[];
/** Calibri ASCII 11x12 Free Type font */
extern const PROGMEM uint8_t free_calibri11x12[];
/** Calibri ASCII 11x12 Free Type font cyrillic */
extern const PROGMEM uint8_t free_calibri11x12_cyrillic[];
/** Calibri ASCII 11x12 Free Type font basic latin */
extern const PROGMEM uint8_t free_calibri11x12_latin[];
/**
* Standard ASCII Free Type font 11x16 with digits only (Ascii codes 32 - 64).
* @warning can be used only with ssd1306_printFixed() and ssd1306_setFixedFont() functions.
*/
extern const PROGMEM uint8_t courier_new_font11x16_digits [];
/**
* Comic Sans ASCII Free Type font 24x32 with digits only (Ascii codes 32 - 64).
* @warning can be used only with ssd1306_printFixed() and ssd1306_setFixedFont() functions.
*/
extern const PROGMEM uint8_t comic_sans_font24x32_123 [];
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif // SSD1306_FONTS_H
+395
View File
@@ -0,0 +1,395 @@
/*
MIT License
Copyright (c) 2016-2019, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
///////////////////////////////////////////////////////////////////////////////
////// GENERIC FUNCTIONS APPLICABLE FOR ALL DISPLAY TYPES /////////////////////
///////////////////////////////////////////////////////////////////////////////
#include "ssd1306.h"
#include "ssd1306_fonts.h"
#include "lcd/lcd_common.h"
#include "intf/i2c/ssd1306_i2c.h"
#include "intf/spi/ssd1306_spi.h"
#include "intf/ssd1306_interface.h"
#include "ssd1306_hal/io.h"
#include "nano_gfx_types.h"
enum
{
SSD1306_OLD_FIXED_FORMAT = 0x00,
SSD1306_NEW_FIXED_FORMAT = 0x01,
SSD1306_NEW_FORMAT = 0x02,
SSD1306_SQUIX_FORMAT = 0x03,
};
uint16_t ssd1306_color = 0xFFFF;
lcduint_t ssd1306_cursorX = 0;
lcduint_t ssd1306_cursorY = 0;
SFixedFontInfo s_fixedFont = {}; //{ { 0 }, 0 };
#ifdef CONFIG_SSD1306_UNICODE_ENABLE
uint8_t g_ssd1306_unicode = 1;
#endif
static void (*s_ssd1306_getCharBitmap)(uint16_t unicode, SCharInfo *info) = NULL;
static const uint8_t *ssd1306_getCharGlyph(char ch);
static const uint8_t *ssd1306_getU16CharGlyph(uint16_t unicode);
lcduint_t ssd1306_displayHeight()
{
return ssd1306_lcd.height;
}
lcduint_t ssd1306_displayWidth()
{
return ssd1306_lcd.width;
}
void ssd1306_setCursor(lcdint_t x, lcdint_t y)
{
ssd1306_cursorX = x;
ssd1306_cursorY = y;
}
static const uint8_t * ssd1306_readUnicodeRecord(SUnicodeBlockRecord *r, const uint8_t *p)
{
r->start_code =( pgm_read_byte(&p[0]) << 8) | (pgm_read_byte(&p[1]));
r->count = pgm_read_byte(&p[2]);
return (r->count > 0) ? (&p[3]): NULL;
}
void ssd1306_setSecondaryFont(const uint8_t * progmemUnicode)
{
#ifdef CONFIG_SSD1306_UNICODE_ENABLE
s_fixedFont.secondary_table = progmemUnicode;
if (s_fixedFont.secondary_table != NULL)
{
s_fixedFont.secondary_table += sizeof(SFontHeaderRecord);
}
#endif
}
void ssd1306_getCharBitmap(uint16_t unicode, SCharInfo *info)
{
return s_ssd1306_getCharBitmap( unicode, info );
}
uint16_t ssd1306_unicode16FromUtf8(uint8_t ch)
{
#ifdef CONFIG_SSD1306_UNICODE_ENABLE
static uint16_t unicode = 0;
ch &= 0x000000FF;
if (!unicode)
{
if ( ch >= 0xc0 )
{
unicode = ch;
return SSD1306_MORE_CHARS_REQUIRED;
}
return ch;
}
uint16_t code = ((unicode & 0x1f) << 6) | (ch & 0x3f);
unicode = 0;
return code;
#else
return ch;
#endif
}
void ssd1306_enableUtf8Mode(void)
{
#ifdef CONFIG_SSD1306_UNICODE_ENABLE
g_ssd1306_unicode = 1;
#endif
}
void ssd1306_enableAsciiMode(void)
{
#ifdef CONFIG_SSD1306_UNICODE_ENABLE
g_ssd1306_unicode = 0;
#endif
}
//////////////////////////////////////////////////////////////////////////////////////////////////
/// SECTION WITH FONT FORMATS
//////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////
/// OLD FORMAT: 1.7.6 and below
/// OLD FORMAT is supported by old and latest versions of ssd1306 library
static const uint8_t *ssd1306_getCharGlyph(char ch)
{
return &s_fixedFont.primary_table[ (ch - s_fixedFont.h.ascii_offset) *
s_fixedFont.glyph_size +
(s_fixedFont.h.type == 0x01 ? sizeof(SUnicodeBlockRecord) : 0) ];
}
#ifdef CONFIG_SSD1306_UNICODE_ENABLE
static const uint8_t *ssd1306_searchCharGlyph(const uint8_t * unicode_table, uint16_t unicode)
{
SUnicodeBlockRecord r;
const uint8_t *data = unicode_table;
// looking for required unicode table
while (1)
{
ssd1306_readUnicodeRecord( &r, data );
if (r.count == 0)
{
break;
}
data += sizeof(SUnicodeBlockRecord);
if ( ( unicode >= r.start_code) && ( unicode < (r.start_code + r.count) ) )
{
break;
}
data += r.count * s_fixedFont.glyph_size;
}
if (r.count == 0)
{
// Sorry, no glyph found for the specified character
return NULL;
}
return &data[ (unicode - r.start_code) * s_fixedFont.glyph_size ];
}
#endif
static const uint8_t *ssd1306_getU16CharGlyph(uint16_t unicode)
{
#ifdef CONFIG_SSD1306_UNICODE_ENABLE
const uint8_t * glyph = NULL;
if (g_ssd1306_unicode)
{
if ((unicode < 128) && (s_fixedFont.h.type == 0x00) && (s_fixedFont.primary_table != NULL))
{
return ssd1306_getCharGlyph(unicode);
}
if (s_fixedFont.primary_table)
{
glyph = ssd1306_searchCharGlyph( s_fixedFont.primary_table, unicode );
}
if (!glyph && s_fixedFont.secondary_table)
{
glyph = ssd1306_searchCharGlyph( s_fixedFont.secondary_table, unicode );
}
if (!glyph)
{
return ssd1306_getCharGlyph( s_fixedFont.h.ascii_offset );
}
return glyph;
}
else
#endif
{
return ssd1306_getCharGlyph(unicode);
}
}
static void __ssd1306_oldFormatGetBitmap(uint16_t unicode, SCharInfo *info)
{
if (info)
{
info->width = s_fixedFont.h.width;
info->height = s_fixedFont.h.height;
info->spacing = 0;
info->glyph = ssd1306_getU16CharGlyph( unicode );
}
}
void ssd1306_setFixedFont(const uint8_t * progmemFont)
{
s_fixedFont.h.type = pgm_read_byte( &progmemFont[0] );
s_fixedFont.h.width = pgm_read_byte(&progmemFont[1]);
s_fixedFont.h.height = pgm_read_byte(&progmemFont[2]);
s_fixedFont.h.ascii_offset = pgm_read_byte(&progmemFont[3]);
s_fixedFont.primary_table = progmemFont + 4;
s_ssd1306_getCharBitmap = __ssd1306_oldFormatGetBitmap;
s_fixedFont.pages = (s_fixedFont.h.height + 7) >> 3;
s_fixedFont.glyph_size = s_fixedFont.pages * s_fixedFont.h.width;
#ifdef CONFIG_SSD1306_UNICODE_ENABLE
s_fixedFont.secondary_table = NULL;
#endif
}
void ssd1306_setFixedFont_oldStyle(const uint8_t * progmemFont)
{
s_fixedFont.h.type = pgm_read_byte( &progmemFont[0] );
s_fixedFont.h.width = pgm_read_byte(&progmemFont[1]);
s_fixedFont.h.height = pgm_read_byte(&progmemFont[2]);
s_fixedFont.h.ascii_offset = pgm_read_byte(&progmemFont[3]);
s_fixedFont.primary_table = progmemFont + 4;
s_fixedFont.pages = (s_fixedFont.h.height + 7) >> 3;
s_fixedFont.glyph_size = s_fixedFont.pages * s_fixedFont.h.width;
}
//////////////////////////////////////////////////////////////////////////////////////////////////
/// NEW FORMAT: 1.7.8 and later
/// NEW FORMAT is supported only by latest versions of ssd1306 library
static void __ssd1306_newFormatGetBitmap(uint16_t unicode, SCharInfo *info)
{
if (info)
{
#ifdef CONFIG_SSD1306_UNICODE_ENABLE
uint8_t table_index = 0;
#endif
const uint8_t *data = s_fixedFont.primary_table;
while (data)
{
SUnicodeBlockRecord r;
data = ssd1306_readUnicodeRecord( &r, data );
if (!data)
{
#ifdef CONFIG_SSD1306_UNICODE_ENABLE
if ( table_index == 0 )
{
table_index++;
data = s_fixedFont.secondary_table;
continue;
}
#endif
break;
}
/* Check that unicode in the section being processed */
if ( ( unicode < r.start_code) || ( unicode >= (r.start_code + r.count) ) )
{
// skip jump table
data += r.count * 4;
// skip block bitmap data
data += ((pgm_read_byte(&data[0]) << 8) | (pgm_read_byte(&data[1]))) + 2;
continue;
}
/* At this point data points to jump table (offset|offset|bytes|width) */
unicode -= r.start_code;
data += unicode * 4;
uint16_t offset = (pgm_read_byte(&data[0]) << 8) | (pgm_read_byte(&data[1]));
uint8_t glyph_width = pgm_read_byte(&data[2]);
uint8_t glyph_height = pgm_read_byte(&data[3]);
info->width = glyph_width;
info->height = glyph_height;
info->spacing = glyph_width ? 1 : (s_fixedFont.h.width >> 1);
info->glyph = data + (r.count - unicode) * 4 + 2 + offset;
break;
}
if (!info->glyph)
{
info->width = 0;
info->height = 0;
info->spacing = s_fixedFont.h.width >> 1;
info->glyph = s_fixedFont.primary_table;
}
}
}
void ssd1306_setFreeFont(const uint8_t * progmemFont)
{
s_fixedFont.h.type = pgm_read_byte( &progmemFont[0] );
s_fixedFont.h.width = pgm_read_byte(&progmemFont[1]);
s_fixedFont.h.height = pgm_read_byte(&progmemFont[2]);
s_fixedFont.h.ascii_offset = pgm_read_byte(&progmemFont[3]);
s_fixedFont.primary_table = progmemFont + 4;
s_ssd1306_getCharBitmap = __ssd1306_newFormatGetBitmap;
s_fixedFont.pages = (s_fixedFont.h.height + 7) >> 3;
#ifdef CONFIG_SSD1306_UNICODE_ENABLE
s_fixedFont.secondary_table = NULL;
#endif
}
//////////////////////////////////////////////////////////////////////////////////////////////////
/// SQUIX FORMAT: 1.7.8 and later
/// SQUIX FORMAT is not fully supported. Use it at your own risk
static void __ssd1306_squixFormatGetBitmap(uint16_t unicode, SCharInfo *info)
{
if (info)
{
const uint8_t *data = s_fixedFont.primary_table;
/* Check that unicode in the section being processed */
if ( !data || ( unicode < s_fixedFont.h.ascii_offset) || ( unicode >= (s_fixedFont.h.ascii_offset + s_fixedFont.count) ) )
{
info->width = 0;
info->height = 0;
info->spacing = s_fixedFont.h.width >> 1;
info->glyph = s_fixedFont.primary_table;
return;
}
/* At this point data points to jump table (offset|offset|bytes|width) */
const uint8_t * bitmap_data = data + (uint16_t)s_fixedFont.count * 4;
unicode -= s_fixedFont.h.ascii_offset;
data += (unicode * 4);
uint16_t offset = (pgm_read_byte(&data[0]) << 8) | pgm_read_byte(&data[1]);
uint8_t glyph_bytes = pgm_read_byte(&data[2]);
// uint8_t width = pgm_read_byte(&data[3]);
info->width = glyph_bytes; //(glyph_bytes + s_fixedFont.pages - 1) / s_fixedFont.pages;
info->height = s_fixedFont.h.height / 2;
info->spacing = 1;
// uint8_t index=0;
info->glyph = bitmap_data;
if ( offset != 0xFFFF )
{
info->glyph += offset;
}
}
}
void ssd1306_setSquixFont(const uint8_t * progmemFont)
{
s_fixedFont.h.type = SSD1306_SQUIX_FORMAT;
s_fixedFont.h.width = pgm_read_byte(&progmemFont[0]);
s_fixedFont.h.height = pgm_read_byte(&progmemFont[1]);
s_fixedFont.h.ascii_offset = pgm_read_byte(&progmemFont[2]);
s_fixedFont.count = pgm_read_byte(&progmemFont[3]);
s_fixedFont.primary_table = progmemFont + 4;
s_ssd1306_getCharBitmap = __ssd1306_squixFormatGetBitmap;
s_fixedFont.pages = (s_fixedFont.h.height + 7) >> 3;
s_fixedFont.glyph_size = s_fixedFont.pages * s_fixedFont.h.width;
#ifdef CONFIG_SSD1306_UNICODE_ENABLE
s_fixedFont.secondary_table = NULL;
#endif
}
lcduint_t ssd1306_getTextSize(const char *text, lcduint_t *height)
{
lcduint_t width = 0;
while (*text)
{
if (*text == '\r' || *text == '\n')
{
text++;
break;
}
uint16_t unicode = ssd1306_unicode16FromUtf8(*text);
if (unicode == SSD1306_MORE_CHARS_REQUIRED)
{
text++;
continue;
}
SCharInfo char_info;
ssd1306_getCharBitmap(unicode, &char_info);
width += char_info.width + char_info.spacing;
if ( height ) *height = char_info.height;
text++;
}
return width;
}
+318
View File
@@ -0,0 +1,318 @@
/*
MIT License
Copyright (c) 2016-2019, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* @file ssd1306_generic.h SSD1306 generic API functions
*/
#ifndef _SSD1306_GENERIC_H_
#define _SSD1306_GENERIC_H_
#include "nano_gfx_types.h"
#ifdef __cplusplus
extern "C" {
#endif
///////////////////////////////////////////////////////////////////////
// GENERIC GRAPH FUNCTIONS
///////////////////////////////////////////////////////////////////////
/** Flag means that more chars are required to decode utf-8 */
#define SSD1306_MORE_CHARS_REQUIRED 0xffff
/**
* @defgroup LCD_GENERIC_API DIRECT DRAW: Generic API functions, common for all displays and all display modes.
* @{
* @brief Generic API functions, common for all displays and all display modes.
*
* @details Generic API functions, common for all displays and all display modes.
*/
/**
* Set position in terms of display.
* @param x - horizontal position in pixels
* @param y - vertical position in blocks (pixels/8)
*/
void ssd1306_setPos(uint8_t x, uint8_t y);
/**
* @brief Sets cursor position for text mode print functions.
*
* Sets cursor position for text mode print functions.
* @param x xpos in pixels
* @param y ypos in pixels
*/
void ssd1306_setCursor(lcdint_t x, lcdint_t y);
/**
* Function allows to set another fixed font for the library.
* By default, the font supports only first 128 - 32 ascii chars.
* Please refer to github wiki on how to generate new fonts.
* @param progmemFont - font to setup located in Flash area
*/
void ssd1306_setFixedFont(const uint8_t * progmemFont);
#ifndef DOXYGEN_SHOULD_SKIP_THIS
void ssd1306_setFixedFont_oldStyle(const uint8_t * progmemFont);
#endif
/**
* Function allows to set another free font for the library.
* By default, the font supports only first 128 - 32 ascii chars.
* Please refer to github wiki on how to generate new fonts.
* @param progmemFont - font to setup located in Flash area
* @note This function supports new fonts of ssd1306 library 1.7.8 and above
*/
void ssd1306_setFreeFont(const uint8_t * progmemFont);
/**
* Function allows sets secondary font for specific language.
* Use it if you want to use additional font to combine capabilities of
* ascii fonts and language specific font.
* @param progmemUnicode font containing unicode table (refer to
* ssd1306xled_font6x8_German as example).
*/
void ssd1306_setSecondaryFont(const uint8_t * progmemUnicode);
/**
* Function allows to set another font for the library.
* By default, the font supports only first 128 - 32 ascii chars.
* First 32 chars of ascii table are non-printable, and removed
* from the font table to reduce flash memory consumption.
* Default font doesn't support russian characters. Using
* this function you can implement your own fonts.
* First font char must be started with \<space\> image.
* @param progmemFont - font to setup located in Flash area
* @deprecated Use ssd1306_setFixedFont() instead.
*/
void ssd1306_setFont6x8(const uint8_t * progmemFont) __attribute__ ((deprecated));
/**
* @brief returns char data for currently set (active) font.
*
* Function returns char data for currently set font: pointer to progmem
* data for specified char, and width, height of the char. You can use these
* data to draw char manually using ssd1306_drawBitmap(), ssd1306_drawMonoBitmap8()
* or NanoCanvasOps::drawBitmap1().
*
* @param ch char to read from set font
* @param info pointer to SCharInfo structure to fill with char data
*
* @see ssd1306_setFixedFont
*/
void ssd1306_getCharBitmap(uint16_t ch, SCharInfo *info);
/**
* Enables utf8 support for all text-functions.
* @note Unicode-16 only supported in text decoding functions.
*/
void ssd1306_enableUtf8Mode(void);
/**
* Enables ascii mode for all text-functions. No any decoding will be performed
*/
void ssd1306_enableAsciiMode(void);
#ifndef DOXYGEN_SHOULD_SKIP_THIS
/**
* Function allows to set and use squix font.
* @param progmemFont - font to setup located in Flash area
* @note This function supports squix fonts for ssd1306 library 1.7.8 and above
* @warning Squix fonts are not fully supported, use them at your own risk
*/
void ssd1306_setSquixFont(const uint8_t * progmemFont);
/**
* Returns 16-bit unicode char, encoded in utf8
* SSD1306_MORE_CHARS_REQUIRED if more characters is expected
* @param ch character byte to decode
* @return 16-bit unicode char, encoded in utf8
* SSD1306_MORE_CHARS_REQUIRED if more characters is expected
*/
uint16_t ssd1306_unicode16FromUtf8(uint8_t ch);
#endif
/**
* Returns dimensions in pixels for text provided.
* @param text text to calculate size of
* @param height variable to store text height. Can be NULL
* @return witdth of passed text in pixels
*/
lcduint_t ssd1306_getTextSize(const char *text, lcduint_t *height);
///////////////////////////////////////////////////////////////////////
// HIGH-LEVEL GRAPH FUNCTIONS
///////////////////////////////////////////////////////////////////////
/**
* Describes menu object
*/
typedef struct
{
/// list of menu items of the menu
const char **items;
/// count of menu items in the menu
uint8_t count;
/// currently selected item. Internally updated.
uint8_t selection;
/// selected item, when last redraw operation was performed. Internally updated.
uint8_t oldSelection;
/// position of menu scrolling. Internally updated
uint8_t scrollPosition;
} SAppMenu;
/**
* Creates menu object with the provided list of menu items.
* List of menu items (strings) must exist all until menu object is no longer needed.
* Selection is set to the first item by default.
*
* @param menu - Pointer to SAppMenu structure
* @param items - array of null-termintated strings (located in SRAM)
* @param count - count of menu items in the array
*/
void ssd1306_createMenu(SAppMenu *menu, const char **items, uint8_t count);
/**
* Shows menu items on the display. If menu items cannot fit the display,
* the function provides scrolling.
*
* @param menu - Pointer to SAppMenu structure
*
* @warning works only in SSD1306 compatible mode.
*/
void ssd1306_showMenu(SAppMenu *menu);
/**
* Shows menu items on the display. If menu items cannot fit the display,
* the function provides scrolling.
*
* @param menu - Pointer to SAppMenu structure
*
* @warning works only in 8-bit RGB normal mode.
*/
void ssd1306_showMenu8(SAppMenu *menu);
/**
* Shows menu items on the display. If menu items cannot fit the display,
* the function provides scrolling.
*
* @param menu - Pointer to SAppMenu structure
*
* @warning works only in 16-bit RGB normal mode.
*/
void ssd1306_showMenu16(SAppMenu *menu);
#ifndef DOXYGEN_SHOULD_SKIP_THIS
static inline void ssd1331_showMenu8(SAppMenu *menu)
{
ssd1306_showMenu8(menu);
}
#endif
/**
* Updates menu items on the display. That is if selection is changed,
* the function will update only those areas, affected by the change.
*
* @param menu - Pointer to SAppMenu structure
*/
void ssd1306_updateMenu(SAppMenu *menu);
/**
* Updates menu items on the display. That is if selection is changed,
* the function will update only those areas, affected by the change.
*
* @param menu - Pointer to SAppMenu structure
*
* @warning works only in SSD1306 compatible mode.
*/
void ssd1306_updateMenu8(SAppMenu *menu);
/**
* Updates menu items on the display. That is if selection is changed,
* the function will update only those areas, affected by the change.
*
* @param menu - Pointer to SAppMenu structure
*
* @warning works only in SSD1306 compatible mode.
*/
void ssd1306_updateMenu16(SAppMenu *menu);
#ifndef DOXYGEN_SHOULD_SKIP_THIS
static inline void ssd1331_updateMenu8(SAppMenu *menu)
{
ssd1306_updateMenu8(menu);
}
#endif
/**
* Returns currently selected menu item.
* First item has zero-index.
*
* @param menu - Pointer to SAppMenu structure
*
* @warning works only in 8-bit RGB normal mode.
*/
uint8_t ssd1306_menuSelection(SAppMenu *menu);
/**
* Moves selection pointer down by 1 item. If there are no items below,
* it will set selection pointer to the first item.
* Use ssd1306_updateMenu() to refresh menu state on the display.
*
* @param menu - Pointer to SAppMenu structure
*/
void ssd1306_menuDown(SAppMenu *menu);
/**
* Moves selection pointer up by 1 item. If selected item is the first one,
* then selection pointer will set to the last item in menu list.
* Use ssd1306_updateMenu() to refresh menu state on the display.
*
* @param menu - Pointer to SAppMenu structure
*/
void ssd1306_menuUp(SAppMenu *menu);
/**
* Draws progress bar in the middle of the screen
* @param progress progress value in range 0 - 100.
*/
void ssd1306_drawProgressBar(int8_t progress);
/**
* Draws progress bar in the middle of the screen
* @param progress progress value in range 0 - 100.
*/
void ssd1306_drawProgressBar8(int8_t progress);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif // _SSD1306_GENERIC_H_
@@ -0,0 +1,111 @@
/*
MIT License
Copyright (c) 2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* @file ssd1306_hal/Print_internal.h SSD1306 Print class implementation
*/
#ifndef _SSD1306_HAL_PRINT_INTERNAL_H_
#define _SSD1306_HAL_PRINT_INTERNAL_H_
#if defined(ARDUINO) && !defined(ARDUINO_FAKE)
/* Include standard print class for Arduino environment */
#include "Print.h"
#else
#include "ssd1306_hal/io.h"
#include <stdio.h>
/** Implements own Print class for plain AVR and Linux environment */
class Print
{
public:
/** Constructor to create Print class object */
Print() {}
/**
* abstract function to be defined in inherited classes
* @param ch char to print
* @return returns number of printed symbols
*/
virtual size_t write(uint8_t ch) = 0;
/**
* Prints string via write()
* @param str string to print
* @return returns number of printed symbols
*/
size_t print(const char* str)
{
size_t n = 0;
while (*str)
{
n += write(*str);
str++;
}
return n;
}
/**
* Prints number via write()
* @param n integer to print
* @return returns number of printed symbols
*/
size_t print(int n)
{
char a[10];
snprintf(a, sizeof(a), "%i", n);
return print( a );
}
/**
* Prints string via write() and goes to next line.
* @param str string to print
* @return returns number of printed symbols
*/
size_t println(const char* str)
{
size_t n = print(str);
n += write('\n');
return n;
};
/**
* Prints number via write() and goes to next line.
* @param data integer to print
* @return returns number of printed symbols
*/
size_t println(int data)
{
size_t n = print(data);
n += write('\n');
return n;
}
};
#endif
#endif
+14
View File
@@ -0,0 +1,14 @@
# Hardware abstraction layer
This directory contain platform specific implementation of hardware abstraction layer.
* arduino dir: for all Arduino platforms (if you use Arduino IDE)
* avr dir: for plain avr-gcc environment
* esp dir: for plain esp8266/esp32 environment
* linux dir: for linux platforms including raspberry pi
* mingw dir: for running under windows
* stm32 dir: for plain stm32 support (not implemented)
* energia dir: for Energia platforms w/ MSP432P401R
Edit UserSettings.h header file, if you want to disable some parts of ssd1306 library to reduce memory consumption in your project
@@ -0,0 +1,96 @@
/*
MIT License
Copyright (c) 2018, Alexey Dynda
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/**
* @file UserSettings.h SSD1306 modules configuration.
*/
#ifndef _USER_SETTINGS_H_
#define _USER_SETTINGS_H_
/**
* @defgroup SSD1306_LIBRARY_CONFIG CONFIG: ssd1306 library configuration
* @{
*
* @brief Group of settings allowing to disable/enable library modules
*
* @details Arduino IDE (at least as for 1.8.2) has a lack library configuration functionality.
* Some Arduino standard libraries are built the way, if you include them to the project,
* but do not use any functions from the, they still eat RAM and Flash on you EVK board.
* To avoid this, you need competely avoid including of such libraries. SSD1306 library
* has a wide interfaces support for different platforms, and even if you don't use
* SSD1306 communication via Arduino Wire/Spi/HardwareSerial libraries, those ones do
* bad things with your sketch size.
* To avoid this you can manually disable SSD1306 modules, you don't need in UserSettings.h
* header file, and gain another 100-200 bytes of RAM and 300-500 bytes of Flash.
*/
/* Comment out options below if you don't need support in the library, *
* and want to reduce memory consumption. */
/** Define this macro if you need to enable software I2C module for compilation */
#define CONFIG_SOFTWARE_I2C_ENABLE
/** Define this macro if you need to enable TWI I2C module for compilation */
#define CONFIG_TWI_I2C_ENABLE
/** Define this macro if you need to enable AVR SPI module for compilation */
#define CONFIG_AVR_SPI_ENABLE
/** Define this macro if you need to enable USI SPI module for compilation */
#define CONFIG_USI_SPI_ENABLE
/** Define this macro if you need to enable AVR UART module for compilation */
#define CONFIG_AVR_UART_ENABLE
/** Define this macro if you need to enable VGA module for compilation */
#define CONFIG_VGA_ENABLE
/** Define this macro if you need to enable Adafruit GFX canvas support for compilation */
#ifndef CONFIG_ADAFRUIT_GFX_ENABLE
//#define CONFIG_ADAFRUIT_GFX_ENABLE
#endif
/**
* Define this macro if platform specific i2c interface is implemented in SSD1306 HAL.
* If you use Arduino platform, this macro enables Arduino Wire library module for compilation.
*/
#define CONFIG_PLATFORM_I2C_ENABLE
/**
* Define this macro if platform specific spi interface is implemented in SSD1306 HAL
* If you use Arduino platform, this macro enables Arduino SPI library module for compilation.
*/
#define CONFIG_PLATFORM_SPI_ENABLE
/**
* Defines, whenever ssd1306 library supports unicode.
* Support of unicode increases RAM and Flasg memory consumption
*/
#define CONFIG_SSD1306_UNICODE_ENABLE
/**
* @}
*/
#endif

Some files were not shown because too many files have changed in this diff Show More