single repo
39
pico-ssd1306/.gitignore
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Compiled Object files
|
||||
*.slo
|
||||
*.lo
|
||||
*.o
|
||||
*.obj
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Compiled Dynamic libraries
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
|
||||
# Fortran module files
|
||||
*.mod
|
||||
*.smod
|
||||
|
||||
# Compiled Static libraries
|
||||
*.lai
|
||||
*.la
|
||||
*.a
|
||||
*.lib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
|
||||
# Ide settings
|
||||
.idea
|
||||
.vscode
|
||||
|
||||
# MacOS
|
||||
.DS_Store
|
||||
13
pico-ssd1306/CMakeLists.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
add_library(pico_ssd1306
|
||||
ssd1306.cpp
|
||||
frameBuffer/FrameBuffer.cpp
|
||||
shapeRenderer/ShapeRenderer.cpp)
|
||||
|
||||
add_subdirectory(textRenderer)
|
||||
|
||||
target_link_libraries(pico_ssd1306
|
||||
ssd1306_textRenderer
|
||||
hardware_i2c
|
||||
pico_stdlib
|
||||
)
|
||||
target_include_directories (pico_ssd1306 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
29
pico-ssd1306/LICENSE
Normal file
@@ -0,0 +1,29 @@
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2021, Harbys
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
19
pico-ssd1306/examples/basic_text/CMakeLists.txt
Normal file
@@ -0,0 +1,19 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
include(pico_sdk_import.cmake)
|
||||
|
||||
project(text_example)
|
||||
|
||||
pico_sdk_init()
|
||||
|
||||
add_subdirectory(pico-ssd1306)
|
||||
|
||||
add_executable(text_example
|
||||
main.cpp)
|
||||
|
||||
target_link_libraries(text_example
|
||||
hardware_i2c
|
||||
pico_ssd1306)
|
||||
|
||||
|
||||
pico_add_extra_outputs(text_example)
|
||||
39
pico-ssd1306/examples/basic_text/main.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
#include "pico/stdlib.h"
|
||||
#include "pico-ssd1306/ssd1306.h"
|
||||
#include "pico-ssd1306/textRenderer/TextRenderer.h"
|
||||
#include "hardware/i2c.h"
|
||||
|
||||
// Use the namespace for convenience
|
||||
using namespace pico_ssd1306;
|
||||
|
||||
int main(){
|
||||
// Init i2c0 controller
|
||||
i2c_init(i2c0, 1000000);
|
||||
// Set up pins 12 and 13
|
||||
gpio_set_function(12, GPIO_FUNC_I2C);
|
||||
gpio_set_function(13, GPIO_FUNC_I2C);
|
||||
gpio_pull_up(12);
|
||||
gpio_pull_up(13);
|
||||
|
||||
// If you don't do anything before initializing a display pi pico is too fast and starts sending
|
||||
// commands before the screen controller had time to set itself up, so we add an artificial delay for
|
||||
// ssd1306 to set itself up
|
||||
sleep_ms(250);
|
||||
|
||||
// Create a new display object at address 0x3D and size of 128x64
|
||||
SSD1306 display = SSD1306(i2c0, 0x3D, Size::W128xH64);
|
||||
|
||||
// Here we rotate the display by 180 degrees, so that it's not upside down from my perspective
|
||||
// If your screen is upside down try setting it to 1 or 0
|
||||
display.setOrientation(0);
|
||||
|
||||
// Draw text on display
|
||||
// After passing a pointer to display, we need to tell the function what font and text to use
|
||||
// Available fonts are listed in textRenderer's readme
|
||||
// Last we tell this function where to anchor the text
|
||||
// Anchor means top left of what we draw
|
||||
drawText(&display, font_12x16, "TEST text", 0 ,0);
|
||||
|
||||
// Send buffer to the display
|
||||
display.sendBuffer();
|
||||
}
|
||||
BIN
pico-ssd1306/examples/basic_text/output.jpg
Executable file
|
After Width: | Height: | Size: 815 KiB |
3
pico-ssd1306/examples/basic_text/readme.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# This examples produces such a result
|
||||
|
||||

|
||||
19
pico-ssd1306/examples/bitmap_image/CMakeLists.txt
Normal file
@@ -0,0 +1,19 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
include(pico_sdk_import.cmake)
|
||||
|
||||
project(bitmap_example)
|
||||
|
||||
pico_sdk_init()
|
||||
|
||||
add_subdirectory(pico-ssd1306)
|
||||
|
||||
add_executable(bitmap_example
|
||||
main.cpp)
|
||||
|
||||
target_link_libraries(bitmap_example
|
||||
hardware_i2c
|
||||
pico_ssd1306)
|
||||
|
||||
|
||||
pico_add_extra_outputs(bitmap_example)
|
||||
55
pico-ssd1306/examples/bitmap_image/main.cpp
Normal file
@@ -0,0 +1,55 @@
|
||||
#include "pico/stdlib.h"
|
||||
#include "pico-ssd1306/ssd1306.h"
|
||||
#include "hardware/i2c.h"
|
||||
|
||||
// Use the namespace for convenience
|
||||
using namespace pico_ssd1306;
|
||||
|
||||
int main() {
|
||||
// Init i2c0 controller
|
||||
i2c_init(i2c0, 1000000);
|
||||
// Set up pins 12 and 13
|
||||
gpio_set_function(12, GPIO_FUNC_I2C);
|
||||
gpio_set_function(13, GPIO_FUNC_I2C);
|
||||
gpio_pull_up(12);
|
||||
gpio_pull_up(13);
|
||||
|
||||
// If you don't do anything before initializing a display pi pico is too fast and starts sending
|
||||
// commands before the screen controller had time to set itself up, so we add an artificial delay for
|
||||
// ssd1306 to set itself up
|
||||
sleep_ms(250);
|
||||
|
||||
// Create a new display object at address 0x3D and size of 128x64
|
||||
SSD1306 display = SSD1306(i2c0, 0x3D, Size::W128xH64);
|
||||
|
||||
// Here we rotate the display by 180 degrees, so that it's not upside down from my perspective
|
||||
// If your screen is upside down try setting it to 1 or 0
|
||||
display.setOrientation(0);
|
||||
|
||||
// Create a variable storing our bitmap image
|
||||
unsigned char image[] = {
|
||||
0b00000001, 0b10000000,
|
||||
0b00000001, 0b10000000,
|
||||
0b00000011, 0b11000000,
|
||||
0b00000010, 0b01000000,
|
||||
0b00000110, 0b11100000,
|
||||
0b00001100, 0b00110000,
|
||||
0b00111001, 0b00011100,
|
||||
0b11101000, 0b01000111,
|
||||
0b11100010, 0b00000111,
|
||||
0b00111000, 0b01011100,
|
||||
0b00001100, 0b10110000,
|
||||
0b00000110, 0b01100000,
|
||||
0b00000011, 0b01000000,
|
||||
0b00000011, 0b11000000,
|
||||
0b00000001, 0b10000000,
|
||||
0b00000001, 0b10000000
|
||||
};
|
||||
|
||||
|
||||
// Add image to buffer with anchor at point x: 10, y:10 and image width: 16 and height:16
|
||||
display.addBitmapImage(10, 10, 16, 16, image);
|
||||
|
||||
// Send buffer to the display
|
||||
display.sendBuffer();
|
||||
}
|
||||
BIN
pico-ssd1306/examples/bitmap_image/output.jpg
Executable file
|
After Width: | Height: | Size: 907 KiB |
3
pico-ssd1306/examples/bitmap_image/readme.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# This examples produces such a result
|
||||
|
||||

|
||||
19
pico-ssd1306/examples/draw_line/CMakeLists.txt
Normal file
@@ -0,0 +1,19 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
include(pico_sdk_import.cmake)
|
||||
|
||||
project(line_example)
|
||||
|
||||
pico_sdk_init()
|
||||
|
||||
add_subdirectory(pico-ssd1306)
|
||||
|
||||
add_executable(line_example
|
||||
main.cpp)
|
||||
|
||||
target_link_libraries(line_example
|
||||
hardware_i2c
|
||||
pico_ssd1306)
|
||||
|
||||
|
||||
pico_add_extra_outputs(line_example)
|
||||
31
pico-ssd1306/examples/draw_line/main.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
#include "pico/stdlib.h"
|
||||
#include "pico-ssd1306/ssd1306.h"
|
||||
#include "pico-ssd1306/shapeRenderer/ShapeRenderer.h"
|
||||
#include "hardware/i2c.h"
|
||||
|
||||
// Use the namespace for convenience
|
||||
using namespace pico_ssd1306;
|
||||
|
||||
int main(){
|
||||
// Init i2c0 controller
|
||||
i2c_init(i2c0, 1000000);
|
||||
// Set up pins 12 and 13
|
||||
gpio_set_function(12, GPIO_FUNC_I2C);
|
||||
gpio_set_function(13, GPIO_FUNC_I2C);
|
||||
gpio_pull_up(12);
|
||||
gpio_pull_up(13);
|
||||
|
||||
// If you don't do anything before initializing a display pi pico is too fast and starts sending
|
||||
// commands before the screen controller had time to set itself up, so we add an artificial delay for
|
||||
// ssd1306 to set itself up
|
||||
sleep_ms(250);
|
||||
|
||||
// Create a new display object at address 0x3D and size of 128x64
|
||||
SSD1306 display = SSD1306(i2c0, 0x3D, Size::W128xH64);
|
||||
|
||||
// Draw a line on display from 0, 0 to 127, 63
|
||||
drawLine(&display, 0, 0 ,127, 63);
|
||||
|
||||
// Send buffer to the display
|
||||
display.sendBuffer();
|
||||
}
|
||||
BIN
pico-ssd1306/examples/draw_line/output.jpg
Normal file
|
After Width: | Height: | Size: 895 KiB |
3
pico-ssd1306/examples/draw_line/readme.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# This examples produces such a result
|
||||
|
||||

|
||||
19
pico-ssd1306/examples/falling_dots/CMakeLists.txt
Normal file
@@ -0,0 +1,19 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
include(pico_sdk_import.cmake)
|
||||
|
||||
project(falling_dots)
|
||||
|
||||
pico_sdk_init()
|
||||
|
||||
add_subdirectory(pico-ssd1306)
|
||||
|
||||
add_executable(falling_dots
|
||||
main.cpp)
|
||||
|
||||
target_link_libraries(falling_dots
|
||||
hardware_i2c
|
||||
pico_ssd1306)
|
||||
|
||||
|
||||
pico_add_extra_outputs(falling_dots)
|
||||
50
pico-ssd1306/examples/falling_dots/main.cpp
Normal file
@@ -0,0 +1,50 @@
|
||||
#include "pico/stdlib.h"
|
||||
#include "pico-ssd1306/ssd1306.h"
|
||||
#include "hardware/i2c.h"
|
||||
|
||||
#pragma ide diagnostic ignored "EndlessLoop"
|
||||
|
||||
// Use the namespace for convenience
|
||||
using namespace pico_ssd1306;
|
||||
|
||||
int main() {
|
||||
// Init i2c0 controller
|
||||
i2c_init(i2c0, 1000000);
|
||||
// Set up pins 12 and 13
|
||||
gpio_set_function(12, GPIO_FUNC_I2C);
|
||||
gpio_set_function(13, GPIO_FUNC_I2C);
|
||||
gpio_pull_up(12);
|
||||
gpio_pull_up(13);
|
||||
|
||||
// If you don't do anything before initializing a display pi pico is too fast and starts sending
|
||||
// commands before the screen controller had time to set itself up, so we add an artificial delay for
|
||||
// ssd1306 to set itself up
|
||||
sleep_ms(250);
|
||||
|
||||
// Create a new display object at address 0x3D and size of 128x64
|
||||
SSD1306 display = SSD1306(i2c0, 0x3D, Size::W128xH64);
|
||||
|
||||
// Here we rotate the display by 180 degrees, so that it's not upside down from my perspective
|
||||
// If your screen is upside down try setting it to 1 or 0
|
||||
display.setOrientation(0);
|
||||
|
||||
|
||||
// variable to count on witch frame we are on
|
||||
uint32_t frame_counter = 0;
|
||||
// Infinite animation loop
|
||||
while (1){
|
||||
|
||||
// Draw pixels spaced 8 px apart, one px lower every frame
|
||||
for (uint8_t pass1 = 0; pass1 < 15; pass1 ++){
|
||||
display.setPixel(pass1 * 8, frame_counter % 63);
|
||||
}
|
||||
// Send buffer to display
|
||||
display.sendBuffer();
|
||||
// Show the frame for 100ms
|
||||
sleep_ms(100);
|
||||
// Clear the buffer
|
||||
display.clear();
|
||||
// Increment frame counter
|
||||
frame_counter ++;
|
||||
}
|
||||
}
|
||||
BIN
pico-ssd1306/examples/falling_dots/output1.jpg
Executable file
|
After Width: | Height: | Size: 902 KiB |
BIN
pico-ssd1306/examples/falling_dots/output2.jpg
Executable file
|
After Width: | Height: | Size: 912 KiB |
BIN
pico-ssd1306/examples/falling_dots/output3.jpg
Executable file
|
After Width: | Height: | Size: 971 KiB |
7
pico-ssd1306/examples/falling_dots/readme.md
Normal file
@@ -0,0 +1,7 @@
|
||||
# This examples produces such a result
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
19
pico-ssd1306/examples/flag/CMakeLists.txt
Normal file
@@ -0,0 +1,19 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
include(pico_sdk_import.cmake)
|
||||
|
||||
project(flag)
|
||||
|
||||
pico_sdk_init()
|
||||
|
||||
add_subdirectory(pico-ssd1306)
|
||||
|
||||
add_executable(flag
|
||||
main.cpp)
|
||||
|
||||
target_link_libraries(flag
|
||||
hardware_i2c
|
||||
pico_ssd1306)
|
||||
|
||||
|
||||
pico_add_extra_outputs(flag)
|
||||
44
pico-ssd1306/examples/flag/main.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
#include "pico/stdlib.h"
|
||||
#include "pico-ssd1306/ssd1306.h"
|
||||
#include "pico-ssd1306/shapeRenderer/ShapeRenderer.h"
|
||||
#include "hardware/i2c.h"
|
||||
|
||||
// Use the namespace for convenience
|
||||
using namespace pico_ssd1306;
|
||||
|
||||
int main() {
|
||||
// Init i2c0 controller
|
||||
i2c_init(i2c0, 1000000);
|
||||
// Set up pins 12 and 13
|
||||
gpio_set_function(12, GPIO_FUNC_I2C);
|
||||
gpio_set_function(13, GPIO_FUNC_I2C);
|
||||
gpio_pull_up(12);
|
||||
gpio_pull_up(13);
|
||||
|
||||
// If you don't do anything before initializing a display pi pico is too fast and starts sending
|
||||
// commands before the screen controller had time to set itself up, so we add an artificial delay for
|
||||
// ssd1306 to set itself up
|
||||
sleep_ms(250);
|
||||
|
||||
// Create a new display object at address 0x3D and size of 128x64
|
||||
SSD1306 display = SSD1306(i2c0, 0x3D, Size::W128xH64);
|
||||
|
||||
// Here we rotate the display by 180 degrees, so that it's not upside down from my perspective
|
||||
// If your screen is upside down try setting it to 1 or 0
|
||||
display.setOrientation(0);
|
||||
|
||||
// Draw an outline
|
||||
drawRect(&display, 0, 0, 127, 63);
|
||||
|
||||
// Draw 2 rectangles
|
||||
fillRect(&display, 0, 0, 63, 31);
|
||||
fillRect(&display, 64, 32, 127, 63);
|
||||
|
||||
// Draw a line across the screen
|
||||
drawLine(&display, 127, 0, 0, 63);
|
||||
|
||||
|
||||
// Send buffer to the display
|
||||
display.sendBuffer();
|
||||
|
||||
}
|
||||
BIN
pico-ssd1306/examples/flag/output1.jpg
Executable file
|
After Width: | Height: | Size: 397 KiB |
5
pico-ssd1306/examples/flag/readme.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# This examples produces such a result
|
||||
|
||||
## Ignore yellow at the bottom (that's just my screen dying from hours of testing and development and some abuse)
|
||||
|
||||

|
||||
19
pico-ssd1306/examples/multiple_displays/CMakeLists.txt
Normal file
@@ -0,0 +1,19 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
include(pico_sdk_import.cmake)
|
||||
|
||||
project(multiple_displays)
|
||||
|
||||
pico_sdk_init()
|
||||
|
||||
add_subdirectory(pico-ssd1306)
|
||||
|
||||
add_executable(multiple_displays
|
||||
main.cpp)
|
||||
|
||||
target_link_libraries(multiple_displays
|
||||
hardware_i2c
|
||||
pico_ssd1306)
|
||||
|
||||
|
||||
pico_add_extra_outputs(multiple_displays)
|
||||
44
pico-ssd1306/examples/multiple_displays/main.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
#include "pico/stdlib.h"
|
||||
#include "pico-ssd1306/ssd1306.h"
|
||||
#include "pico-ssd1306/textRenderer/TextRenderer.h"
|
||||
#include "hardware/i2c.h"
|
||||
|
||||
// Use the namespace for convenience
|
||||
using namespace pico_ssd1306;
|
||||
|
||||
int main() {
|
||||
// Init i2c0 controller
|
||||
i2c_init(i2c0, 1000000);
|
||||
// Set up pins 12 and 13
|
||||
gpio_set_function(12, GPIO_FUNC_I2C);
|
||||
gpio_set_function(13, GPIO_FUNC_I2C);
|
||||
gpio_pull_up(12);
|
||||
gpio_pull_up(13);
|
||||
|
||||
// If you don't do anything before initializing a display pi pico is too fast and starts sending
|
||||
// commands before the screen controller had time to set itself up, so we add an artificial delay for
|
||||
// ssd1306 to set itself up
|
||||
sleep_ms(250);
|
||||
|
||||
// Create a new display object at address 0x3C and size of 128x32
|
||||
SSD1306 display1 = SSD1306(i2c0, 0x3C, Size::W128xH32);
|
||||
|
||||
// Create a new display object at address 0x3D and size of 128x64
|
||||
SSD1306 display2 = SSD1306(i2c0, 0x3D, Size::W128xH64);
|
||||
|
||||
// Here we rotate the display by 180 degrees, so that it's not upside down from my perspective
|
||||
// If your screen is upside down try setting it to 1 or 0
|
||||
display1.setOrientation(0);
|
||||
display2.setOrientation(0);
|
||||
|
||||
// Draw text on display 1
|
||||
drawText(&display1, font_16x32, "Disp 1", 0, 0);
|
||||
|
||||
// Draw text on display 2
|
||||
drawText(&display2, font_16x32, "Disp 2", 0, 0);
|
||||
|
||||
// Send buffer to the displays
|
||||
display1.sendBuffer();
|
||||
display2.sendBuffer();
|
||||
|
||||
}
|
||||
BIN
pico-ssd1306/examples/multiple_displays/output1.jpg
Executable file
|
After Width: | Height: | Size: 363 KiB |
3
pico-ssd1306/examples/multiple_displays/readme.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# This examples produces such a result
|
||||
|
||||

|
||||
53
pico-ssd1306/examples/readme.md
Normal file
@@ -0,0 +1,53 @@
|
||||
# Examples for pico ssd1306 library
|
||||
|
||||
## Core library
|
||||
| Link | Description |
|
||||
|----------------------------------------|-------------------------------------------------|
|
||||
| [bitmap_image](bitmap_image) | Display a simple bitmap image |
|
||||
| [falling_dots](falling_dots) | Animation of dots falling on screen |
|
||||
| [write_mode](write_mode) | Example showing differences between write modes |
|
||||
| [multiple_displays](multiple_displays) | 2 Displays connected to the same i2c controller |
|
||||
|
||||
## Shape Renderer Module
|
||||
| Link | Description |
|
||||
|------------------------|-------------------------------------------------------------------------------|
|
||||
| [draw_line](draw_line) | Example of drawing a line across the screen |
|
||||
| [flag](flag) | Drawing a "flag" on your display. Shows how to use different shape renderers. |
|
||||
|
||||
|
||||
## Text Renderer Module
|
||||
| Link | Description |
|
||||
|--------------------------------------------|----------------------------------------|
|
||||
| [basic_text](basic_text) | Drawing some sample text to the screen |
|
||||
| [text_advanced](text_advanced) | Drawing normal and rotated text |
|
||||
| [text_extended_ascii](text_extended_ascii) | Using extended ASCII chars |
|
||||
|
||||
## How to build an example
|
||||
|
||||
* Clone this project and go into one of the examples
|
||||
```shell
|
||||
git clone https://github.com/Harbys/pico-ssd1306.git
|
||||
cd pico-ssd1306/examples/(choose_an_example)
|
||||
```
|
||||
* Copy pico_sdk_import.cmake from your pico-sdk
|
||||
```shell
|
||||
cp (path_to_pico_sdk)/external/pico_sdk_import.cmake .
|
||||
```
|
||||
* Set the PICO_SDK_PATH environment variable
|
||||
```shell
|
||||
export PICO_SDK_PATH="(path_to_pico_sdk)"
|
||||
```
|
||||
* Create a symlink to the whole library
|
||||
```shell
|
||||
ln -s ../../. pico-ssd1306
|
||||
```
|
||||
* Create a build directory and enter it
|
||||
```shell
|
||||
mkdir build
|
||||
cd build
|
||||
```
|
||||
* Build
|
||||
```shell
|
||||
cmake .. && make
|
||||
```
|
||||
* Copy the uf2 file to your pico
|
||||
19
pico-ssd1306/examples/text_advanced/CMakeLists.txt
Normal file
@@ -0,0 +1,19 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
include(pico_sdk_import.cmake)
|
||||
|
||||
project(text_advanced)
|
||||
|
||||
pico_sdk_init()
|
||||
|
||||
add_subdirectory(pico-ssd1306)
|
||||
|
||||
add_executable(text_advanced
|
||||
main.cpp)
|
||||
|
||||
target_link_libraries(text_advanced
|
||||
hardware_i2c
|
||||
pico_ssd1306)
|
||||
|
||||
|
||||
pico_add_extra_outputs(text_advanced)
|
||||
40
pico-ssd1306/examples/text_advanced/main.cpp
Normal file
@@ -0,0 +1,40 @@
|
||||
#include "pico/stdlib.h"
|
||||
#include "pico-ssd1306/ssd1306.h"
|
||||
#include "pico-ssd1306/textRenderer/TextRenderer.h"
|
||||
#include "hardware/i2c.h"
|
||||
|
||||
// Use the namespace for convenience
|
||||
using namespace pico_ssd1306;
|
||||
|
||||
int main() {
|
||||
// Init i2c0 controller
|
||||
i2c_init(i2c0, 1000000);
|
||||
// Set up pins 12 and 13
|
||||
gpio_set_function(12, GPIO_FUNC_I2C);
|
||||
gpio_set_function(13, GPIO_FUNC_I2C);
|
||||
gpio_pull_up(12);
|
||||
gpio_pull_up(13);
|
||||
|
||||
// If you don't do anything before initializing a display pi pico is too fast and starts sending
|
||||
// commands before the screen controller had time to set itself up, so we add an artificial delay for
|
||||
// ssd1306 to set itself up
|
||||
sleep_ms(250);
|
||||
|
||||
// Create a new display object at address 0x3D and size of 128x64
|
||||
SSD1306 display = SSD1306(i2c0, 0x3D, Size::W128xH64);
|
||||
|
||||
// Here we rotate the display by 180 degrees, so that it's not upside down from my perspective
|
||||
// If your screen is upside down try setting it to 1 or 0
|
||||
display.setOrientation(0);
|
||||
|
||||
// Draw unrotated text
|
||||
drawText(&display, font_8x8, "Text Normal", 16, 0);
|
||||
|
||||
// Draw text rotated by 90 degrees
|
||||
drawText(&display, font_5x8, "Text Rotated", 0, 0, WriteMode::ADD, Rotation::deg90);
|
||||
|
||||
|
||||
// Send buffer to the display
|
||||
display.sendBuffer();
|
||||
|
||||
}
|
||||
BIN
pico-ssd1306/examples/text_advanced/output1.jpg
Executable file
|
After Width: | Height: | Size: 388 KiB |
3
pico-ssd1306/examples/text_advanced/readme.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# This examples produces such a result
|
||||
|
||||

|
||||
19
pico-ssd1306/examples/text_extended_ascii/CMakeLists.txt
Normal file
@@ -0,0 +1,19 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
include(pico_sdk_import.cmake)
|
||||
|
||||
project(text_extended_ascii)
|
||||
|
||||
pico_sdk_init()
|
||||
|
||||
add_subdirectory(pico-ssd1306)
|
||||
|
||||
add_executable(text_extended_ascii
|
||||
main.cpp)
|
||||
|
||||
target_link_libraries(text_extended_ascii
|
||||
hardware_i2c
|
||||
pico_ssd1306)
|
||||
|
||||
|
||||
pico_add_extra_outputs(text_extended_ascii)
|
||||
46
pico-ssd1306/examples/text_extended_ascii/main.cpp
Normal file
@@ -0,0 +1,46 @@
|
||||
// Define SSD1306_ASCII_FULL to use full ascii range (32 - 255)
|
||||
#define SSD1306_ASCII_FULL
|
||||
|
||||
#include "pico/stdlib.h"
|
||||
#include "pico-ssd1306/ssd1306.h"
|
||||
#include "pico-ssd1306/textRenderer/TextRenderer.h"
|
||||
#include "hardware/i2c.h"
|
||||
|
||||
// Use the namespace for convenience
|
||||
using namespace pico_ssd1306;
|
||||
|
||||
int main(){
|
||||
// Init i2c0 controller
|
||||
i2c_init(i2c0, 1000000);
|
||||
// Set up pins 12 and 13
|
||||
gpio_set_function(12, GPIO_FUNC_I2C);
|
||||
gpio_set_function(13, GPIO_FUNC_I2C);
|
||||
gpio_pull_up(12);
|
||||
gpio_pull_up(13);
|
||||
|
||||
// If you don't do anything before initializing a display pi pico is too fast and starts sending
|
||||
// commands before the screen controller had time to set itself up, so we add an artificial delay for
|
||||
// ssd1306 to set itself up
|
||||
sleep_ms(250);
|
||||
|
||||
// Create a new display object at address 0x3D and size of 128x64
|
||||
SSD1306 display = SSD1306(i2c0, 0x3D, Size::W128xH64);
|
||||
|
||||
// Here we rotate the display by 180 degrees, so that it's not upside down from my perspective
|
||||
// If your screen is upside down try setting it to 1 or 0
|
||||
display.setOrientation(0);
|
||||
|
||||
// Draw text on display
|
||||
// After passing a pointer to display, we need to tell the function what font and text to use
|
||||
// Available fonts are listed in textRenderer's readme
|
||||
// Last we tell this function where to anchor the text
|
||||
// Anchor means top left of what we draw
|
||||
// We use \x escape to use chars by their hex numeration according to the ASCII table
|
||||
drawText(&display, font_5x8, "\x24 \xba \xb2", 0 ,0);
|
||||
drawText(&display, font_8x8, "\x24 \xba \xb2", 0 ,10);
|
||||
drawText(&display, font_12x16, "\x24 \xba \xb2", 0 ,20);
|
||||
drawText(&display, font_16x32, "\x24 \xba \xb2", 0 ,36);
|
||||
|
||||
// Send buffer to the display
|
||||
display.sendBuffer();
|
||||
}
|
||||
BIN
pico-ssd1306/examples/text_extended_ascii/output1.jpg
Normal file
|
After Width: | Height: | Size: 3.4 MiB |
3
pico-ssd1306/examples/text_extended_ascii/readme.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# This examples produces such a result
|
||||
|
||||

|
||||
19
pico-ssd1306/examples/write_mode/CMakeLists.txt
Normal file
@@ -0,0 +1,19 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
include(pico_sdk_import.cmake)
|
||||
|
||||
project(write_mode)
|
||||
|
||||
pico_sdk_init()
|
||||
|
||||
add_subdirectory(pico-ssd1306)
|
||||
|
||||
add_executable(write_mode
|
||||
main.cpp)
|
||||
|
||||
target_link_libraries(write_mode
|
||||
hardware_i2c
|
||||
pico_ssd1306)
|
||||
|
||||
|
||||
pico_add_extra_outputs(write_mode)
|
||||
65
pico-ssd1306/examples/write_mode/main.cpp
Normal file
@@ -0,0 +1,65 @@
|
||||
#include "pico/stdlib.h"
|
||||
#include "pico-ssd1306/ssd1306.h"
|
||||
#include "pico-ssd1306/shapeRenderer/ShapeRenderer.h"
|
||||
#include "hardware/i2c.h"
|
||||
|
||||
#pragma ide diagnostic ignored "EndlessLoop"
|
||||
|
||||
// Use the namespace for convenience
|
||||
using namespace pico_ssd1306;
|
||||
|
||||
int main() {
|
||||
// Init i2c0 controller
|
||||
i2c_init(i2c0, 1000000);
|
||||
// Set up pins 12 and 13
|
||||
gpio_set_function(12, GPIO_FUNC_I2C);
|
||||
gpio_set_function(13, GPIO_FUNC_I2C);
|
||||
gpio_pull_up(12);
|
||||
gpio_pull_up(13);
|
||||
|
||||
// If you don't do anything before initializing a display pi pico is too fast and starts sending
|
||||
// commands before the screen controller had time to set itself up, so we add an artificial delay for
|
||||
// ssd1306 to set itself up
|
||||
sleep_ms(250);
|
||||
|
||||
// Create a new display object at address 0x3D and size of 128x64
|
||||
SSD1306 display = SSD1306(i2c0, 0x3D, Size::W128xH64);
|
||||
|
||||
// Here we rotate the display by 180 degrees, so that it's not upside down from my perspective
|
||||
// If your screen is upside down try setting it to 1 or 0
|
||||
display.setOrientation(0);
|
||||
|
||||
// Fill left half of the screen
|
||||
fillRect(&display, 0, 0, 63,63);
|
||||
|
||||
// Create a variable storing a bitmap image
|
||||
unsigned char image[] = {
|
||||
0b00000001, 0b10000000,
|
||||
0b00000001, 0b10000000,
|
||||
0b00000011, 0b11000000,
|
||||
0b00000010, 0b01000000,
|
||||
0b00000110, 0b11100000,
|
||||
0b00001100, 0b00110000,
|
||||
0b00111001, 0b00011100,
|
||||
0b11101000, 0b01000111,
|
||||
0b11100010, 0b00000111,
|
||||
0b00111000, 0b01011100,
|
||||
0b00001100, 0b10110000,
|
||||
0b00000110, 0b01100000,
|
||||
0b00000011, 0b01000000,
|
||||
0b00000011, 0b11000000,
|
||||
0b00000001, 0b10000000,
|
||||
0b00000001, 0b10000000
|
||||
};
|
||||
|
||||
// To see this example at work play with WriteMode
|
||||
// Add will turn pixels on regardless of their state
|
||||
// Subtract will turn pixels off regardless of their state
|
||||
// Invert will swap state of selected pixels
|
||||
display.addBitmapImage(63-8, 31-8, 16, 16, image, WriteMode::INVERT);
|
||||
|
||||
// Send buffer to the display
|
||||
display.sendBuffer();
|
||||
|
||||
|
||||
}
|
||||
BIN
pico-ssd1306/examples/write_mode/output1.jpg
Executable file
|
After Width: | Height: | Size: 421 KiB |
BIN
pico-ssd1306/examples/write_mode/output2.jpg
Executable file
|
After Width: | Height: | Size: 408 KiB |
BIN
pico-ssd1306/examples/write_mode/output3.jpg
Executable file
|
After Width: | Height: | Size: 357 KiB |
12
pico-ssd1306/examples/write_mode/readme.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# This examples produces such a result
|
||||
|
||||
## Ignore yellow at the bottom (that's just my screen dying from hours of testing and development and some abuse)
|
||||
|
||||
### WriteMode::ADD
|
||||

|
||||
|
||||
### WriteMode::SUBTRACT
|
||||

|
||||
|
||||
### WriteMode::INVERT
|
||||

|
||||
43
pico-ssd1306/frameBuffer/FrameBuffer.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
#include "FrameBuffer.h"
|
||||
|
||||
FrameBuffer::FrameBuffer() {
|
||||
this->buffer = new unsigned char[FRAMEBUFFER_SIZE];
|
||||
}
|
||||
|
||||
FrameBuffer::~FrameBuffer() {
|
||||
delete[] this->buffer;
|
||||
}
|
||||
|
||||
void FrameBuffer::byteOR(int n, unsigned char byte) {
|
||||
// return if index outside 0 - buffer length - 1
|
||||
if (n > (FRAMEBUFFER_SIZE-1)) return;
|
||||
this->buffer[n] |= byte;
|
||||
}
|
||||
|
||||
void FrameBuffer::byteAND(int n, unsigned char byte) {
|
||||
// return if index outside 0 - buffer length - 1
|
||||
if (n > (FRAMEBUFFER_SIZE-1)) return;
|
||||
this->buffer[n] &= byte;
|
||||
}
|
||||
|
||||
void FrameBuffer::byteXOR(int n, unsigned char byte) {
|
||||
// return if index outside 0 - buffer length - 1
|
||||
if (n > (FRAMEBUFFER_SIZE-1)) return;
|
||||
this->buffer[n] ^= byte;
|
||||
}
|
||||
|
||||
|
||||
void FrameBuffer::setBuffer(unsigned char *new_buffer) {
|
||||
// free buffer memory to prevent memory leak
|
||||
delete[] this->buffer;
|
||||
this->buffer = new_buffer;
|
||||
}
|
||||
|
||||
void FrameBuffer::clear() {
|
||||
//zeroes out the buffer via memset function from string library
|
||||
memset(this->buffer, 0, FRAMEBUFFER_SIZE);
|
||||
}
|
||||
|
||||
unsigned char *FrameBuffer::get() {
|
||||
return this->buffer;
|
||||
}
|
||||
54
pico-ssd1306/frameBuffer/FrameBuffer.h
Normal file
@@ -0,0 +1,54 @@
|
||||
#ifndef SSD1306_FRAMEBUFFER_H
|
||||
#define SSD1306_FRAMEBUFFER_H
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/// \brief Set frame buffer to 1024 bytes, witch is 128*64 / 8
|
||||
///
|
||||
/// For 128x32 displays it's still 1024 due to how memory mapping works on ssd1306.
|
||||
/// This is explained in readme.md
|
||||
#define FRAMEBUFFER_SIZE 1024
|
||||
|
||||
/// \brief Framebuffer class contains a pointer to buffer and functions for interacting with it
|
||||
class FrameBuffer {
|
||||
unsigned char * buffer;
|
||||
public:
|
||||
/// Constructs frame buffer and allocates memory for buffer
|
||||
FrameBuffer();
|
||||
|
||||
/// Destroys frame buffer and frees buffer memory
|
||||
~FrameBuffer();
|
||||
|
||||
/// \brief Performs OR logical operation on selected and provided byte
|
||||
///
|
||||
/// ex. if byte in buffer at position n is 0b10001111 and provided byte is 0b11110000 the buffer at position n becomes 0b11111111
|
||||
/// \param n - byte offset in buffer array to work on
|
||||
/// \param byte - provided byte to make operation
|
||||
void byteOR(int n, unsigned char byte);
|
||||
|
||||
/// \brief Performs AND logical operation on selected and provided byte
|
||||
///
|
||||
/// ex. if byte in buffer at position n is 0b10001111 and provided byte is 0b11110000 the buffer at position n becomes 0b10000000
|
||||
/// \param n - byte offset in buffer array to work on
|
||||
/// \param byte - provided byte to make operation
|
||||
void byteAND(int n, unsigned char byte);
|
||||
|
||||
/// \brief Performs XOR logical operation on selected and provided byte
|
||||
///
|
||||
/// ex. if byte in buffer at position n is 0b10001111 and provided byte is 0b11110000 the buffer at position n becomes 0b0111111
|
||||
/// \param n - byte offset in buffer array to work on
|
||||
/// \param byte - provided byte to make operation
|
||||
void byteXOR(int n, unsigned char byte);
|
||||
|
||||
/// Replaces pointer with one pointing to a different buffer
|
||||
void setBuffer(unsigned char * new_buffer);
|
||||
|
||||
/// Zeroes out the buffer aka set buffer to all 0
|
||||
void clear();
|
||||
|
||||
/// Returns a pointer to the buffer
|
||||
unsigned char * get();
|
||||
};
|
||||
|
||||
|
||||
#endif //SSD1306_FRAMEBUFFER_H
|
||||
BIN
pico-ssd1306/images/ex1.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
pico-ssd1306/images/ex2.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
pico-ssd1306/images/ex3.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
pico-ssd1306/images/ex4.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
pico-ssd1306/images/ex5.png
Normal file
|
After Width: | Height: | Size: 50 KiB |
75
pico-ssd1306/readme.md
Normal file
@@ -0,0 +1,75 @@
|
||||
# SSD1306 OLED Library for RP2040
|
||||
|
||||
## 1. Importing the library
|
||||
* Clone this project into your pico project
|
||||
* Add this to your CMakeLists.txt
|
||||
```cmake
|
||||
add_subdirectory(pico-ssd1306)
|
||||
target_link_libraries(your_project_name
|
||||
pico_ssd1306
|
||||
# you will also need hardware i2c library for communication with the display
|
||||
hardware_i2c)
|
||||
```
|
||||
* Import library in your code
|
||||
```c++
|
||||
#include "pico-ssd1306/ssd1306.h"
|
||||
```
|
||||
## 2. Basic usage
|
||||
```c++
|
||||
i2c_init(I2C_PORT, 1000000); //Use i2c port with baud rate of 1Mhz
|
||||
//Set pins for I2C operation
|
||||
gpio_set_function(I2C_PIN_SDA, GPIO_FUNC_I2C);
|
||||
gpio_set_function(I2C_PIN_SCL, GPIO_FUNC_I2C);
|
||||
gpio_pull_up(I2C_PIN_SDA);
|
||||
gpio_pull_up(I2C_PIN_SCL);
|
||||
|
||||
//Create a new display object
|
||||
pico_ssd1306::SSD1306 display = pico_ssd1306::SSD1306(I2C_PORT, 0x3D, pico_ssd1306::Size::W128xH64);
|
||||
|
||||
//create a vertical line on x: 64 y:0-63
|
||||
for (int y = 0; y < 64; y++){
|
||||
display.setPixel(64, y);
|
||||
}
|
||||
display.sendBuffer(); //Send buffer to device and show on screen
|
||||
```
|
||||
### Expected output:
|
||||

|
||||
|
||||
You may have noticed that this entire library is under pico_ssd1306 namespace to avoid conflicts, but if you don't have any
|
||||
conflicts and don't want to write ```pico_ssd1306::``` all the time just add
|
||||
```c++
|
||||
using namespace pico_ssd1306;
|
||||
```
|
||||
to your file
|
||||
|
||||
## 3. Principles of operation
|
||||
See [usage explanation](usage.md) for detailed information on how to use core of the lib, but in short:
|
||||
* First Initialize i2c and pins for i2c communication
|
||||
* Create a display object. This automatically send setup commands to the device and prepares it for operation
|
||||
* Modify the buffer containing pixel data
|
||||
* Send buffer to display
|
||||
* Clear the buffer and repeat
|
||||
|
||||
## 4. Pixel Addressing
|
||||

|
||||
|
||||
same is true for 128x32 displays, then y range is 0-31
|
||||
|
||||
## 5. Additional Modules
|
||||
This library comes with additional modules for shape rendering and text rendering to make your life easier
|
||||
### Importing Shape Renderer
|
||||
```c++
|
||||
#include "pico-ssd1306/shapeRenderer/ShapeRenderer.h"
|
||||
```
|
||||
See: [Shape Renderer readme](shapeRenderer/readme.md) for usage and details
|
||||
### Importing Text Renderer
|
||||
```c++
|
||||
#include "pico-ssd1306/textRenderer/TextRenderer.h"
|
||||
```
|
||||
See: [Text Renderer readme](textRenderer/readme.md) for usage and details
|
||||
|
||||
## 6. Examples
|
||||
See [examples](examples). Many of them have their own readmes. Many things are also explained in code comments.
|
||||
|
||||
## 7. Documentation
|
||||
Documentation of all functions is [here](https://ssd1306.harbys.me)
|
||||
80
pico-ssd1306/shapeRenderer/ShapeRenderer.cpp
Normal file
@@ -0,0 +1,80 @@
|
||||
#include "ShapeRenderer.h"
|
||||
|
||||
void pico_ssd1306::drawLine(pico_ssd1306::SSD1306 *ssd1306, uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1,
|
||||
pico_ssd1306::WriteMode mode) {
|
||||
int x, y, dx, dy, dx0, dy0, px, py, xe, ye, i;
|
||||
dx = x1 - x0;
|
||||
dy = y1 - y0;
|
||||
dx0 = fabs(dx);
|
||||
dy0 = fabs(dy);
|
||||
px = 2 * dy0 - dx0;
|
||||
py = 2 * dx0 - dy0;
|
||||
if (dy0 <= dx0) {
|
||||
if (dx >= 0) {
|
||||
x = x0;
|
||||
y = y0;
|
||||
xe = x1;
|
||||
} else {
|
||||
x = x1;
|
||||
y = y1;
|
||||
xe = x0;
|
||||
}
|
||||
ssd1306->setPixel(x, y, mode);
|
||||
for (i = 0; x < xe; i++) {
|
||||
x = x + 1;
|
||||
if (px < 0) {
|
||||
px = px + 2 * dy0;
|
||||
} else {
|
||||
if ((dx < 0 && dy < 0) || (dx > 0 && dy > 0)) {
|
||||
y = y + 1;
|
||||
} else {
|
||||
y = y - 1;
|
||||
}
|
||||
px = px + 2 * (dy0 - dx0);
|
||||
}
|
||||
ssd1306->setPixel(x, y, mode);
|
||||
}
|
||||
} else {
|
||||
if (dy >= 0) {
|
||||
x = x0;
|
||||
y = y0;
|
||||
ye = y1;
|
||||
} else {
|
||||
x = x1;
|
||||
y = y1;
|
||||
ye = y0;
|
||||
}
|
||||
ssd1306->setPixel(x, y, mode);
|
||||
for (i = 0; y < ye; i++) {
|
||||
y = y + 1;
|
||||
if (py <= 0) {
|
||||
py = py + 2 * dx0;
|
||||
} else {
|
||||
if ((dx < 0 && dy < 0) || (dx > 0 && dy > 0)) {
|
||||
x = x + 1;
|
||||
} else {
|
||||
x = x - 1;
|
||||
}
|
||||
py = py + 2 * (dx0 - dy0);
|
||||
}
|
||||
ssd1306->setPixel(x, y, mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pico_ssd1306::drawRect(pico_ssd1306::SSD1306 *ssd1306, uint8_t x_start, uint8_t y_start, uint8_t x_end, uint8_t y_end,
|
||||
pico_ssd1306::WriteMode mode) {
|
||||
drawLine(ssd1306, x_start, y_start, x_end, y_start, mode);
|
||||
drawLine(ssd1306, x_start, y_end, x_end, y_end, mode);
|
||||
drawLine(ssd1306, x_start, y_start, x_start, y_end, mode);
|
||||
drawLine(ssd1306, x_end, y_start, x_end, y_end, mode);
|
||||
}
|
||||
|
||||
void pico_ssd1306::fillRect(pico_ssd1306::SSD1306 *ssd1306, uint8_t x_start, uint8_t y_start, uint8_t x_end, uint8_t y_end,
|
||||
pico_ssd1306::WriteMode mode) {
|
||||
for (uint8_t x = x_start; x <= x_end; x++) {
|
||||
for (uint8_t y = y_start; y <= y_end; y++) {
|
||||
ssd1306->setPixel(x, y, mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
27
pico-ssd1306/shapeRenderer/ShapeRenderer.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#ifndef SSD1306_SHAPERENDERER_H
|
||||
#define SSD1306_SHAPERENDERER_H
|
||||
|
||||
#include <math.h>
|
||||
#include "../ssd1306.h"
|
||||
|
||||
namespace pico_ssd1306{
|
||||
|
||||
/// \brief Draws a line from x0, y0 to x1, y1.
|
||||
/// It supports all drawing angles
|
||||
/// \param ssd1306 - is the pointer to a SSD1306 object aka an initialised display
|
||||
/// \param x0, y0, x1, y1 are the start and end coordinates between which the line will be drawn
|
||||
/// \param mode - mode describes setting behavior. See WriteMode doc for more information
|
||||
void drawLine (pico_ssd1306::SSD1306 *ssd1306, uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, pico_ssd1306::WriteMode mode = pico_ssd1306::WriteMode::ADD);
|
||||
|
||||
/// \brief Draws a 1px wide rectangle between x0, y0 and x1, y1
|
||||
/// \param x_start, x_end, y_start, y_end - corner points for the rectangle
|
||||
/// \param mode - mode describes setting behavior. See WriteMode doc for more information
|
||||
void drawRect (pico_ssd1306::SSD1306 *ssd1306 , uint8_t x_start, uint8_t y_start, uint8_t x_end, uint8_t y_end, pico_ssd1306::WriteMode mode = pico_ssd1306::WriteMode::ADD);
|
||||
|
||||
/// \brief Fills a rectangle from x0, y0 to x1, y1
|
||||
/// \param x_start, x_end, y_start, y_end - corner points for the rectangle
|
||||
/// \param mode - mode describes setting behavior. See WriteMode doc for more information
|
||||
void fillRect (pico_ssd1306::SSD1306 *ssd1306 , uint8_t x_start, uint8_t y_start, uint8_t x_end, uint8_t y_end, pico_ssd1306::WriteMode mode = pico_ssd1306::WriteMode::ADD);
|
||||
}
|
||||
|
||||
#endif //SSD1306_SHAPERENDERER_H
|
||||
27
pico-ssd1306/shapeRenderer/readme.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# Shape Renderer Module
|
||||
## This module provides functions for drawing basic geometrical shapes with simple code
|
||||
|
||||
## 1. Importing
|
||||
```c++
|
||||
#include "pico-ssd1306/shapeRenderer/ShapeRenderer.h"
|
||||
```
|
||||
note that core library and hardware_i2c library's need to be imported to use this library so follow steps from section 1
|
||||
of [readme.md](../readme.md)
|
||||
|
||||
## 2. Differences from core library
|
||||
Calling functions from modules is different from core lib. You can't just do ```object.drawLine(...``` since modules don't
|
||||
actually extend the SSD1306 class. You need to provide module functions with a pointer to a display object. So the first
|
||||
argument of every module draw function is a pointer to a display.
|
||||
|
||||
To see this more clearly here is an example:
|
||||
```c++
|
||||
// Create a new display object
|
||||
pico_ssd1306::SSD1306 display = pico_ssd1306::SSD1306(I2C_PORT, 0x3D, pico_ssd1306::Size::W128xH64);
|
||||
|
||||
// Draw a line from x: 0, y: 0 to x: 128, y: 64
|
||||
// Notice how we first pass the address of display object to the function
|
||||
pico_ssd1306::drawLine(&display, 0, 0, 128, 64);
|
||||
|
||||
```
|
||||
|
||||
## All functions are documented [here](https://ssd1306.harbys.me)
|
||||
187
pico-ssd1306/ssd1306.cpp
Normal file
@@ -0,0 +1,187 @@
|
||||
#include "ssd1306.h"
|
||||
|
||||
namespace pico_ssd1306 {
|
||||
SSD1306::SSD1306(i2c_inst *i2CInst, uint16_t Address, Size size) {
|
||||
// Set class instanced variables
|
||||
this->i2CInst = i2CInst;
|
||||
this->address = Address;
|
||||
this->size = size;
|
||||
|
||||
this->width = 128;
|
||||
|
||||
if (size == Size::W128xH32) {
|
||||
this->height = 32;
|
||||
} else {
|
||||
this->height = 64;
|
||||
}
|
||||
|
||||
// display is not inverted by default
|
||||
this->inverted = false;
|
||||
|
||||
// this is a list of setup commands for the display
|
||||
uint8_t setup[] = {
|
||||
SSD1306_DISPLAY_OFF,
|
||||
SSD1306_LOWCOLUMN,
|
||||
SSD1306_HIGHCOLUMN,
|
||||
SSD1306_STARTLINE,
|
||||
|
||||
SSD1306_MEMORYMODE,
|
||||
SSD1306_MEMORYMODE_HORZONTAL,
|
||||
|
||||
SSD1306_CONTRAST,
|
||||
0xFF,
|
||||
|
||||
SSD1306_INVERTED_OFF,
|
||||
|
||||
SSD1306_MULTIPLEX,
|
||||
63,
|
||||
|
||||
SSD1306_DISPLAYOFFSET,
|
||||
0x00,
|
||||
|
||||
SSD1306_DISPLAYCLOCKDIV,
|
||||
0x80,
|
||||
|
||||
SSD1306_PRECHARGE,
|
||||
0x22,
|
||||
|
||||
SSD1306_COMPINS,
|
||||
0x12,
|
||||
|
||||
SSD1306_VCOMDETECT,
|
||||
0x40,
|
||||
|
||||
SSD1306_CHARGEPUMP,
|
||||
0x14,
|
||||
|
||||
SSD1306_DISPLAYALL_ON_RESUME,
|
||||
SSD1306_DISPLAY_ON
|
||||
};
|
||||
|
||||
// send each one of the setup commands
|
||||
for (uint8_t &command: setup) {
|
||||
this->cmd(command);
|
||||
}
|
||||
|
||||
// clear the buffer and send it to the display
|
||||
// if not done display shows garbage data
|
||||
this->clear();
|
||||
this->sendBuffer();
|
||||
|
||||
}
|
||||
|
||||
void SSD1306::setPixel(int16_t x, int16_t y, WriteMode mode) {
|
||||
// return if position out of bounds
|
||||
if ((x < 0) || (x >= this->width) || (y < 0) || (y >= this->height)) return;
|
||||
|
||||
// byte to be used for buffer operation
|
||||
uint8_t byte;
|
||||
|
||||
// display with 32 px height requires doubling of set bits, reason to this is explained in readme
|
||||
// this shifts 1 to byte based on y coordinate
|
||||
// remember that buffer is a one dimension array, so we have to calculate offset from coordinates
|
||||
if (size == Size::W128xH32) {
|
||||
y = (y << 1) + 1;
|
||||
byte = 1 << (y & 7);
|
||||
char byte_offset = byte >> 1;
|
||||
byte = byte | byte_offset;
|
||||
} else {
|
||||
byte = 1 << (y & 7);
|
||||
}
|
||||
|
||||
// check the write mode and manipulate the frame buffer
|
||||
if (mode == WriteMode::ADD) {
|
||||
this->frameBuffer.byteOR(x + (y / 8) * this->width, byte);
|
||||
} else if (mode == WriteMode::SUBTRACT) {
|
||||
this->frameBuffer.byteAND(x + (y / 8) * this->width, ~byte);
|
||||
} else if (mode == WriteMode::INVERT) {
|
||||
this->frameBuffer.byteXOR(x + (y / 8) * this->width, byte);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void SSD1306::sendBuffer() {
|
||||
this->cmd(SSD1306_PAGEADDR); //Set page address from min to max
|
||||
this->cmd(0x00);
|
||||
this->cmd(0x07);
|
||||
this->cmd(SSD1306_COLUMNADDR); //Set column address from min to max
|
||||
this->cmd(0x00);
|
||||
this->cmd(127);
|
||||
|
||||
// create a temporary buffer of size of buffer plus 1 byte for startline command aka 0x40
|
||||
unsigned char data[FRAMEBUFFER_SIZE + 1];
|
||||
|
||||
data[0] = SSD1306_STARTLINE;
|
||||
|
||||
// copy framebuffer to temporary buffer
|
||||
memcpy(data + 1, frameBuffer.get(), FRAMEBUFFER_SIZE);
|
||||
|
||||
// send data to device
|
||||
i2c_write_blocking(this->i2CInst, this->address, data, FRAMEBUFFER_SIZE + 1, false);
|
||||
}
|
||||
|
||||
void SSD1306::clear() {
|
||||
this->frameBuffer.clear();
|
||||
}
|
||||
|
||||
void SSD1306::setOrientation(bool orientation) {
|
||||
// remap columns and rows scan direction, effectively flipping the image on display
|
||||
if (orientation) {
|
||||
this->cmd(SSD1306_CLUMN_REMAP_OFF);
|
||||
this->cmd(SSD1306_COM_REMAP_OFF);
|
||||
} else {
|
||||
this->cmd(SSD1306_CLUMN_REMAP_ON);
|
||||
this->cmd(SSD1306_COM_REMAP_ON);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SSD1306::addBitmapImage(int16_t anchorX, int16_t anchorY, uint8_t image_width, uint8_t image_height,
|
||||
uint8_t *image,
|
||||
WriteMode mode) {
|
||||
uint8_t byte;
|
||||
// goes over every single bit in image and sets pixel data on its coordinates
|
||||
for (uint8_t y = 0; y < image_height; y++) {
|
||||
for (uint8_t x = 0; x < image_width / 8; x++) {
|
||||
byte = image[y * (image_width / 8) + x];
|
||||
for (uint8_t z = 0; z < 8; z++) {
|
||||
if ((byte >> (7 - z)) & 1) {
|
||||
this->setPixel(x * 8 + z + anchorX, y + anchorY, mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SSD1306::invertDisplay() {
|
||||
this->cmd(SSD1306_INVERTED_OFF | !this->inverted);
|
||||
inverted = !inverted;
|
||||
}
|
||||
|
||||
void SSD1306::cmd(unsigned char command) {
|
||||
// 0x00 is a byte indicating to ssd1306 that a command is being sent
|
||||
uint8_t data[2] = {0x00, command};
|
||||
i2c_write_blocking(this->i2CInst, this->address, data, 2, false);
|
||||
}
|
||||
|
||||
|
||||
void SSD1306::setContrast(unsigned char contrast) {
|
||||
this->cmd(SSD1306_CONTRAST);
|
||||
this->cmd(contrast);
|
||||
}
|
||||
|
||||
void SSD1306::setBuffer(unsigned char * buffer) {
|
||||
this->frameBuffer.setBuffer(buffer);
|
||||
}
|
||||
|
||||
void SSD1306::turnOff() {
|
||||
this->cmd(SSD1306_DISPLAY_OFF);
|
||||
}
|
||||
|
||||
void SSD1306::turnOn() {
|
||||
this->cmd(SSD1306_DISPLAY_ON);
|
||||
}
|
||||
|
||||
}
|
||||
134
pico-ssd1306/ssd1306.h
Normal file
@@ -0,0 +1,134 @@
|
||||
#ifndef SSD1306_SSD1306_H
|
||||
#define SSD1306_SSD1306_H
|
||||
|
||||
#include <string.h>
|
||||
#include "hardware/i2c.h"
|
||||
#include "frameBuffer/FrameBuffer.h"
|
||||
|
||||
namespace pico_ssd1306 {
|
||||
/// Register addresses from datasheet
|
||||
enum REG_ADDRESSES : unsigned char{
|
||||
SSD1306_CONTRAST = 0x81,
|
||||
SSD1306_DISPLAYALL_ON_RESUME = 0xA4,
|
||||
SSD1306_DISPLAYALL_ON = 0xA5,
|
||||
SSD1306_INVERTED_OFF = 0xA6,
|
||||
SSD1306_INVERTED_ON = 0xA7,
|
||||
SSD1306_DISPLAY_OFF = 0xAE,
|
||||
SSD1306_DISPLAY_ON = 0xAF,
|
||||
SSD1306_DISPLAYOFFSET = 0xD3,
|
||||
SSD1306_COMPINS = 0xDA,
|
||||
SSD1306_VCOMDETECT = 0xDB,
|
||||
SSD1306_DISPLAYCLOCKDIV = 0xD5,
|
||||
SSD1306_PRECHARGE = 0xD9,
|
||||
SSD1306_MULTIPLEX = 0xA8,
|
||||
SSD1306_LOWCOLUMN = 0x00,
|
||||
SSD1306_HIGHCOLUMN = 0x10,
|
||||
SSD1306_STARTLINE = 0x40,
|
||||
SSD1306_MEMORYMODE = 0x20,
|
||||
SSD1306_MEMORYMODE_HORZONTAL = 0x00,
|
||||
SSD1306_MEMORYMODE_VERTICAL = 0x01,
|
||||
SSD1306_MEMORYMODE_PAGE = 0x10,
|
||||
SSD1306_COLUMNADDR = 0x21,
|
||||
SSD1306_PAGEADDR = 0x22,
|
||||
SSD1306_COM_REMAP_OFF = 0xC0,
|
||||
SSD1306_COM_REMAP_ON = 0xC8,
|
||||
SSD1306_CLUMN_REMAP_OFF = 0xA0,
|
||||
SSD1306_CLUMN_REMAP_ON = 0xA1,
|
||||
SSD1306_CHARGEPUMP = 0x8D,
|
||||
SSD1306_EXTERNALVCC = 0x1,
|
||||
SSD1306_SWITCHCAPVCC = 0x2,
|
||||
};
|
||||
|
||||
/// \enum pico_ssd1306::Size
|
||||
enum class Size {
|
||||
/// Display size W128xH64
|
||||
W128xH64,
|
||||
/// Display size W128xH32
|
||||
W128xH32
|
||||
};
|
||||
|
||||
/// \enum pico_ssd1306::WriteMode
|
||||
enum class WriteMode : const unsigned char{
|
||||
/// sets pixel on regardless of its state
|
||||
ADD = 0,
|
||||
/// sets pixel off regardless of its state
|
||||
SUBTRACT = 1,
|
||||
/// inverts pixel, so 1->0 or 0->1
|
||||
INVERT = 2,
|
||||
};
|
||||
|
||||
/// \class SSD1306 ssd1306.h "pico-ssd1306/ssd1306.h"
|
||||
/// \brief SSD1306 class represents i2c connection to display
|
||||
class SSD1306 {
|
||||
private:
|
||||
i2c_inst *i2CInst;
|
||||
uint16_t address;
|
||||
Size size;
|
||||
|
||||
FrameBuffer frameBuffer;
|
||||
|
||||
uint8_t width, height;
|
||||
|
||||
bool inverted;
|
||||
|
||||
/// \brief Sends single 8bit command to ssd1306 controller
|
||||
/// \param command - byte to be sent to controller
|
||||
void cmd(unsigned char command);
|
||||
|
||||
public:
|
||||
/// \brief SSD1306 constructor initialized display and sets all required registers for operation
|
||||
/// \param i2CInst - i2c instance. Either i2c0 or i2c1
|
||||
/// \param Address - display i2c address. usually for 128x32 0x3C and for 128x64 0x3D
|
||||
/// \param size - display size. Acceptable values W128xH32 or W128xH64
|
||||
SSD1306(i2c_inst *i2CInst, uint16_t Address, Size size);
|
||||
|
||||
/// \brief Set pixel operates frame buffer
|
||||
/// x is the x position of pixel you want to change. values 0 - 127
|
||||
/// y is the y position of pixel you want to change. values 0 - 31 or 0 - 63
|
||||
/// \param x - position of pixel you want to change. values 0 - 127
|
||||
/// \param y - position of pixel you want to change. values 0 - 31 or 0 - 63
|
||||
/// \param mode - mode describes setting behavior. See WriteMode doc for more information
|
||||
void setPixel(int16_t x, int16_t y, WriteMode mode = WriteMode::ADD);
|
||||
|
||||
/// \brief Sends frame buffer to display so that it updated
|
||||
void sendBuffer();
|
||||
|
||||
/// \brief Adds bitmap image to frame buffer
|
||||
/// \param anchorX - sets start point of where to put the image on the screen
|
||||
/// \param anchorY - sets start point of where to put the image on the screen
|
||||
/// \param image_width - width of the image in pixels
|
||||
/// \param image_height - height of the image in pixels
|
||||
/// \param image - pointer to uint8_t (unsigned char) array containing image data
|
||||
/// \param mode - mode describes setting behavior. See WriteMode doc for more information
|
||||
void addBitmapImage(int16_t anchorX, int16_t anchorY, uint8_t image_width, uint8_t image_height, uint8_t *image,
|
||||
WriteMode mode = WriteMode::ADD);
|
||||
|
||||
/// \brief Manually set frame buffer. make sure it's correct size of 1024 bytes
|
||||
/// \param buffer - pointer to a new buffer
|
||||
void setBuffer(unsigned char *buffer);
|
||||
|
||||
/// \brief Flips the display
|
||||
/// \param orientation - 0 for not flipped, 1 for flipped display
|
||||
void setOrientation(bool orientation);
|
||||
|
||||
|
||||
/// \brief Clears frame buffer aka set all bytes to 0
|
||||
void clear();
|
||||
|
||||
/// \brief Inverts screen on hardware level. Way more efficient than setting buffer to all ones and then using WriteMode subtract.
|
||||
void invertDisplay();
|
||||
|
||||
/// \brief Sets display contrast according to ssd1306 documentation
|
||||
/// \param contrast - accepted values of 0 to 255 to set the contrast
|
||||
void setContrast(unsigned char contrast);
|
||||
|
||||
/// \brief Turns display off
|
||||
void turnOff();
|
||||
|
||||
/// \brief Turns display on
|
||||
void turnOn();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif //SSD1306_SSD1306_H
|
||||
7991
pico-ssd1306/textRenderer/12x16_font.h
Normal file
10543
pico-ssd1306/textRenderer/16x32_font.h
Normal file
1930
pico-ssd1306/textRenderer/5x8_font.h
Normal file
2887
pico-ssd1306/textRenderer/8x8_font.h
Normal file
12
pico-ssd1306/textRenderer/CMakeLists.txt
Normal file
@@ -0,0 +1,12 @@
|
||||
add_library(ssd1306_textRenderer
|
||||
TextRenderer.cpp
|
||||
5x8_font.h
|
||||
8x8_font.h
|
||||
12x16_font.h
|
||||
16x32_font.h
|
||||
)
|
||||
|
||||
target_link_libraries(ssd1306_textRenderer
|
||||
hardware_i2c
|
||||
pico_stdlib
|
||||
)
|
||||
57
pico-ssd1306/textRenderer/TextRenderer.cpp
Normal file
@@ -0,0 +1,57 @@
|
||||
#include "TextRenderer.h"
|
||||
|
||||
namespace pico_ssd1306 {
|
||||
|
||||
void drawText(pico_ssd1306::SSD1306 *ssd1306, const unsigned char *font, const char *text, uint8_t anchor_x,
|
||||
uint8_t anchor_y, WriteMode mode, Rotation rotation) {
|
||||
if(!ssd1306 || !font || !text) return;
|
||||
|
||||
uint8_t font_width = font[0];
|
||||
|
||||
uint16_t n = 0;
|
||||
while (text[n] != '\0') {
|
||||
switch (rotation) {
|
||||
case Rotation::deg0:
|
||||
drawChar(ssd1306, font, text[n], anchor_x + (n * font_width), anchor_y, mode, rotation);
|
||||
break;
|
||||
case Rotation::deg90:
|
||||
drawChar(ssd1306, font, text[n], anchor_x, anchor_y + (n * font_width), mode, rotation);
|
||||
break;
|
||||
}
|
||||
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
void drawChar(pico_ssd1306::SSD1306 *ssd1306, const unsigned char *font, char c, uint8_t anchor_x, uint8_t anchor_y,
|
||||
WriteMode mode, Rotation rotation) {
|
||||
if(!ssd1306 || !font || c < 32) return;
|
||||
|
||||
uint8_t font_width = font[0];
|
||||
uint8_t font_height = font[1];
|
||||
|
||||
uint16_t seek = (c - 32) * (font_width * font_height) / 8 + 2;
|
||||
|
||||
uint8_t b_seek = 0;
|
||||
|
||||
for (uint8_t x = 0; x < font_width; x++) {
|
||||
for (uint8_t y = 0; y < font_height; y++) {
|
||||
if (font[seek] >> b_seek & 0b00000001) {
|
||||
switch (rotation) {
|
||||
case Rotation::deg0:
|
||||
ssd1306->setPixel(x + anchor_x, y + anchor_y, mode);
|
||||
break;
|
||||
case Rotation::deg90:
|
||||
ssd1306->setPixel(-y + anchor_x + font_height, x + anchor_y, mode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
b_seek++;
|
||||
if (b_seek == 8) {
|
||||
b_seek = 0;
|
||||
seek++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
40
pico-ssd1306/textRenderer/TextRenderer.h
Normal file
@@ -0,0 +1,40 @@
|
||||
#ifndef SSD1306_TEXTRENDERER_H
|
||||
#define SSD1306_TEXTRENDERER_H
|
||||
|
||||
#include "../ssd1306.h"
|
||||
|
||||
#include "5x8_font.h"
|
||||
#include "8x8_font.h"
|
||||
#include "12x16_font.h"
|
||||
#include "16x32_font.h"
|
||||
|
||||
namespace pico_ssd1306{
|
||||
|
||||
/// \enum pico_ssd1306::Rotation
|
||||
enum class Rotation{
|
||||
/// deg0 - means no rotation
|
||||
deg0,
|
||||
/// deg 90 - means 90 deg rotation
|
||||
deg90,
|
||||
};
|
||||
|
||||
/// \brief Draws a single glyph on the screen
|
||||
/// \param ssd1306 - pointer to a SSD1306 object aka initialised display
|
||||
/// \param font - pointer to a font data array
|
||||
/// \param c - char to be drawn
|
||||
/// \param anchor_x, anchor_y - coordinates setting where to put the glyph
|
||||
/// \param mode - mode describes setting behavior. See WriteMode doc for more information
|
||||
/// \param rotation - either rotates the char by 90 deg or leaves it unrotated
|
||||
void drawChar(pico_ssd1306::SSD1306 *ssd1306, const unsigned char * font, char c, uint8_t anchor_x, uint8_t anchor_y, WriteMode mode = WriteMode::ADD, Rotation rotation = Rotation::deg0);
|
||||
|
||||
/// \brief Draws text on screen
|
||||
/// \param ssd1306 - pointer to a SSD1306 object aka initialised display
|
||||
/// \param font - pointer to a font data array
|
||||
/// \param text - text to be drawn
|
||||
/// \param anchor_x, anchor_y - coordinates setting where to put the text
|
||||
/// \param mode - mode describes setting behavior. See WriteMode doc for more information
|
||||
/// \param rotation - either rotates the text by 90 deg or leaves it unrotated
|
||||
void drawText(pico_ssd1306::SSD1306 *ssd1306, const unsigned char * font, const char * text, uint8_t anchor_x, uint8_t anchor_y, WriteMode mode = WriteMode::ADD, Rotation rotation = Rotation::deg0);
|
||||
}
|
||||
|
||||
#endif //SSD1306_TEXTRENDERER_H
|
||||
60
pico-ssd1306/textRenderer/readme.md
Normal file
@@ -0,0 +1,60 @@
|
||||
# Text Renderer Module
|
||||
## This module provides functions for drawing chars and text on ssd1306 displays
|
||||
|
||||
## 1. Importing
|
||||
```c++
|
||||
#include "pico-ssd1306/textRenderer/TextRenderer.h"
|
||||
```
|
||||
note that core library and hardware_i2c library's need to be imported to use this library so follow steps from section 1
|
||||
of [readme.md](../readme.md)
|
||||
|
||||
## 2. Differences from core library
|
||||
Calling functions from modules is different from core lib. You can't just do ```object.drawText(...``` since modules don't
|
||||
actually extend the SSD1306 class. You need to provide module functions with a pointer to a display object. So the first
|
||||
argument of every module draw function is a pointer to a display.
|
||||
|
||||
To see this more clearly here is an example:
|
||||
```c++
|
||||
// Create a new display object
|
||||
pico_ssd1306::SSD1306 display = pico_ssd1306::SSD1306(I2C_PORT, 0x3D, pico_ssd1306::Size::W128xH64);
|
||||
|
||||
// Draw some text
|
||||
// Notice how we first pass the address of display object to the function
|
||||
drawText(&display, font_12x16, "TEST text", 0 ,0);
|
||||
```
|
||||
|
||||
## 3. Available fonts
|
||||
This module comes with 4 fonts to choose from
|
||||
* font_5x8 - 5px wide, 8px high font
|
||||
* font_8x8 - 8px wide, 8px high font
|
||||
* font_12x16 - 12px wide, 16px high font
|
||||
* font_16x32 - 16px wide, 32px high font
|
||||
|
||||
Basic fonts support basic ASCII set chars (32-127), if you want to extended ASCII define
|
||||
```c++
|
||||
#define SSD1306_ASCII_FULL
|
||||
```
|
||||
at the top of your file
|
||||
|
||||
#### Note that using extended ASCII range increases project size
|
||||
|
||||
### Creating your own fonts
|
||||
doing so is not that hard
|
||||
a font is just a large array of bytes
|
||||
```c++
|
||||
const unsigned char font_16x32[] = {
|
||||
...
|
||||
};
|
||||
```
|
||||
the first 2 bytes are font's width and height
|
||||
```c++
|
||||
const unsigned char font_16x32[] = {
|
||||
0x10, 0x20, // font width, height
|
||||
...
|
||||
};
|
||||
```
|
||||
then followed by char data for ascii characters 32 - 126
|
||||
|
||||
Unlike bitmap images in the core library, fonts are scanned right to left, top to bottom
|
||||
|
||||
## All functions are documented [here](https://ssd1306.harbys.me)
|
||||
149
pico-ssd1306/usage.md
Normal file
@@ -0,0 +1,149 @@
|
||||
# Using the core library
|
||||
|
||||
## 1. Setting up the i2c ports
|
||||
In order to communicate with the display you need to set up pico's i2c communication
|
||||
|
||||
### Add hardware_i2c library to CMakeLists.txt
|
||||
```cmake
|
||||
target_link_libraries(project_name
|
||||
hardware_i2c)
|
||||
```
|
||||
|
||||
### Add the ssd1306 library to your project
|
||||
This is explained in [readme.md](readme.md) section 1
|
||||
|
||||
|
||||
### Set up i2c
|
||||
Pico has 2 i2c controllers. You can use any of these, just remember to pass according i2c instance in code
|
||||
|
||||
for this example pins 12 and 13 are used for sda and scl lines. These are connected to i2c0 controller. You can use any
|
||||
pins capable of i2c communication but if they are connected to i2c1 controller you'll need to change the code when
|
||||
initializing i2c communication and when creating a display object
|
||||
|
||||
#### imports:
|
||||
you need
|
||||
```c++
|
||||
#include "hardware/i2c.h"
|
||||
#include "pico-ssd1306/ssd1306.h"
|
||||
```
|
||||
i2c init and pin init:
|
||||
```c++
|
||||
i2c_init(i2c0, 1000000); // Init i2c0 and set baud rate to 1Mhz (max supported speed by pico)
|
||||
// lower baud rates make the communication slower, and since this lib uses blocking writing,
|
||||
// lower baud rates lower maximal achievable frame rate
|
||||
gpio_set_function(12, GPIO_FUNC_I2C); // Set pins 12 and 13 for i2c role
|
||||
gpio_set_function(13, GPIO_FUNC_I2C);
|
||||
gpio_pull_up(12); // Pull up the pins for proper communication
|
||||
gpio_pull_up(13);
|
||||
```
|
||||
|
||||
## 2. Create a display object
|
||||
When creating a display object you need to provide 3 arguments. Witch i2c controller you want to use (the one you
|
||||
initialized above), display address (usually 0x3C or 0x3D with ssd1306) and display size. This library defines 2
|
||||
available sizes Size::W128xH64 and Size::W128xH32
|
||||
```c++
|
||||
pico_ssd1306::SSD1306 display = pico_ssd1306::SSD1306(i2c0, 0x3D, pico_ssd1306::Size::W128xH64);
|
||||
```
|
||||
|
||||
## 3. A few words on how this works
|
||||
From now on you can use the display object to draw anything you want to the display.
|
||||
Core of ssd1306 library exposes 2 functions for drawing (documentation of all functions is here [doxygen](https://ssd1306.harbys.me)).
|
||||
```setPixel()``` and ```addBitmapImage()``` but just calling these won't draw anything on screen. These functions only affect the buffer.
|
||||
To actually display something you need to first draw to buffer (by ```setPixel()``` or ```addBitmapImage()```) and then sending it to the
|
||||
display with ```sendBuffer()```. Same is true for ```clear()``` function. It just clears the buffer, not the screen. so
|
||||
calling ```clear()``` and ```sendBuffer()``` will actually clear the display.
|
||||
|
||||
## 4. Turning on a pixel
|
||||
```setPixel()``` is pretty self-explanatory. It modifies the state of exactly 1 pixel. Just give it the x and y coordinates,
|
||||
optionally change the write mode and done. If you're confused about write mode see [doxygen](https://ssd1306.harbys.me)
|
||||
section about write mode. tldr write mode decides whether a pixel is to be set on, off or inverted (on to off and vice versa)
|
||||
|
||||
this example set pixel at x = 0 and y = 0 (top left corner) on
|
||||
```c++
|
||||
//Create a new display object
|
||||
pico_ssd1306::SSD1306 display = pico_ssd1306::SSD1306(I2C_PORT, 0x3D, pico_ssd1306::Size::W128xH64);
|
||||
|
||||
display.setPixel(0, 0);
|
||||
|
||||
display.sendBuffer();
|
||||
```
|
||||
|
||||
## 5. Displaying an image
|
||||
|
||||
### How to prepare an image for pico
|
||||
Well you can't just shove a png file into c++ and expect it to work. We need a bitmap containing data on which pixels
|
||||
to turn on. This library scans bytes in bit map left to right, top to bottom, so :
|
||||
```c++
|
||||
#define IMAGE_WIDTH 32
|
||||
#define IMAGE_HEIGHT 32
|
||||
uint8_t image[128] = {
|
||||
0b00100000, 0b00000001, 0b00000000, 0b00000100,
|
||||
0b00100000, 0b00000001, 0b00000000, 0b00000100,
|
||||
0b00100000, 0b00000001, 0b00000000, 0b00000100,
|
||||
0b00100000, 0b00000001, 0b00000000, 0b00000100,
|
||||
0b00100000, 0b00000001, 0b00000000, 0b00000100,
|
||||
0b00100000, 0b00000001, 0b00000000, 0b00000100,
|
||||
0b00100000, 0b00000001, 0b00000000, 0b00000100,
|
||||
0b00100000, 0b00000001, 0b00000000, 0b00000100,
|
||||
0b00100000, 0b00000001, 0b00000000, 0b00000100,
|
||||
0b00100000, 0b00000001, 0b00000000, 0b00000100,
|
||||
0b00100000, 0b00000001, 0b00000000, 0b00000100,
|
||||
0b00100000, 0b00000001, 0b00000000, 0b00000100,
|
||||
0b00100000, 0b00000001, 0b00000000, 0b00000100,
|
||||
0b00100000, 0b00000001, 0b00000000, 0b00000100,
|
||||
0b00100000, 0b00000001, 0b00000000, 0b00000100,
|
||||
0b00111111, 0b11111111, 0b11111111, 0b11111100,
|
||||
0b00100000, 0b00000001, 0b00000000, 0b00000100,
|
||||
0b00100000, 0b00000001, 0b00000000, 0b00000100,
|
||||
0b00100000, 0b00000001, 0b00000000, 0b00000100,
|
||||
0b00100000, 0b00000001, 0b00000000, 0b00000100,
|
||||
0b00100000, 0b00000001, 0b00000000, 0b00000100,
|
||||
0b00100000, 0b00000001, 0b00000000, 0b00000100,
|
||||
0b00100000, 0b00000001, 0b00000000, 0b00000100,
|
||||
0b00100000, 0b00000001, 0b00000000, 0b00000100,
|
||||
0b00100000, 0b00000001, 0b00000000, 0b00000100,
|
||||
0b00100000, 0b00000001, 0b00000000, 0b00000100,
|
||||
0b00100000, 0b00000001, 0b00000000, 0b00000100,
|
||||
0b00100000, 0b00000001, 0b00000000, 0b00000100,
|
||||
0b00100000, 0b00000001, 0b00000000, 0b00000100,
|
||||
0b00100000, 0b00000001, 0b00000000, 0b00000100,
|
||||
0b00100000, 0b00000001, 0b00000000, 0b00000100,
|
||||
0b00100000, 0b00000001, 0b00000000, 0b00000100
|
||||
};
|
||||
```
|
||||
contains such an image:
|
||||
|
||||

|
||||
|
||||
It's best to keep width to a number divisible by 8. Otherwise, errors occur while shifting bytes and rendering fails.
|
||||
Height does not have such a limitation.
|
||||
|
||||
### Bitmap to display
|
||||
```addBitmapImage()``` function does pretty much all the work for us. we need to tell it what and where to draw and done.
|
||||
So what do we need? x and y coordinated on where to anchor an image (anchor is top left point of the image), image and width, height.
|
||||
|
||||
```c++
|
||||
display.addBitmapImage(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT, image);
|
||||
display.sendBuffer();
|
||||
```
|
||||
Should draw this image to display at point 0, 0
|
||||
|
||||
Entire display now should look like this:
|
||||
|
||||

|
||||
|
||||
Also note that ```addBitmapImage()``` in default write mode doesn't turn pixels off, so overlaying images is possible, so:
|
||||
|
||||
```c++
|
||||
display.addBitmapImage(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT, image);
|
||||
display.addBitmapImage(8, 0, IMAGE_WIDTH, IMAGE_HEIGHT, image);
|
||||
display.sendBuffer();
|
||||
```
|
||||
will overlay the same image with 8 pixel to right image, producing:
|
||||
|
||||

|
||||
|
||||
This function can take an optional argument of write mode, this is same as in ```setPixel()```
|
||||
|
||||
## 6. Additional Settings
|
||||
### Things like setting contrast, flipping the display etc. are all documented [here](https://ssd1306.harbys.me)
|
||||