Add display library, show battery voltage
untested
This commit is contained in:
parent
3449bb7f34
commit
0804aaf240
@ -6,6 +6,7 @@ idf_component_register(
|
||||
"button.cpp"
|
||||
"fan.cpp"
|
||||
"auto.cpp"
|
||||
"display.cpp"
|
||||
INCLUDE_DIRS
|
||||
"."
|
||||
)
|
||||
|
207
board_single/main/display.cpp
Normal file
207
board_single/main/display.cpp
Normal file
@ -0,0 +1,207 @@
|
||||
#include "display.hpp"
|
||||
extern "C"{
|
||||
#include <driver/adc.h>
|
||||
}
|
||||
|
||||
|
||||
//#
|
||||
//# SSD1306 Configuration
|
||||
//#
|
||||
#define GPIO_RANGE_MAX 33
|
||||
#define I2C_INTERFACE y
|
||||
//# SPI_INTERFACE is not set
|
||||
//# SSD1306_128x32 is not set
|
||||
#define SSD1306_128x64 y
|
||||
#define OFFSETX 0
|
||||
//# FLIP is not set
|
||||
#define SCL_GPIO 22
|
||||
#define SDA_GPIO 23
|
||||
#define RESET_GPIO 15 //FIXME remove this
|
||||
#define I2C_PORT_0 y
|
||||
//# I2C_PORT_1 is not set
|
||||
//# end of SSD1306 Configuration
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//--------------------------
|
||||
//------- getVoltage -------
|
||||
//--------------------------
|
||||
//local function to get average voltage from adc
|
||||
float getVoltage1(adc1_channel_t adc, uint32_t samples){
|
||||
//measure voltage
|
||||
int measure = 0;
|
||||
for (int j=0; j<samples; j++){
|
||||
measure += adc1_get_raw(adc);
|
||||
ets_delay_us(50);
|
||||
}
|
||||
return (float)measure / samples / 4096 * 3.3;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void startDisplayTest(){
|
||||
|
||||
adc1_config_channel_atten(ADC1_CHANNEL_6, ADC_ATTEN_DB_11); //max voltage
|
||||
|
||||
|
||||
|
||||
|
||||
SSD1306_t dev;
|
||||
int center, top, bottom;
|
||||
char lineChar[20];
|
||||
|
||||
#if I2C_INTERFACE
|
||||
ESP_LOGI(tag, "INTERFACE is i2c");
|
||||
ESP_LOGI(tag, "SDA_GPIO=%d",SDA_GPIO);
|
||||
ESP_LOGI(tag, "SCL_GPIO=%d",SCL_GPIO);
|
||||
ESP_LOGI(tag, "RESET_GPIO=%d",RESET_GPIO);
|
||||
i2c_master_init(&dev, SDA_GPIO, SCL_GPIO, RESET_GPIO);
|
||||
#endif // I2C_INTERFACE
|
||||
|
||||
|
||||
#if FLIP
|
||||
dev._flip = true;
|
||||
ESP_LOGW(tag, "Flip upside down");
|
||||
#endif
|
||||
|
||||
#if SSD1306_128x64
|
||||
ESP_LOGI(tag, "Panel is 128x64");
|
||||
ssd1306_init(&dev, 128, 64);
|
||||
#endif // SSD1306_128x64
|
||||
|
||||
ssd1306_clear_screen(&dev, false);
|
||||
ssd1306_contrast(&dev, 0xff);
|
||||
ssd1306_display_text_x3(&dev, 0, "Hello", 5, false);
|
||||
vTaskDelay(3000 / portTICK_PERIOD_MS);
|
||||
|
||||
top = 2;
|
||||
center = 3;
|
||||
bottom = 8;
|
||||
//ssd1306_display_text(&dev, 0, "SSD1306 128x64", 14, false);
|
||||
//ssd1306_display_text(&dev, 1, "ABCDEFGHIJKLMNOP", 16, false);
|
||||
//ssd1306_display_text(&dev, 2, "abcdefghijklmnop",16, false);
|
||||
//ssd1306_display_text(&dev, 3, "Hello World!!", 13, false);
|
||||
////ssd1306_clear_line(&dev, 4, true);
|
||||
////ssd1306_clear_line(&dev, 5, true);
|
||||
////ssd1306_clear_line(&dev, 6, true);
|
||||
////ssd1306_clear_line(&dev, 7, true);
|
||||
//ssd1306_display_text(&dev, 4, "SSD1306 128x64", 14, true);
|
||||
//ssd1306_display_text(&dev, 5, "ABCDEFGHIJKLMNOP", 16, true);
|
||||
//ssd1306_display_text(&dev, 6, "abcdefghijklmnop",16, true);
|
||||
//ssd1306_display_text(&dev, 7, "Hello World!!", 13, true);
|
||||
|
||||
vTaskDelay(3000 / portTICK_PERIOD_MS);
|
||||
|
||||
|
||||
while(1){
|
||||
float voltage = getVoltage1( ADC1_CHANNEL_6, 1000);
|
||||
float battVoltage = voltage * 9;
|
||||
char buf[20];
|
||||
int len = snprintf(buf, sizeof(buf), "Batt: %.3fV", battVoltage);
|
||||
ssd1306_display_text(&dev, 2, buf, len, false);
|
||||
ssd1306_display_text(&dev, 2, buf, len, true);
|
||||
vTaskDelay(2000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
//// Display Count Down
|
||||
//uint8_t image[24];
|
||||
//memset(image, 0, sizeof(image));
|
||||
//ssd1306_display_image(&dev, top, (6*8-1), image, sizeof(image));
|
||||
//ssd1306_display_image(&dev, top+1, (6*8-1), image, sizeof(image));
|
||||
//ssd1306_display_image(&dev, top+2, (6*8-1), image, sizeof(image));
|
||||
//for(int font=0x39;font>0x30;font--) {
|
||||
// memset(image, 0, sizeof(image));
|
||||
// ssd1306_display_image(&dev, top+1, (7*8-1), image, 8);
|
||||
// memcpy(image, font8x8_basic_tr[font], 8);
|
||||
// if (dev._flip) ssd1306_flip(image, 8);
|
||||
// ssd1306_display_image(&dev, top+1, (7*8-1), image, 8);
|
||||
// vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
//}
|
||||
//
|
||||
//// Scroll Up
|
||||
//ssd1306_clear_screen(&dev, false);
|
||||
//ssd1306_contrast(&dev, 0xff);
|
||||
//ssd1306_display_text(&dev, 0, "---Scroll UP---", 16, true);
|
||||
////ssd1306_software_scroll(&dev, 7, 1);
|
||||
//ssd1306_software_scroll(&dev, (dev._pages - 1), 1);
|
||||
//for (int line=0;line<bottom+10;line++) {
|
||||
// lineChar[0] = 0x01;
|
||||
// sprintf(&lineChar[1], " Line %02d", line);
|
||||
// ssd1306_scroll_text(&dev, lineChar, strlen(lineChar), false);
|
||||
// vTaskDelay(500 / portTICK_PERIOD_MS);
|
||||
//}
|
||||
//vTaskDelay(3000 / portTICK_PERIOD_MS);
|
||||
//
|
||||
//// Scroll Down
|
||||
//ssd1306_clear_screen(&dev, false);
|
||||
//ssd1306_contrast(&dev, 0xff);
|
||||
//ssd1306_display_text(&dev, 0, "--Scroll DOWN--", 16, true);
|
||||
////ssd1306_software_scroll(&dev, 1, 7);
|
||||
//ssd1306_software_scroll(&dev, 1, (dev._pages - 1) );
|
||||
//for (int line=0;line<bottom+10;line++) {
|
||||
// lineChar[0] = 0x02;
|
||||
// sprintf(&lineChar[1], " Line %02d", line);
|
||||
// ssd1306_scroll_text(&dev, lineChar, strlen(lineChar), false);
|
||||
// vTaskDelay(500 / portTICK_PERIOD_MS);
|
||||
//}
|
||||
//vTaskDelay(3000 / portTICK_PERIOD_MS);
|
||||
|
||||
//// Page Down
|
||||
//ssd1306_clear_screen(&dev, false);
|
||||
//ssd1306_contrast(&dev, 0xff);
|
||||
//ssd1306_display_text(&dev, 0, "---Page DOWN---", 16, true);
|
||||
//ssd1306_software_scroll(&dev, 1, (dev._pages-1) );
|
||||
//for (int line=0;line<bottom+10;line++) {
|
||||
// //if ( (line % 7) == 0) ssd1306_scroll_clear(&dev);
|
||||
// if ( (line % (dev._pages-1)) == 0) ssd1306_scroll_clear(&dev);
|
||||
// lineChar[0] = 0x02;
|
||||
// sprintf(&lineChar[1], " Line %02d", line);
|
||||
// ssd1306_scroll_text(&dev, lineChar, strlen(lineChar), false);
|
||||
// vTaskDelay(500 / portTICK_PERIOD_MS);
|
||||
//}
|
||||
//vTaskDelay(3000 / portTICK_PERIOD_MS);
|
||||
|
||||
//// Horizontal Scroll
|
||||
//ssd1306_clear_screen(&dev, false);
|
||||
//ssd1306_contrast(&dev, 0xff);
|
||||
//ssd1306_display_text(&dev, center, "Horizontal", 10, false);
|
||||
//ssd1306_hardware_scroll(&dev, SCROLL_RIGHT);
|
||||
//vTaskDelay(5000 / portTICK_PERIOD_MS);
|
||||
//ssd1306_hardware_scroll(&dev, SCROLL_LEFT);
|
||||
//vTaskDelay(5000 / portTICK_PERIOD_MS);
|
||||
//ssd1306_hardware_scroll(&dev, SCROLL_STOP);
|
||||
//
|
||||
//// Vertical Scroll
|
||||
//ssd1306_clear_screen(&dev, false);
|
||||
//ssd1306_contrast(&dev, 0xff);
|
||||
//ssd1306_display_text(&dev, center, "Vertical", 8, false);
|
||||
//ssd1306_hardware_scroll(&dev, SCROLL_DOWN);
|
||||
//vTaskDelay(5000 / portTICK_PERIOD_MS);
|
||||
//ssd1306_hardware_scroll(&dev, SCROLL_UP);
|
||||
//vTaskDelay(5000 / portTICK_PERIOD_MS);
|
||||
//ssd1306_hardware_scroll(&dev, SCROLL_STOP);
|
||||
//
|
||||
//// Invert
|
||||
//ssd1306_clear_screen(&dev, true);
|
||||
//ssd1306_contrast(&dev, 0xff);
|
||||
//ssd1306_display_text(&dev, center, " Good Bye!!", 12, true);
|
||||
//vTaskDelay(5000 / portTICK_PERIOD_MS);
|
||||
|
||||
|
||||
//// Fade Out
|
||||
//ssd1306_fadeout(&dev);
|
||||
|
||||
#if 0
|
||||
// Fade Out
|
||||
for(int contrast=0xff;contrast>0;contrast=contrast-0x20) {
|
||||
ssd1306_contrast(&dev, contrast);
|
||||
vTaskDelay(40);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
14
board_single/main/display.hpp
Normal file
14
board_single/main/display.hpp
Normal file
@ -0,0 +1,14 @@
|
||||
extern "C" {
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "ssd1306.h"
|
||||
#include "font8x8_basic.h"
|
||||
}
|
||||
|
||||
|
||||
void startDisplayTest();
|
@ -28,6 +28,8 @@ extern "C"
|
||||
|
||||
#include "uart_common.hpp"
|
||||
|
||||
#include "display.hpp"
|
||||
|
||||
//tag for logging
|
||||
static const char * TAG = "main";
|
||||
|
||||
@ -232,6 +234,10 @@ extern "C" void app_main(void) {
|
||||
//control.changeMode(controlMode_t::HTTP);
|
||||
|
||||
|
||||
|
||||
//========== display test ============
|
||||
startDisplayTest();
|
||||
|
||||
//--- main loop ---
|
||||
//does nothing except for testing things
|
||||
while(1){
|
||||
|
5
components/ssd1306/CMakeLists.txt
Normal file
5
components/ssd1306/CMakeLists.txt
Normal file
@ -0,0 +1,5 @@
|
||||
set(component_srcs "ssd1306.c" "ssd1306_i2c.c" "ssd1306_spi.c")
|
||||
|
||||
idf_component_register(SRCS "${component_srcs}"
|
||||
PRIV_REQUIRES driver
|
||||
INCLUDE_DIRS ".")
|
183
components/ssd1306/Kconfig.projbuild
Normal file
183
components/ssd1306/Kconfig.projbuild
Normal file
@ -0,0 +1,183 @@
|
||||
menu "SSD1306 Configuration"
|
||||
|
||||
config GPIO_RANGE_MAX
|
||||
int
|
||||
default 33 if IDF_TARGET_ESP32
|
||||
default 46 if IDF_TARGET_ESP32S2
|
||||
default 48 if IDF_TARGET_ESP32S3
|
||||
default 18 if IDF_TARGET_ESP32C2
|
||||
default 19 if IDF_TARGET_ESP32C3
|
||||
default 30 if IDF_TARGET_ESP32C6
|
||||
|
||||
choice INTERFACE
|
||||
prompt "Interface"
|
||||
default I2C_INTERFACE
|
||||
help
|
||||
Select Interface.
|
||||
config I2C_INTERFACE
|
||||
bool "I2C Interface"
|
||||
help
|
||||
I2C Interface.
|
||||
config SPI_INTERFACE
|
||||
bool "SPI Interface"
|
||||
help
|
||||
SPI Interface.
|
||||
endchoice
|
||||
|
||||
choice PANEL
|
||||
prompt "Panel Type"
|
||||
default SSD1306_128x64
|
||||
help
|
||||
Select Panel Type.
|
||||
config SSD1306_128x32
|
||||
bool "128x32 Panel"
|
||||
help
|
||||
Panel is 128x32.
|
||||
config SSD1306_128x64
|
||||
bool "128x64 Panel"
|
||||
help
|
||||
Panel is 128x64.
|
||||
endchoice
|
||||
|
||||
config OFFSETX
|
||||
int "GRAM X OFFSET"
|
||||
range 0 99
|
||||
default 0
|
||||
help
|
||||
When your TFT have offset(X), set it.
|
||||
|
||||
config FLIP
|
||||
bool "Flip upside down"
|
||||
default false
|
||||
help
|
||||
Flip upside down.
|
||||
|
||||
config SCL_GPIO
|
||||
depends on I2C_INTERFACE
|
||||
int "SCL GPIO number"
|
||||
range 0 GPIO_RANGE_MAX
|
||||
default 22 if IDF_TARGET_ESP32
|
||||
default 12 if IDF_TARGET_ESP32S2
|
||||
default 12 if IDF_TARGET_ESP32S3
|
||||
default 6 # C3 and others
|
||||
help
|
||||
GPIO number (IOxx) to I2C SCL.
|
||||
Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to I2C.
|
||||
GPIOs 35-39 are input-only so cannot be used as outputs.
|
||||
|
||||
config SDA_GPIO
|
||||
depends on I2C_INTERFACE
|
||||
int "SDA GPIO number"
|
||||
range 0 GPIO_RANGE_MAX
|
||||
default 21 if IDF_TARGET_ESP32
|
||||
default 11 if IDF_TARGET_ESP32S2
|
||||
default 11 if IDF_TARGET_ESP32S3
|
||||
default 5 # C3 and others
|
||||
help
|
||||
GPIO number (IOxx) to I2C SDA.
|
||||
Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to I2C.
|
||||
GPIOs 35-39 are input-only so cannot be used as outputs.
|
||||
|
||||
config MOSI_GPIO
|
||||
depends on SPI_INTERFACE
|
||||
int "MOSI GPIO number"
|
||||
range 0 GPIO_RANGE_MAX
|
||||
default 23 if IDF_TARGET_ESP32
|
||||
default 35 if IDF_TARGET_ESP32S2
|
||||
default 35 if IDF_TARGET_ESP32S3
|
||||
default 1 # C3 and others
|
||||
help
|
||||
GPIO number (IOxx) to SPI MOSI.
|
||||
Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to MOSI.
|
||||
On the ESP32, GPIOs 35-39 are input-only so cannot be used as outputs.
|
||||
On the ESP32-S2, GPIO 46 is input-only so cannot be used as outputs.
|
||||
|
||||
config SCLK_GPIO
|
||||
depends on SPI_INTERFACE
|
||||
int "SCLK GPIO number"
|
||||
range 0 GPIO_RANGE_MAX
|
||||
default 18 if IDF_TARGET_ESP32
|
||||
default 36 if IDF_TARGET_ESP32S2
|
||||
default 36 if IDF_TARGET_ESP32S3
|
||||
default 2 # C3 and others
|
||||
help
|
||||
GPIO number (IOxx) to SPI SCLK.
|
||||
Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to SCLK.
|
||||
On the ESP32, GPIOs 35-39 are input-only so cannot be used as outputs.
|
||||
On the ESP32-S2, GPIO 46 is input-only so cannot be used as outputs.
|
||||
|
||||
config CS_GPIO
|
||||
depends on SPI_INTERFACE
|
||||
int "CS GPIO number"
|
||||
range 0 GPIO_RANGE_MAX
|
||||
default 5 if IDF_TARGET_ESP32
|
||||
default 34 if IDF_TARGET_ESP32S2
|
||||
default 34 if IDF_TARGET_ESP32S3
|
||||
default 10 # C3 and others
|
||||
help
|
||||
GPIO number (IOxx) to SPI CS.
|
||||
Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to CS.
|
||||
GPIOs 35-39 are input-only so cannot be used as outputs.
|
||||
|
||||
config DC_GPIO
|
||||
depends on SPI_INTERFACE
|
||||
int "DC GPIO number"
|
||||
range 0 GPIO_RANGE_MAX
|
||||
default 4 if IDF_TARGET_ESP32
|
||||
default 37 if IDF_TARGET_ESP32S2
|
||||
default 37 if IDF_TARGET_ESP32S3
|
||||
default 3 # C3 and others
|
||||
help
|
||||
GPIO number (IOxx) to SPI DC.
|
||||
Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to DC.
|
||||
GPIOs 35-39 are input-only so cannot be used as outputs.
|
||||
|
||||
config RESET_GPIO
|
||||
int "RESET GPIO number"
|
||||
range -1 GPIO_RANGE_MAX
|
||||
default 15 if IDF_TARGET_ESP32
|
||||
default 38 if IDF_TARGET_ESP32S2
|
||||
default 38 if IDF_TARGET_ESP32S3
|
||||
default 4 # C3 and others
|
||||
help
|
||||
GPIO number (IOxx) to RESET.
|
||||
When it is -1, RESET isn't performed.
|
||||
Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to RESET.
|
||||
GPIOs 35-39 are input-only so cannot be used as outputs.
|
||||
|
||||
choice I2C_PORT
|
||||
depends on I2C_INTERFACE
|
||||
prompt "I2C port that controls this bus"
|
||||
default I2C_PORT_0
|
||||
help
|
||||
Select I2C port that controls this bus.
|
||||
config I2C_PORT_0
|
||||
bool "I2C_PORT_0"
|
||||
help
|
||||
Use I2C_PORT_0.
|
||||
config I2C_PORT_1
|
||||
depends on IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
|
||||
bool "I2C_PORT_1"
|
||||
help
|
||||
Use I2C_PORT_1.
|
||||
endchoice
|
||||
|
||||
choice SPI_HOST
|
||||
depends on SPI_INTERFACE
|
||||
prompt "SPI peripheral that controls this bus"
|
||||
default SPI2_HOST
|
||||
help
|
||||
Select SPI peripheral that controls this bus.
|
||||
config SPI2_HOST
|
||||
bool "SPI2_HOST"
|
||||
help
|
||||
Use SPI2_HOST. This is also called HSPI_HOST.
|
||||
config SPI3_HOST
|
||||
depends on IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
|
||||
bool "SPI3_HOST"
|
||||
help
|
||||
USE SPI3_HOST. This is also called VSPI_HOST
|
||||
endchoice
|
||||
|
||||
endmenu
|
||||
|
174
components/ssd1306/font8x8_basic.h
Normal file
174
components/ssd1306/font8x8_basic.h
Normal file
@ -0,0 +1,174 @@
|
||||
/*
|
||||
* font8x8_basic.h
|
||||
*
|
||||
* Created on: 2017/05/03
|
||||
* Author: yanbe
|
||||
*/
|
||||
|
||||
#ifndef MAIN_FONT8X8_BASIC_H_
|
||||
#define MAIN_FONT8X8_BASIC_H_
|
||||
|
||||
/*
|
||||
Constant: font8x8_basic_tr
|
||||
Contains an 90 digree transposed 8x8 font map for unicode points
|
||||
U+0000 - U+007F (basic latin)
|
||||
|
||||
To make it easy to use with SSD1306's GDDRAM mapping and API,
|
||||
this constant is an 90 degree transposed.
|
||||
The original version written by Marcel Sondaar is availble at:
|
||||
https://github.com/dhepper/font8x8/blob/master/font8x8_basic.h
|
||||
|
||||
Conversion is done via following procedure:
|
||||
|
||||
for (int code = 0; code < 128; code++) {
|
||||
uint8_t trans[8];
|
||||
for (int w = 0; w < 8; w++) {
|
||||
trans[w] = 0x00;
|
||||
for (int b = 0; b < 8; b++) {
|
||||
trans[w] |= ((font8x8_basic[code][b] & (1 << w)) >> w) << b;
|
||||
}
|
||||
}
|
||||
|
||||
for (int w = 0; w < 8; w++) {
|
||||
if (w == 0) { printf(" { "); }
|
||||
printf("0x%.2X", trans[w]);
|
||||
if (w < 7) { printf(", "); }
|
||||
if (w == 7) { printf(" }, // U+00%.2X (%c)\n", code, code); }
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
static uint8_t font8x8_basic_tr[128][8] = {
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0000 (nul)
|
||||
{ 0x00, 0x04, 0x02, 0xFF, 0x02, 0x04, 0x00, 0x00 }, // U+0001 (Up Allow)
|
||||
{ 0x00, 0x20, 0x40, 0xFF, 0x40, 0x20, 0x00, 0x00 }, // U+0002 (Down Allow)
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0003
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0004
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0005
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0006
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0007
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0008
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0009
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+000A
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+000B
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+000C
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+000D
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+000E
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+000F
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0010
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0011
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0012
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0013
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0014
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0015
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0016
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0017
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0018
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0019
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+001A
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+001B
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+001C
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+001D
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+001E
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+001F
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0020 (space)
|
||||
{ 0x00, 0x00, 0x06, 0x5F, 0x5F, 0x06, 0x00, 0x00 }, // U+0021 (!)
|
||||
{ 0x00, 0x03, 0x03, 0x00, 0x03, 0x03, 0x00, 0x00 }, // U+0022 (")
|
||||
{ 0x14, 0x7F, 0x7F, 0x14, 0x7F, 0x7F, 0x14, 0x00 }, // U+0023 (#)
|
||||
{ 0x24, 0x2E, 0x6B, 0x6B, 0x3A, 0x12, 0x00, 0x00 }, // U+0024 ($)
|
||||
{ 0x46, 0x66, 0x30, 0x18, 0x0C, 0x66, 0x62, 0x00 }, // U+0025 (%)
|
||||
{ 0x30, 0x7A, 0x4F, 0x5D, 0x37, 0x7A, 0x48, 0x00 }, // U+0026 (&)
|
||||
{ 0x04, 0x07, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0027 (')
|
||||
{ 0x00, 0x1C, 0x3E, 0x63, 0x41, 0x00, 0x00, 0x00 }, // U+0028 (()
|
||||
{ 0x00, 0x41, 0x63, 0x3E, 0x1C, 0x00, 0x00, 0x00 }, // U+0029 ())
|
||||
{ 0x08, 0x2A, 0x3E, 0x1C, 0x1C, 0x3E, 0x2A, 0x08 }, // U+002A (*)
|
||||
{ 0x08, 0x08, 0x3E, 0x3E, 0x08, 0x08, 0x00, 0x00 }, // U+002B (+)
|
||||
{ 0x00, 0x80, 0xE0, 0x60, 0x00, 0x00, 0x00, 0x00 }, // U+002C (,)
|
||||
{ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00 }, // U+002D (-)
|
||||
{ 0x00, 0x00, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00 }, // U+002E (.)
|
||||
{ 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00 }, // U+002F (/)
|
||||
{ 0x3E, 0x7F, 0x71, 0x59, 0x4D, 0x7F, 0x3E, 0x00 }, // U+0030 (0)
|
||||
{ 0x40, 0x42, 0x7F, 0x7F, 0x40, 0x40, 0x00, 0x00 }, // U+0031 (1)
|
||||
{ 0x62, 0x73, 0x59, 0x49, 0x6F, 0x66, 0x00, 0x00 }, // U+0032 (2)
|
||||
{ 0x22, 0x63, 0x49, 0x49, 0x7F, 0x36, 0x00, 0x00 }, // U+0033 (3)
|
||||
{ 0x18, 0x1C, 0x16, 0x53, 0x7F, 0x7F, 0x50, 0x00 }, // U+0034 (4)
|
||||
{ 0x27, 0x67, 0x45, 0x45, 0x7D, 0x39, 0x00, 0x00 }, // U+0035 (5)
|
||||
{ 0x3C, 0x7E, 0x4B, 0x49, 0x79, 0x30, 0x00, 0x00 }, // U+0036 (6)
|
||||
{ 0x03, 0x03, 0x71, 0x79, 0x0F, 0x07, 0x00, 0x00 }, // U+0037 (7)
|
||||
{ 0x36, 0x7F, 0x49, 0x49, 0x7F, 0x36, 0x00, 0x00 }, // U+0038 (8)
|
||||
{ 0x06, 0x4F, 0x49, 0x69, 0x3F, 0x1E, 0x00, 0x00 }, // U+0039 (9)
|
||||
{ 0x00, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00 }, // U+003A (:)
|
||||
{ 0x00, 0x80, 0xE6, 0x66, 0x00, 0x00, 0x00, 0x00 }, // U+003B (;)
|
||||
{ 0x08, 0x1C, 0x36, 0x63, 0x41, 0x00, 0x00, 0x00 }, // U+003C (<)
|
||||
{ 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x00, 0x00 }, // U+003D (=)
|
||||
{ 0x00, 0x41, 0x63, 0x36, 0x1C, 0x08, 0x00, 0x00 }, // U+003E (>)
|
||||
{ 0x02, 0x03, 0x51, 0x59, 0x0F, 0x06, 0x00, 0x00 }, // U+003F (?)
|
||||
{ 0x3E, 0x7F, 0x41, 0x5D, 0x5D, 0x1F, 0x1E, 0x00 }, // U+0040 (@)
|
||||
{ 0x7C, 0x7E, 0x13, 0x13, 0x7E, 0x7C, 0x00, 0x00 }, // U+0041 (A)
|
||||
{ 0x41, 0x7F, 0x7F, 0x49, 0x49, 0x7F, 0x36, 0x00 }, // U+0042 (B)
|
||||
{ 0x1C, 0x3E, 0x63, 0x41, 0x41, 0x63, 0x22, 0x00 }, // U+0043 (C)
|
||||
{ 0x41, 0x7F, 0x7F, 0x41, 0x63, 0x3E, 0x1C, 0x00 }, // U+0044 (D)
|
||||
{ 0x41, 0x7F, 0x7F, 0x49, 0x5D, 0x41, 0x63, 0x00 }, // U+0045 (E)
|
||||
{ 0x41, 0x7F, 0x7F, 0x49, 0x1D, 0x01, 0x03, 0x00 }, // U+0046 (F)
|
||||
{ 0x1C, 0x3E, 0x63, 0x41, 0x51, 0x73, 0x72, 0x00 }, // U+0047 (G)
|
||||
{ 0x7F, 0x7F, 0x08, 0x08, 0x7F, 0x7F, 0x00, 0x00 }, // U+0048 (H)
|
||||
{ 0x00, 0x41, 0x7F, 0x7F, 0x41, 0x00, 0x00, 0x00 }, // U+0049 (I)
|
||||
{ 0x30, 0x70, 0x40, 0x41, 0x7F, 0x3F, 0x01, 0x00 }, // U+004A (J)
|
||||
{ 0x41, 0x7F, 0x7F, 0x08, 0x1C, 0x77, 0x63, 0x00 }, // U+004B (K)
|
||||
{ 0x41, 0x7F, 0x7F, 0x41, 0x40, 0x60, 0x70, 0x00 }, // U+004C (L)
|
||||
{ 0x7F, 0x7F, 0x0E, 0x1C, 0x0E, 0x7F, 0x7F, 0x00 }, // U+004D (M)
|
||||
{ 0x7F, 0x7F, 0x06, 0x0C, 0x18, 0x7F, 0x7F, 0x00 }, // U+004E (N)
|
||||
{ 0x1C, 0x3E, 0x63, 0x41, 0x63, 0x3E, 0x1C, 0x00 }, // U+004F (O)
|
||||
{ 0x41, 0x7F, 0x7F, 0x49, 0x09, 0x0F, 0x06, 0x00 }, // U+0050 (P)
|
||||
{ 0x1E, 0x3F, 0x21, 0x71, 0x7F, 0x5E, 0x00, 0x00 }, // U+0051 (Q)
|
||||
{ 0x41, 0x7F, 0x7F, 0x09, 0x19, 0x7F, 0x66, 0x00 }, // U+0052 (R)
|
||||
{ 0x26, 0x6F, 0x4D, 0x59, 0x73, 0x32, 0x00, 0x00 }, // U+0053 (S)
|
||||
{ 0x03, 0x41, 0x7F, 0x7F, 0x41, 0x03, 0x00, 0x00 }, // U+0054 (T)
|
||||
{ 0x7F, 0x7F, 0x40, 0x40, 0x7F, 0x7F, 0x00, 0x00 }, // U+0055 (U)
|
||||
{ 0x1F, 0x3F, 0x60, 0x60, 0x3F, 0x1F, 0x00, 0x00 }, // U+0056 (V)
|
||||
{ 0x7F, 0x7F, 0x30, 0x18, 0x30, 0x7F, 0x7F, 0x00 }, // U+0057 (W)
|
||||
{ 0x43, 0x67, 0x3C, 0x18, 0x3C, 0x67, 0x43, 0x00 }, // U+0058 (X)
|
||||
{ 0x07, 0x4F, 0x78, 0x78, 0x4F, 0x07, 0x00, 0x00 }, // U+0059 (Y)
|
||||
{ 0x47, 0x63, 0x71, 0x59, 0x4D, 0x67, 0x73, 0x00 }, // U+005A (Z)
|
||||
{ 0x00, 0x7F, 0x7F, 0x41, 0x41, 0x00, 0x00, 0x00 }, // U+005B ([)
|
||||
{ 0x01, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x00 }, // U+005C (\)
|
||||
{ 0x00, 0x41, 0x41, 0x7F, 0x7F, 0x00, 0x00, 0x00 }, // U+005D (])
|
||||
{ 0x08, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x08, 0x00 }, // U+005E (^)
|
||||
{ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 }, // U+005F (_)
|
||||
{ 0x00, 0x00, 0x03, 0x07, 0x04, 0x00, 0x00, 0x00 }, // U+0060 (`)
|
||||
{ 0x20, 0x74, 0x54, 0x54, 0x3C, 0x78, 0x40, 0x00 }, // U+0061 (a)
|
||||
{ 0x41, 0x7F, 0x3F, 0x48, 0x48, 0x78, 0x30, 0x00 }, // U+0062 (b)
|
||||
{ 0x38, 0x7C, 0x44, 0x44, 0x6C, 0x28, 0x00, 0x00 }, // U+0063 (c)
|
||||
{ 0x30, 0x78, 0x48, 0x49, 0x3F, 0x7F, 0x40, 0x00 }, // U+0064 (d)
|
||||
{ 0x38, 0x7C, 0x54, 0x54, 0x5C, 0x18, 0x00, 0x00 }, // U+0065 (e)
|
||||
{ 0x48, 0x7E, 0x7F, 0x49, 0x03, 0x02, 0x00, 0x00 }, // U+0066 (f)
|
||||
{ 0x98, 0xBC, 0xA4, 0xA4, 0xF8, 0x7C, 0x04, 0x00 }, // U+0067 (g)
|
||||
{ 0x41, 0x7F, 0x7F, 0x08, 0x04, 0x7C, 0x78, 0x00 }, // U+0068 (h)
|
||||
{ 0x00, 0x44, 0x7D, 0x7D, 0x40, 0x00, 0x00, 0x00 }, // U+0069 (i)
|
||||
{ 0x60, 0xE0, 0x80, 0x80, 0xFD, 0x7D, 0x00, 0x00 }, // U+006A (j)
|
||||
{ 0x41, 0x7F, 0x7F, 0x10, 0x38, 0x6C, 0x44, 0x00 }, // U+006B (k)
|
||||
{ 0x00, 0x41, 0x7F, 0x7F, 0x40, 0x00, 0x00, 0x00 }, // U+006C (l)
|
||||
{ 0x7C, 0x7C, 0x18, 0x38, 0x1C, 0x7C, 0x78, 0x00 }, // U+006D (m)
|
||||
{ 0x7C, 0x7C, 0x04, 0x04, 0x7C, 0x78, 0x00, 0x00 }, // U+006E (n)
|
||||
{ 0x38, 0x7C, 0x44, 0x44, 0x7C, 0x38, 0x00, 0x00 }, // U+006F (o)
|
||||
{ 0x84, 0xFC, 0xF8, 0xA4, 0x24, 0x3C, 0x18, 0x00 }, // U+0070 (p)
|
||||
{ 0x18, 0x3C, 0x24, 0xA4, 0xF8, 0xFC, 0x84, 0x00 }, // U+0071 (q)
|
||||
{ 0x44, 0x7C, 0x78, 0x4C, 0x04, 0x1C, 0x18, 0x00 }, // U+0072 (r)
|
||||
{ 0x48, 0x5C, 0x54, 0x54, 0x74, 0x24, 0x00, 0x00 }, // U+0073 (s)
|
||||
{ 0x00, 0x04, 0x3E, 0x7F, 0x44, 0x24, 0x00, 0x00 }, // U+0074 (t)
|
||||
{ 0x3C, 0x7C, 0x40, 0x40, 0x3C, 0x7C, 0x40, 0x00 }, // U+0075 (u)
|
||||
{ 0x1C, 0x3C, 0x60, 0x60, 0x3C, 0x1C, 0x00, 0x00 }, // U+0076 (v)
|
||||
{ 0x3C, 0x7C, 0x70, 0x38, 0x70, 0x7C, 0x3C, 0x00 }, // U+0077 (w)
|
||||
{ 0x44, 0x6C, 0x38, 0x10, 0x38, 0x6C, 0x44, 0x00 }, // U+0078 (x)
|
||||
{ 0x9C, 0xBC, 0xA0, 0xA0, 0xFC, 0x7C, 0x00, 0x00 }, // U+0079 (y)
|
||||
{ 0x4C, 0x64, 0x74, 0x5C, 0x4C, 0x64, 0x00, 0x00 }, // U+007A (z)
|
||||
{ 0x08, 0x08, 0x3E, 0x77, 0x41, 0x41, 0x00, 0x00 }, // U+007B ({)
|
||||
{ 0x00, 0x00, 0x00, 0x77, 0x77, 0x00, 0x00, 0x00 }, // U+007C (|)
|
||||
{ 0x41, 0x41, 0x77, 0x3E, 0x08, 0x08, 0x00, 0x00 }, // U+007D (})
|
||||
{ 0x02, 0x03, 0x01, 0x03, 0x02, 0x03, 0x01, 0x00 }, // U+007E (~)
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } // U+007F
|
||||
};
|
||||
|
||||
#endif /* MAIN_FONT8X8_BASIC_H_ */
|
||||
|
||||
|
619
components/ssd1306/ssd1306.c
Normal file
619
components/ssd1306/ssd1306.c
Normal file
@ -0,0 +1,619 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "ssd1306.h"
|
||||
#include "font8x8_basic.h"
|
||||
|
||||
#define TAG "SSD1306"
|
||||
|
||||
#define PACK8 __attribute__((aligned( __alignof__( uint8_t ) ), packed ))
|
||||
|
||||
typedef union out_column_t {
|
||||
uint32_t u32;
|
||||
uint8_t u8[4];
|
||||
} PACK8 out_column_t;
|
||||
|
||||
void ssd1306_init(SSD1306_t * dev, int width, int height)
|
||||
{
|
||||
if (dev->_address == SPIAddress) {
|
||||
spi_init(dev, width, height);
|
||||
} else {
|
||||
i2c_init(dev, width, height);
|
||||
}
|
||||
// Initialize internal buffer
|
||||
for (int i=0;i<dev->_pages;i++) {
|
||||
memset(dev->_page[i]._segs, 0, 128);
|
||||
}
|
||||
}
|
||||
|
||||
int ssd1306_get_width(SSD1306_t * dev)
|
||||
{
|
||||
return dev->_width;
|
||||
}
|
||||
|
||||
int ssd1306_get_height(SSD1306_t * dev)
|
||||
{
|
||||
return dev->_height;
|
||||
}
|
||||
|
||||
int ssd1306_get_pages(SSD1306_t * dev)
|
||||
{
|
||||
return dev->_pages;
|
||||
}
|
||||
|
||||
void ssd1306_show_buffer(SSD1306_t * dev)
|
||||
{
|
||||
if (dev->_address == SPIAddress) {
|
||||
for (int page=0; page<dev->_pages;page++) {
|
||||
spi_display_image(dev, page, 0, dev->_page[page]._segs, dev->_width);
|
||||
}
|
||||
} else {
|
||||
for (int page=0; page<dev->_pages;page++) {
|
||||
i2c_display_image(dev, page, 0, dev->_page[page]._segs, dev->_width);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ssd1306_set_buffer(SSD1306_t * dev, uint8_t * buffer)
|
||||
{
|
||||
int index = 0;
|
||||
for (int page=0; page<dev->_pages;page++) {
|
||||
memcpy(&dev->_page[page]._segs, &buffer[index], 128);
|
||||
index = index + 128;
|
||||
}
|
||||
}
|
||||
|
||||
void ssd1306_get_buffer(SSD1306_t * dev, uint8_t * buffer)
|
||||
{
|
||||
int index = 0;
|
||||
for (int page=0; page<dev->_pages;page++) {
|
||||
memcpy(&buffer[index], &dev->_page[page]._segs, 128);
|
||||
index = index + 128;
|
||||
}
|
||||
}
|
||||
|
||||
void ssd1306_display_image(SSD1306_t * dev, int page, int seg, uint8_t * images, int width)
|
||||
{
|
||||
if (dev->_address == SPIAddress) {
|
||||
spi_display_image(dev, page, seg, images, width);
|
||||
} else {
|
||||
i2c_display_image(dev, page, seg, images, width);
|
||||
}
|
||||
// Set to internal buffer
|
||||
memcpy(&dev->_page[page]._segs[seg], images, width);
|
||||
}
|
||||
|
||||
void ssd1306_display_text(SSD1306_t * dev, int page, char * text, int text_len, bool invert)
|
||||
{
|
||||
if (page >= dev->_pages) return;
|
||||
int _text_len = text_len;
|
||||
if (_text_len > 16) _text_len = 16;
|
||||
|
||||
uint8_t seg = 0;
|
||||
uint8_t image[8];
|
||||
for (uint8_t i = 0; i < _text_len; i++) {
|
||||
memcpy(image, font8x8_basic_tr[(uint8_t)text[i]], 8);
|
||||
if (invert) ssd1306_invert(image, 8);
|
||||
if (dev->_flip) ssd1306_flip(image, 8);
|
||||
ssd1306_display_image(dev, page, seg, image, 8);
|
||||
#if 0
|
||||
if (dev->_address == SPIAddress) {
|
||||
spi_display_image(dev, page, seg, image, 8);
|
||||
} else {
|
||||
i2c_display_image(dev, page, seg, image, 8);
|
||||
}
|
||||
#endif
|
||||
seg = seg + 8;
|
||||
}
|
||||
}
|
||||
|
||||
// by Coert Vonk
|
||||
void
|
||||
ssd1306_display_text_x3(SSD1306_t * dev, int page, char * text, int text_len, bool invert)
|
||||
{
|
||||
if (page >= dev->_pages) return;
|
||||
int _text_len = text_len;
|
||||
if (_text_len > 5) _text_len = 5;
|
||||
|
||||
uint8_t seg = 0;
|
||||
|
||||
for (uint8_t nn = 0; nn < _text_len; nn++) {
|
||||
|
||||
uint8_t const * const in_columns = font8x8_basic_tr[(uint8_t)text[nn]];
|
||||
|
||||
// make the character 3x as high
|
||||
out_column_t out_columns[8];
|
||||
memset(out_columns, 0, sizeof(out_columns));
|
||||
|
||||
for (uint8_t xx = 0; xx < 8; xx++) { // for each column (x-direction)
|
||||
|
||||
uint32_t in_bitmask = 0b1;
|
||||
uint32_t out_bitmask = 0b111;
|
||||
|
||||
for (uint8_t yy = 0; yy < 8; yy++) { // for pixel (y-direction)
|
||||
if (in_columns[xx] & in_bitmask) {
|
||||
out_columns[xx].u32 |= out_bitmask;
|
||||
}
|
||||
in_bitmask <<= 1;
|
||||
out_bitmask <<= 3;
|
||||
}
|
||||
}
|
||||
|
||||
// render character in 8 column high pieces, making them 3x as wide
|
||||
for (uint8_t yy = 0; yy < 3; yy++) { // for each group of 8 pixels high (y-direction)
|
||||
|
||||
uint8_t image[24];
|
||||
for (uint8_t xx = 0; xx < 8; xx++) { // for each column (x-direction)
|
||||
image[xx*3+0] =
|
||||
image[xx*3+1] =
|
||||
image[xx*3+2] = out_columns[xx].u8[yy];
|
||||
}
|
||||
if (invert) ssd1306_invert(image, 24);
|
||||
if (dev->_flip) ssd1306_flip(image, 24);
|
||||
if (dev->_address == SPIAddress) {
|
||||
spi_display_image(dev, page+yy, seg, image, 24);
|
||||
} else {
|
||||
i2c_display_image(dev, page+yy, seg, image, 24);
|
||||
}
|
||||
memcpy(&dev->_page[page+yy]._segs[seg], image, 24);
|
||||
}
|
||||
seg = seg + 24;
|
||||
}
|
||||
}
|
||||
|
||||
void ssd1306_clear_screen(SSD1306_t * dev, bool invert)
|
||||
{
|
||||
char space[16];
|
||||
memset(space, 0x00, sizeof(space));
|
||||
for (int page = 0; page < dev->_pages; page++) {
|
||||
ssd1306_display_text(dev, page, space, sizeof(space), invert);
|
||||
}
|
||||
}
|
||||
|
||||
void ssd1306_clear_line(SSD1306_t * dev, int page, bool invert)
|
||||
{
|
||||
char space[16];
|
||||
memset(space, 0x00, sizeof(space));
|
||||
ssd1306_display_text(dev, page, space, sizeof(space), invert);
|
||||
}
|
||||
|
||||
void ssd1306_contrast(SSD1306_t * dev, int contrast)
|
||||
{
|
||||
if (dev->_address == SPIAddress) {
|
||||
spi_contrast(dev, contrast);
|
||||
} else {
|
||||
i2c_contrast(dev, contrast);
|
||||
}
|
||||
}
|
||||
|
||||
void ssd1306_software_scroll(SSD1306_t * dev, int start, int end)
|
||||
{
|
||||
ESP_LOGD(TAG, "software_scroll start=%d end=%d _pages=%d", start, end, dev->_pages);
|
||||
if (start < 0 || end < 0) {
|
||||
dev->_scEnable = false;
|
||||
} else if (start >= dev->_pages || end >= dev->_pages) {
|
||||
dev->_scEnable = false;
|
||||
} else {
|
||||
dev->_scEnable = true;
|
||||
dev->_scStart = start;
|
||||
dev->_scEnd = end;
|
||||
dev->_scDirection = 1;
|
||||
if (start > end ) dev->_scDirection = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ssd1306_scroll_text(SSD1306_t * dev, char * text, int text_len, bool invert)
|
||||
{
|
||||
ESP_LOGD(TAG, "dev->_scEnable=%d", dev->_scEnable);
|
||||
if (dev->_scEnable == false) return;
|
||||
|
||||
void (*func)(SSD1306_t * dev, int page, int seg, uint8_t * images, int width);
|
||||
if (dev->_address == SPIAddress) {
|
||||
func = spi_display_image;
|
||||
} else {
|
||||
func = i2c_display_image;
|
||||
}
|
||||
|
||||
int srcIndex = dev->_scEnd - dev->_scDirection;
|
||||
while(1) {
|
||||
int dstIndex = srcIndex + dev->_scDirection;
|
||||
ESP_LOGD(TAG, "srcIndex=%d dstIndex=%d", srcIndex,dstIndex);
|
||||
for(int seg = 0; seg < dev->_width; seg++) {
|
||||
dev->_page[dstIndex]._segs[seg] = dev->_page[srcIndex]._segs[seg];
|
||||
}
|
||||
(*func)(dev, dstIndex, 0, dev->_page[dstIndex]._segs, sizeof(dev->_page[dstIndex]._segs));
|
||||
if (srcIndex == dev->_scStart) break;
|
||||
srcIndex = srcIndex - dev->_scDirection;
|
||||
}
|
||||
|
||||
int _text_len = text_len;
|
||||
if (_text_len > 16) _text_len = 16;
|
||||
|
||||
ssd1306_display_text(dev, srcIndex, text, text_len, invert);
|
||||
}
|
||||
|
||||
void ssd1306_scroll_clear(SSD1306_t * dev)
|
||||
{
|
||||
ESP_LOGD(TAG, "dev->_scEnable=%d", dev->_scEnable);
|
||||
if (dev->_scEnable == false) return;
|
||||
|
||||
int srcIndex = dev->_scEnd - dev->_scDirection;
|
||||
while(1) {
|
||||
int dstIndex = srcIndex + dev->_scDirection;
|
||||
ESP_LOGD(TAG, "srcIndex=%d dstIndex=%d", srcIndex,dstIndex);
|
||||
ssd1306_clear_line(dev, dstIndex, false);
|
||||
if (dstIndex == dev->_scStart) break;
|
||||
srcIndex = srcIndex - dev->_scDirection;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ssd1306_hardware_scroll(SSD1306_t * dev, ssd1306_scroll_type_t scroll)
|
||||
{
|
||||
if (dev->_address == SPIAddress) {
|
||||
spi_hardware_scroll(dev, scroll);
|
||||
} else {
|
||||
i2c_hardware_scroll(dev, scroll);
|
||||
}
|
||||
}
|
||||
|
||||
// delay = 0 : display with no wait
|
||||
// delay > 0 : display with wait
|
||||
// delay < 0 : no display
|
||||
void ssd1306_wrap_arround(SSD1306_t * dev, ssd1306_scroll_type_t scroll, int start, int end, int8_t delay)
|
||||
{
|
||||
if (scroll == SCROLL_RIGHT) {
|
||||
int _start = start; // 0 to 7
|
||||
int _end = end; // 0 to 7
|
||||
if (_end >= dev->_pages) _end = dev->_pages - 1;
|
||||
uint8_t wk;
|
||||
//for (int page=0;page<dev->_pages;page++) {
|
||||
for (int page=_start;page<=_end;page++) {
|
||||
wk = dev->_page[page]._segs[127];
|
||||
for (int seg=127;seg>0;seg--) {
|
||||
dev->_page[page]._segs[seg] = dev->_page[page]._segs[seg-1];
|
||||
}
|
||||
dev->_page[page]._segs[0] = wk;
|
||||
}
|
||||
|
||||
} else if (scroll == SCROLL_LEFT) {
|
||||
int _start = start; // 0 to 7
|
||||
int _end = end; // 0 to 7
|
||||
if (_end >= dev->_pages) _end = dev->_pages - 1;
|
||||
uint8_t wk;
|
||||
//for (int page=0;page<dev->_pages;page++) {
|
||||
for (int page=_start;page<=_end;page++) {
|
||||
wk = dev->_page[page]._segs[0];
|
||||
for (int seg=0;seg<127;seg++) {
|
||||
dev->_page[page]._segs[seg] = dev->_page[page]._segs[seg+1];
|
||||
}
|
||||
dev->_page[page]._segs[127] = wk;
|
||||
}
|
||||
|
||||
} else if (scroll == SCROLL_UP) {
|
||||
int _start = start; // 0 to {width-1}
|
||||
int _end = end; // 0 to {width-1}
|
||||
if (_end >= dev->_width) _end = dev->_width - 1;
|
||||
uint8_t wk0;
|
||||
uint8_t wk1;
|
||||
uint8_t wk2;
|
||||
uint8_t save[128];
|
||||
// Save pages 0
|
||||
for (int seg=0;seg<128;seg++) {
|
||||
save[seg] = dev->_page[0]._segs[seg];
|
||||
}
|
||||
// Page0 to Page6
|
||||
for (int page=0;page<dev->_pages-1;page++) {
|
||||
//for (int seg=0;seg<128;seg++) {
|
||||
for (int seg=_start;seg<=_end;seg++) {
|
||||
wk0 = dev->_page[page]._segs[seg];
|
||||
wk1 = dev->_page[page+1]._segs[seg];
|
||||
if (dev->_flip) wk0 = ssd1306_rotate_byte(wk0);
|
||||
if (dev->_flip) wk1 = ssd1306_rotate_byte(wk1);
|
||||
if (seg == 0) {
|
||||
ESP_LOGD(TAG, "b page=%d wk0=%02x wk1=%02x", page, wk0, wk1);
|
||||
}
|
||||
wk0 = wk0 >> 1;
|
||||
wk1 = wk1 & 0x01;
|
||||
wk1 = wk1 << 7;
|
||||
wk2 = wk0 | wk1;
|
||||
if (seg == 0) {
|
||||
ESP_LOGD(TAG, "a page=%d wk0=%02x wk1=%02x wk2=%02x", page, wk0, wk1, wk2);
|
||||
}
|
||||
if (dev->_flip) wk2 = ssd1306_rotate_byte(wk2);
|
||||
dev->_page[page]._segs[seg] = wk2;
|
||||
}
|
||||
}
|
||||
// Page7
|
||||
int pages = dev->_pages-1;
|
||||
//for (int seg=0;seg<128;seg++) {
|
||||
for (int seg=_start;seg<=_end;seg++) {
|
||||
wk0 = dev->_page[pages]._segs[seg];
|
||||
wk1 = save[seg];
|
||||
if (dev->_flip) wk0 = ssd1306_rotate_byte(wk0);
|
||||
if (dev->_flip) wk1 = ssd1306_rotate_byte(wk1);
|
||||
wk0 = wk0 >> 1;
|
||||
wk1 = wk1 & 0x01;
|
||||
wk1 = wk1 << 7;
|
||||
wk2 = wk0 | wk1;
|
||||
if (dev->_flip) wk2 = ssd1306_rotate_byte(wk2);
|
||||
dev->_page[pages]._segs[seg] = wk2;
|
||||
}
|
||||
|
||||
} else if (scroll == SCROLL_DOWN) {
|
||||
int _start = start; // 0 to {width-1}
|
||||
int _end = end; // 0 to {width-1}
|
||||
if (_end >= dev->_width) _end = dev->_width - 1;
|
||||
uint8_t wk0;
|
||||
uint8_t wk1;
|
||||
uint8_t wk2;
|
||||
uint8_t save[128];
|
||||
// Save pages 7
|
||||
int pages = dev->_pages-1;
|
||||
for (int seg=0;seg<128;seg++) {
|
||||
save[seg] = dev->_page[pages]._segs[seg];
|
||||
}
|
||||
// Page7 to Page1
|
||||
for (int page=pages;page>0;page--) {
|
||||
//for (int seg=0;seg<128;seg++) {
|
||||
for (int seg=_start;seg<=_end;seg++) {
|
||||
wk0 = dev->_page[page]._segs[seg];
|
||||
wk1 = dev->_page[page-1]._segs[seg];
|
||||
if (dev->_flip) wk0 = ssd1306_rotate_byte(wk0);
|
||||
if (dev->_flip) wk1 = ssd1306_rotate_byte(wk1);
|
||||
if (seg == 0) {
|
||||
ESP_LOGD(TAG, "b page=%d wk0=%02x wk1=%02x", page, wk0, wk1);
|
||||
}
|
||||
wk0 = wk0 << 1;
|
||||
wk1 = wk1 & 0x80;
|
||||
wk1 = wk1 >> 7;
|
||||
wk2 = wk0 | wk1;
|
||||
if (seg == 0) {
|
||||
ESP_LOGD(TAG, "a page=%d wk0=%02x wk1=%02x wk2=%02x", page, wk0, wk1, wk2);
|
||||
}
|
||||
if (dev->_flip) wk2 = ssd1306_rotate_byte(wk2);
|
||||
dev->_page[page]._segs[seg] = wk2;
|
||||
}
|
||||
}
|
||||
// Page0
|
||||
//for (int seg=0;seg<128;seg++) {
|
||||
for (int seg=_start;seg<=_end;seg++) {
|
||||
wk0 = dev->_page[0]._segs[seg];
|
||||
wk1 = save[seg];
|
||||
if (dev->_flip) wk0 = ssd1306_rotate_byte(wk0);
|
||||
if (dev->_flip) wk1 = ssd1306_rotate_byte(wk1);
|
||||
wk0 = wk0 << 1;
|
||||
wk1 = wk1 & 0x80;
|
||||
wk1 = wk1 >> 7;
|
||||
wk2 = wk0 | wk1;
|
||||
if (dev->_flip) wk2 = ssd1306_rotate_byte(wk2);
|
||||
dev->_page[0]._segs[seg] = wk2;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (delay >= 0) {
|
||||
for (int page=0;page<dev->_pages;page++) {
|
||||
if (dev->_address == SPIAddress) {
|
||||
spi_display_image(dev, page, 0, dev->_page[page]._segs, 128);
|
||||
} else {
|
||||
i2c_display_image(dev, page, 0, dev->_page[page]._segs, 128);
|
||||
}
|
||||
if (delay) vTaskDelay(delay);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ssd1306_bitmaps(SSD1306_t * dev, int xpos, int ypos, uint8_t * bitmap, int width, int height, bool invert)
|
||||
{
|
||||
if ( (width % 8) != 0) {
|
||||
ESP_LOGE(TAG, "width must be a multiple of 8");
|
||||
return;
|
||||
}
|
||||
int _width = width / 8;
|
||||
uint8_t wk0;
|
||||
uint8_t wk1;
|
||||
uint8_t wk2;
|
||||
uint8_t page = (ypos / 8);
|
||||
uint8_t _seg = xpos;
|
||||
uint8_t dstBits = (ypos % 8);
|
||||
ESP_LOGD(TAG, "ypos=%d page=%d dstBits=%d", ypos, page, dstBits);
|
||||
int offset = 0;
|
||||
for(int _height=0;_height<height;_height++) {
|
||||
for (int index=0;index<_width;index++) {
|
||||
for (int srcBits=7; srcBits>=0; srcBits--) {
|
||||
wk0 = dev->_page[page]._segs[_seg];
|
||||
if (dev->_flip) wk0 = ssd1306_rotate_byte(wk0);
|
||||
|
||||
wk1 = bitmap[index+offset];
|
||||
if (invert) wk1 = ~wk1;
|
||||
|
||||
//wk2 = ssd1306_copy_bit(bitmap[index+offset], srcBits, wk0, dstBits);
|
||||
wk2 = ssd1306_copy_bit(wk1, srcBits, wk0, dstBits);
|
||||
if (dev->_flip) wk2 = ssd1306_rotate_byte(wk2);
|
||||
|
||||
ESP_LOGD(TAG, "index=%d offset=%d page=%d _seg=%d, wk2=%02x", index, offset, page, _seg, wk2);
|
||||
dev->_page[page]._segs[_seg] = wk2;
|
||||
_seg++;
|
||||
}
|
||||
}
|
||||
vTaskDelay(1);
|
||||
offset = offset + _width;
|
||||
dstBits++;
|
||||
_seg = xpos;
|
||||
if (dstBits == 8) {
|
||||
page++;
|
||||
dstBits=0;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
for (int _seg=ypos;_seg<ypos+width;_seg++) {
|
||||
ssd1306_dump_page(dev, page-1, _seg);
|
||||
}
|
||||
for (int _seg=ypos;_seg<ypos+width;_seg++) {
|
||||
ssd1306_dump_page(dev, page, _seg);
|
||||
}
|
||||
#endif
|
||||
ssd1306_show_buffer(dev);
|
||||
}
|
||||
|
||||
|
||||
// Set pixel to internal buffer. Not show it.
|
||||
void _ssd1306_pixel(SSD1306_t * dev, int xpos, int ypos, bool invert)
|
||||
{
|
||||
uint8_t _page = (ypos / 8);
|
||||
uint8_t _bits = (ypos % 8);
|
||||
uint8_t _seg = xpos;
|
||||
uint8_t wk0 = dev->_page[_page]._segs[_seg];
|
||||
uint8_t wk1 = 1 << _bits;
|
||||
ESP_LOGD(TAG, "ypos=%d _page=%d _bits=%d wk0=0x%02x wk1=0x%02x", ypos, _page, _bits, wk0, wk1);
|
||||
if (invert) {
|
||||
wk0 = wk0 & ~wk1;
|
||||
} else {
|
||||
wk0 = wk0 | wk1;
|
||||
}
|
||||
if (dev->_flip) wk0 = ssd1306_rotate_byte(wk0);
|
||||
ESP_LOGD(TAG, "wk0=0x%02x wk1=0x%02x", wk0, wk1);
|
||||
dev->_page[_page]._segs[_seg] = wk0;
|
||||
}
|
||||
|
||||
// Set line to internal buffer. Not show it.
|
||||
void _ssd1306_line(SSD1306_t * dev, int x1, int y1, int x2, int y2, bool invert)
|
||||
{
|
||||
int i;
|
||||
int dx,dy;
|
||||
int sx,sy;
|
||||
int E;
|
||||
|
||||
/* distance between two points */
|
||||
dx = ( x2 > x1 ) ? x2 - x1 : x1 - x2;
|
||||
dy = ( y2 > y1 ) ? y2 - y1 : y1 - y2;
|
||||
|
||||
/* direction of two point */
|
||||
sx = ( x2 > x1 ) ? 1 : -1;
|
||||
sy = ( y2 > y1 ) ? 1 : -1;
|
||||
|
||||
/* inclination < 1 */
|
||||
if ( dx > dy ) {
|
||||
E = -dx;
|
||||
for ( i = 0 ; i <= dx ; i++ ) {
|
||||
_ssd1306_pixel(dev, x1, y1, invert);
|
||||
x1 += sx;
|
||||
E += 2 * dy;
|
||||
if ( E >= 0 ) {
|
||||
y1 += sy;
|
||||
E -= 2 * dx;
|
||||
}
|
||||
}
|
||||
|
||||
/* inclination >= 1 */
|
||||
} else {
|
||||
E = -dy;
|
||||
for ( i = 0 ; i <= dy ; i++ ) {
|
||||
_ssd1306_pixel(dev, x1, y1, invert);
|
||||
y1 += sy;
|
||||
E += 2 * dx;
|
||||
if ( E >= 0 ) {
|
||||
x1 += sx;
|
||||
E -= 2 * dy;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ssd1306_invert(uint8_t *buf, size_t blen)
|
||||
{
|
||||
uint8_t wk;
|
||||
for(int i=0; i<blen; i++){
|
||||
wk = buf[i];
|
||||
buf[i] = ~wk;
|
||||
}
|
||||
}
|
||||
|
||||
// Flip upside down
|
||||
void ssd1306_flip(uint8_t *buf, size_t blen)
|
||||
{
|
||||
for(int i=0; i<blen; i++){
|
||||
buf[i] = ssd1306_rotate_byte(buf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t ssd1306_copy_bit(uint8_t src, int srcBits, uint8_t dst, int dstBits)
|
||||
{
|
||||
ESP_LOGD(TAG, "src=%02x srcBits=%d dst=%02x dstBits=%d", src, srcBits, dst, dstBits);
|
||||
uint8_t smask = 0x01 << srcBits;
|
||||
uint8_t dmask = 0x01 << dstBits;
|
||||
uint8_t _src = src & smask;
|
||||
#if 0
|
||||
if (_src != 0) _src = 1;
|
||||
uint8_t _wk = _src << dstBits;
|
||||
uint8_t _dst = dst | _wk;
|
||||
#endif
|
||||
uint8_t _dst;
|
||||
if (_src != 0) {
|
||||
_dst = dst | dmask; // set bit
|
||||
} else {
|
||||
_dst = dst & ~(dmask); // clear bit
|
||||
}
|
||||
return _dst;
|
||||
}
|
||||
|
||||
|
||||
// Rotate 8-bit data
|
||||
// 0x12-->0x48
|
||||
uint8_t ssd1306_rotate_byte(uint8_t ch1) {
|
||||
uint8_t ch2 = 0;
|
||||
for (int j=0;j<8;j++) {
|
||||
ch2 = (ch2 << 1) + (ch1 & 0x01);
|
||||
ch1 = ch1 >> 1;
|
||||
}
|
||||
return ch2;
|
||||
}
|
||||
|
||||
|
||||
void ssd1306_fadeout(SSD1306_t * dev)
|
||||
{
|
||||
void (*func)(SSD1306_t * dev, int page, int seg, uint8_t * images, int width);
|
||||
if (dev->_address == SPIAddress) {
|
||||
func = spi_display_image;
|
||||
} else {
|
||||
func = i2c_display_image;
|
||||
}
|
||||
|
||||
uint8_t image[1];
|
||||
for(int page=0; page<dev->_pages; page++) {
|
||||
image[0] = 0xFF;
|
||||
for(int line=0; line<8; line++) {
|
||||
if (dev->_flip) {
|
||||
image[0] = image[0] >> 1;
|
||||
} else {
|
||||
image[0] = image[0] << 1;
|
||||
}
|
||||
for(int seg=0; seg<128; seg++) {
|
||||
(*func)(dev, page, seg, image, 1);
|
||||
dev->_page[page]._segs[seg] = image[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ssd1306_dump(SSD1306_t dev)
|
||||
{
|
||||
printf("_address=%x\n",dev._address);
|
||||
printf("_width=%x\n",dev._width);
|
||||
printf("_height=%x\n",dev._height);
|
||||
printf("_pages=%x\n",dev._pages);
|
||||
}
|
||||
|
||||
void ssd1306_dump_page(SSD1306_t * dev, int page, int seg)
|
||||
{
|
||||
ESP_LOGI(TAG, "dev->_page[%d]._segs[%d]=%02x", page, seg, dev->_page[page]._segs[seg]);
|
||||
}
|
||||
|
157
components/ssd1306/ssd1306.h
Normal file
157
components/ssd1306/ssd1306.h
Normal file
@ -0,0 +1,157 @@
|
||||
#ifndef MAIN_SSD1306_H_
|
||||
#define MAIN_SSD1306_H_
|
||||
|
||||
#include "driver/spi_master.h"
|
||||
|
||||
// Following definitions are bollowed from
|
||||
// http://robotcantalk.blogspot.com/2015/03/interfacing-arduino-with-ssd1306-driven.html
|
||||
|
||||
/* Control byte for i2c
|
||||
Co : bit 8 : Continuation Bit
|
||||
* 1 = no-continuation (only one byte to follow)
|
||||
* 0 = the controller should expect a stream of bytes.
|
||||
D/C# : bit 7 : Data/Command Select bit
|
||||
* 1 = the next byte or byte stream will be Data.
|
||||
* 0 = a Command byte or byte stream will be coming up next.
|
||||
Bits 6-0 will be all zeros.
|
||||
Usage:
|
||||
0x80 : Single Command byte
|
||||
0x00 : Command Stream
|
||||
0xC0 : Single Data byte
|
||||
0x40 : Data Stream
|
||||
*/
|
||||
#define OLED_CONTROL_BYTE_CMD_SINGLE 0x80
|
||||
#define OLED_CONTROL_BYTE_CMD_STREAM 0x00
|
||||
#define OLED_CONTROL_BYTE_DATA_SINGLE 0xC0
|
||||
#define OLED_CONTROL_BYTE_DATA_STREAM 0x40
|
||||
|
||||
// Fundamental commands (pg.28)
|
||||
#define OLED_CMD_SET_CONTRAST 0x81 // follow with 0x7F
|
||||
#define OLED_CMD_DISPLAY_RAM 0xA4
|
||||
#define OLED_CMD_DISPLAY_ALLON 0xA5
|
||||
#define OLED_CMD_DISPLAY_NORMAL 0xA6
|
||||
#define OLED_CMD_DISPLAY_INVERTED 0xA7
|
||||
#define OLED_CMD_DISPLAY_OFF 0xAE
|
||||
#define OLED_CMD_DISPLAY_ON 0xAF
|
||||
|
||||
// Addressing Command Table (pg.30)
|
||||
#define OLED_CMD_SET_MEMORY_ADDR_MODE 0x20
|
||||
#define OLED_CMD_SET_HORI_ADDR_MODE 0x00 // Horizontal Addressing Mode
|
||||
#define OLED_CMD_SET_VERT_ADDR_MODE 0x01 // Vertical Addressing Mode
|
||||
#define OLED_CMD_SET_PAGE_ADDR_MODE 0x02 // Page Addressing Mode
|
||||
#define OLED_CMD_SET_COLUMN_RANGE 0x21 // can be used only in HORZ/VERT mode - follow with 0x00 and 0x7F = COL127
|
||||
#define OLED_CMD_SET_PAGE_RANGE 0x22 // can be used only in HORZ/VERT mode - follow with 0x00 and 0x07 = PAGE7
|
||||
|
||||
// Hardware Config (pg.31)
|
||||
#define OLED_CMD_SET_DISPLAY_START_LINE 0x40
|
||||
#define OLED_CMD_SET_SEGMENT_REMAP_0 0xA0
|
||||
#define OLED_CMD_SET_SEGMENT_REMAP_1 0xA1
|
||||
#define OLED_CMD_SET_MUX_RATIO 0xA8 // follow with 0x3F = 64 MUX
|
||||
#define OLED_CMD_SET_COM_SCAN_MODE 0xC8
|
||||
#define OLED_CMD_SET_DISPLAY_OFFSET 0xD3 // follow with 0x00
|
||||
#define OLED_CMD_SET_COM_PIN_MAP 0xDA // follow with 0x12
|
||||
#define OLED_CMD_NOP 0xE3 // NOP
|
||||
|
||||
// Timing and Driving Scheme (pg.32)
|
||||
#define OLED_CMD_SET_DISPLAY_CLK_DIV 0xD5 // follow with 0x80
|
||||
#define OLED_CMD_SET_PRECHARGE 0xD9 // follow with 0xF1
|
||||
#define OLED_CMD_SET_VCOMH_DESELCT 0xDB // follow with 0x30
|
||||
|
||||
// Charge Pump (pg.62)
|
||||
#define OLED_CMD_SET_CHARGE_PUMP 0x8D // follow with 0x14
|
||||
|
||||
// Scrolling Command
|
||||
#define OLED_CMD_HORIZONTAL_RIGHT 0x26
|
||||
#define OLED_CMD_HORIZONTAL_LEFT 0x27
|
||||
#define OLED_CMD_CONTINUOUS_SCROLL 0x29
|
||||
#define OLED_CMD_DEACTIVE_SCROLL 0x2E
|
||||
#define OLED_CMD_ACTIVE_SCROLL 0x2F
|
||||
#define OLED_CMD_VERTICAL 0xA3
|
||||
|
||||
#define I2CAddress 0x3C
|
||||
#define SPIAddress 0xFF
|
||||
|
||||
typedef enum {
|
||||
SCROLL_RIGHT = 1,
|
||||
SCROLL_LEFT = 2,
|
||||
SCROLL_DOWN = 3,
|
||||
SCROLL_UP = 4,
|
||||
SCROLL_STOP = 5
|
||||
} ssd1306_scroll_type_t;
|
||||
|
||||
typedef struct {
|
||||
bool _valid; // Not using it anymore
|
||||
int _segLen; // Not using it anymore
|
||||
uint8_t _segs[128];
|
||||
} PAGE_t;
|
||||
|
||||
typedef struct {
|
||||
int _address;
|
||||
int _width;
|
||||
int _height;
|
||||
int _pages;
|
||||
int _dc;
|
||||
spi_device_handle_t _SPIHandle;
|
||||
bool _scEnable;
|
||||
int _scStart;
|
||||
int _scEnd;
|
||||
int _scDirection;
|
||||
PAGE_t _page[8];
|
||||
bool _flip;
|
||||
} SSD1306_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
void ssd1306_init(SSD1306_t * dev, int width, int height);
|
||||
int ssd1306_get_width(SSD1306_t * dev);
|
||||
int ssd1306_get_height(SSD1306_t * dev);
|
||||
int ssd1306_get_pages(SSD1306_t * dev);
|
||||
void ssd1306_show_buffer(SSD1306_t * dev);
|
||||
void ssd1306_set_buffer(SSD1306_t * dev, uint8_t * buffer);
|
||||
void ssd1306_get_buffer(SSD1306_t * dev, uint8_t * buffer);
|
||||
void ssd1306_display_image(SSD1306_t * dev, int page, int seg, uint8_t * images, int width);
|
||||
void ssd1306_display_text(SSD1306_t * dev, int page, char * text, int text_len, bool invert);
|
||||
void ssd1306_display_text_x3(SSD1306_t * dev, int page, char * text, int text_len, bool invert);
|
||||
void ssd1306_clear_screen(SSD1306_t * dev, bool invert);
|
||||
void ssd1306_clear_line(SSD1306_t * dev, int page, bool invert);
|
||||
void ssd1306_contrast(SSD1306_t * dev, int contrast);
|
||||
void ssd1306_software_scroll(SSD1306_t * dev, int start, int end);
|
||||
void ssd1306_scroll_text(SSD1306_t * dev, char * text, int text_len, bool invert);
|
||||
void ssd1306_scroll_clear(SSD1306_t * dev);
|
||||
void ssd1306_hardware_scroll(SSD1306_t * dev, ssd1306_scroll_type_t scroll);
|
||||
void ssd1306_wrap_arround(SSD1306_t * dev, ssd1306_scroll_type_t scroll, int start, int end, int8_t delay);
|
||||
void ssd1306_bitmaps(SSD1306_t * dev, int xpos, int ypos, uint8_t * bitmap, int width, int height, bool invert);
|
||||
void _ssd1306_pixel(SSD1306_t * dev, int xpos, int ypos, bool invert);
|
||||
void _ssd1306_line(SSD1306_t * dev, int x1, int y1, int x2, int y2, bool invert);
|
||||
void ssd1306_invert(uint8_t *buf, size_t blen);
|
||||
void ssd1306_flip(uint8_t *buf, size_t blen);
|
||||
uint8_t ssd1306_copy_bit(uint8_t src, int srcBits, uint8_t dst, int dstBits);
|
||||
uint8_t ssd1306_rotate_byte(uint8_t ch1);
|
||||
void ssd1306_fadeout(SSD1306_t * dev);
|
||||
void ssd1306_dump(SSD1306_t dev);
|
||||
void ssd1306_dump_page(SSD1306_t * dev, int page, int seg);
|
||||
|
||||
void i2c_master_init(SSD1306_t * dev, int16_t sda, int16_t scl, int16_t reset);
|
||||
void i2c_init(SSD1306_t * dev, int width, int height);
|
||||
void i2c_display_image(SSD1306_t * dev, int page, int seg, uint8_t * images, int width);
|
||||
void i2c_contrast(SSD1306_t * dev, int contrast);
|
||||
void i2c_hardware_scroll(SSD1306_t * dev, ssd1306_scroll_type_t scroll);
|
||||
|
||||
void spi_master_init(SSD1306_t * dev, int16_t GPIO_MOSI, int16_t GPIO_SCLK, int16_t GPIO_CS, int16_t GPIO_DC, int16_t GPIO_RESET);
|
||||
bool spi_master_write_byte(spi_device_handle_t SPIHandle, const uint8_t* Data, size_t DataLength );
|
||||
bool spi_master_write_command(SSD1306_t * dev, uint8_t Command );
|
||||
bool spi_master_write_data(SSD1306_t * dev, const uint8_t* Data, size_t DataLength );
|
||||
void spi_init(SSD1306_t * dev, int width, int height);
|
||||
void spi_display_image(SSD1306_t * dev, int page, int seg, uint8_t * images, int width);
|
||||
void spi_contrast(SSD1306_t * dev, int contrast);
|
||||
void spi_hardware_scroll(SSD1306_t * dev, ssd1306_scroll_type_t scroll);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* MAIN_SSD1306_H_ */
|
||||
|
253
components/ssd1306/ssd1306_i2c.c
Normal file
253
components/ssd1306/ssd1306_i2c.c
Normal file
@ -0,0 +1,253 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#include "driver/i2c.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "ssd1306.h"
|
||||
|
||||
#define tag "SSD1306"
|
||||
|
||||
#if CONFIG_I2C_PORT_0
|
||||
#define I2C_NUM I2C_NUM_0
|
||||
#elif CONFIG_I2C_PORT_1
|
||||
#define I2C_NUM I2C_NUM_1
|
||||
#else
|
||||
#define I2C_NUM I2C_NUM_0 // if spi is selected
|
||||
#endif
|
||||
|
||||
#define I2C_MASTER_FREQ_HZ 400000 /*!< I2C clock of SSD1306 can run at 400 kHz max. */
|
||||
|
||||
void i2c_master_init(SSD1306_t * dev, int16_t sda, int16_t scl, int16_t reset)
|
||||
{
|
||||
i2c_config_t i2c_config = {
|
||||
.mode = I2C_MODE_MASTER,
|
||||
.sda_io_num = sda,
|
||||
.scl_io_num = scl,
|
||||
.sda_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.scl_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.master.clk_speed = I2C_MASTER_FREQ_HZ
|
||||
};
|
||||
ESP_ERROR_CHECK(i2c_param_config(I2C_NUM, &i2c_config));
|
||||
ESP_ERROR_CHECK(i2c_driver_install(I2C_NUM, I2C_MODE_MASTER, 0, 0, 0));
|
||||
|
||||
if (reset >= 0) {
|
||||
//gpio_pad_select_gpio(reset);
|
||||
gpio_reset_pin(reset);
|
||||
gpio_set_direction(reset, GPIO_MODE_OUTPUT);
|
||||
gpio_set_level(reset, 0);
|
||||
vTaskDelay(50 / portTICK_PERIOD_MS);
|
||||
gpio_set_level(reset, 1);
|
||||
}
|
||||
dev->_address = I2CAddress;
|
||||
dev->_flip = false;
|
||||
}
|
||||
|
||||
void i2c_init(SSD1306_t * dev, int width, int height) {
|
||||
dev->_width = width;
|
||||
dev->_height = height;
|
||||
dev->_pages = 8;
|
||||
if (dev->_height == 32) dev->_pages = 4;
|
||||
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, (dev->_address << 1) | I2C_MASTER_WRITE, true);
|
||||
i2c_master_write_byte(cmd, OLED_CONTROL_BYTE_CMD_STREAM, true);
|
||||
i2c_master_write_byte(cmd, OLED_CMD_DISPLAY_OFF, true); // AE
|
||||
i2c_master_write_byte(cmd, OLED_CMD_SET_MUX_RATIO, true); // A8
|
||||
if (dev->_height == 64) i2c_master_write_byte(cmd, 0x3F, true);
|
||||
if (dev->_height == 32) i2c_master_write_byte(cmd, 0x1F, true);
|
||||
i2c_master_write_byte(cmd, OLED_CMD_SET_DISPLAY_OFFSET, true); // D3
|
||||
i2c_master_write_byte(cmd, 0x00, true);
|
||||
//i2c_master_write_byte(cmd, OLED_CONTROL_BYTE_DATA_STREAM, true); // 40
|
||||
i2c_master_write_byte(cmd, OLED_CMD_SET_DISPLAY_START_LINE, true); // 40
|
||||
//i2c_master_write_byte(cmd, OLED_CMD_SET_SEGMENT_REMAP, true); // A1
|
||||
if (dev->_flip) {
|
||||
i2c_master_write_byte(cmd, OLED_CMD_SET_SEGMENT_REMAP_0, true); // A0
|
||||
} else {
|
||||
i2c_master_write_byte(cmd, OLED_CMD_SET_SEGMENT_REMAP_1, true); // A1
|
||||
}
|
||||
i2c_master_write_byte(cmd, OLED_CMD_SET_COM_SCAN_MODE, true); // C8
|
||||
i2c_master_write_byte(cmd, OLED_CMD_SET_DISPLAY_CLK_DIV, true); // D5
|
||||
i2c_master_write_byte(cmd, 0x80, true);
|
||||
i2c_master_write_byte(cmd, OLED_CMD_SET_COM_PIN_MAP, true); // DA
|
||||
if (dev->_height == 64) i2c_master_write_byte(cmd, 0x12, true);
|
||||
if (dev->_height == 32) i2c_master_write_byte(cmd, 0x02, true);
|
||||
i2c_master_write_byte(cmd, OLED_CMD_SET_CONTRAST, true); // 81
|
||||
i2c_master_write_byte(cmd, 0xFF, true);
|
||||
i2c_master_write_byte(cmd, OLED_CMD_DISPLAY_RAM, true); // A4
|
||||
i2c_master_write_byte(cmd, OLED_CMD_SET_VCOMH_DESELCT, true); // DB
|
||||
i2c_master_write_byte(cmd, 0x40, true);
|
||||
i2c_master_write_byte(cmd, OLED_CMD_SET_MEMORY_ADDR_MODE, true); // 20
|
||||
//i2c_master_write_byte(cmd, OLED_CMD_SET_HORI_ADDR_MODE, true); // 00
|
||||
i2c_master_write_byte(cmd, OLED_CMD_SET_PAGE_ADDR_MODE, true); // 02
|
||||
// Set Lower Column Start Address for Page Addressing Mode
|
||||
i2c_master_write_byte(cmd, 0x00, true);
|
||||
// Set Higher Column Start Address for Page Addressing Mode
|
||||
i2c_master_write_byte(cmd, 0x10, true);
|
||||
i2c_master_write_byte(cmd, OLED_CMD_SET_CHARGE_PUMP, true); // 8D
|
||||
i2c_master_write_byte(cmd, 0x14, true);
|
||||
i2c_master_write_byte(cmd, OLED_CMD_DEACTIVE_SCROLL, true); // 2E
|
||||
i2c_master_write_byte(cmd, OLED_CMD_DISPLAY_NORMAL, true); // A6
|
||||
i2c_master_write_byte(cmd, OLED_CMD_DISPLAY_ON, true); // AF
|
||||
|
||||
i2c_master_stop(cmd);
|
||||
|
||||
esp_err_t espRc = i2c_master_cmd_begin(I2C_NUM, cmd, 10/portTICK_PERIOD_MS);
|
||||
if (espRc == ESP_OK) {
|
||||
ESP_LOGI(tag, "OLED configured successfully");
|
||||
} else {
|
||||
ESP_LOGE(tag, "OLED configuration failed. code: 0x%.2X", espRc);
|
||||
}
|
||||
i2c_cmd_link_delete(cmd);
|
||||
}
|
||||
|
||||
|
||||
void i2c_display_image(SSD1306_t * dev, int page, int seg, uint8_t * images, int width) {
|
||||
i2c_cmd_handle_t cmd;
|
||||
|
||||
if (page >= dev->_pages) return;
|
||||
if (seg >= dev->_width) return;
|
||||
|
||||
int _seg = seg + CONFIG_OFFSETX;
|
||||
uint8_t columLow = _seg & 0x0F;
|
||||
uint8_t columHigh = (_seg >> 4) & 0x0F;
|
||||
|
||||
int _page = page;
|
||||
if (dev->_flip) {
|
||||
_page = (dev->_pages - page) - 1;
|
||||
}
|
||||
|
||||
cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, (dev->_address << 1) | I2C_MASTER_WRITE, true);
|
||||
|
||||
i2c_master_write_byte(cmd, OLED_CONTROL_BYTE_CMD_STREAM, true);
|
||||
// Set Lower Column Start Address for Page Addressing Mode
|
||||
i2c_master_write_byte(cmd, (0x00 + columLow), true);
|
||||
// Set Higher Column Start Address for Page Addressing Mode
|
||||
i2c_master_write_byte(cmd, (0x10 + columHigh), true);
|
||||
// Set Page Start Address for Page Addressing Mode
|
||||
i2c_master_write_byte(cmd, 0xB0 | _page, true);
|
||||
|
||||
i2c_master_stop(cmd);
|
||||
i2c_master_cmd_begin(I2C_NUM, cmd, 10/portTICK_PERIOD_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
|
||||
cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, (dev->_address << 1) | I2C_MASTER_WRITE, true);
|
||||
|
||||
i2c_master_write_byte(cmd, OLED_CONTROL_BYTE_DATA_STREAM, true);
|
||||
i2c_master_write(cmd, images, width, true);
|
||||
|
||||
i2c_master_stop(cmd);
|
||||
i2c_master_cmd_begin(I2C_NUM, cmd, 10/portTICK_PERIOD_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
}
|
||||
|
||||
void i2c_contrast(SSD1306_t * dev, int contrast) {
|
||||
i2c_cmd_handle_t cmd;
|
||||
int _contrast = contrast;
|
||||
if (contrast < 0x0) _contrast = 0;
|
||||
if (contrast > 0xFF) _contrast = 0xFF;
|
||||
|
||||
cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, (dev->_address << 1) | I2C_MASTER_WRITE, true);
|
||||
i2c_master_write_byte(cmd, OLED_CONTROL_BYTE_CMD_STREAM, true);
|
||||
i2c_master_write_byte(cmd, OLED_CMD_SET_CONTRAST, true); // 81
|
||||
i2c_master_write_byte(cmd, _contrast, true);
|
||||
i2c_master_stop(cmd);
|
||||
i2c_master_cmd_begin(I2C_NUM, cmd, 10/portTICK_PERIOD_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
}
|
||||
|
||||
|
||||
void i2c_hardware_scroll(SSD1306_t * dev, ssd1306_scroll_type_t scroll) {
|
||||
esp_err_t espRc;
|
||||
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
|
||||
i2c_master_write_byte(cmd, (dev->_address << 1) | I2C_MASTER_WRITE, true);
|
||||
i2c_master_write_byte(cmd, OLED_CONTROL_BYTE_CMD_STREAM, true);
|
||||
|
||||
if (scroll == SCROLL_RIGHT) {
|
||||
i2c_master_write_byte(cmd, OLED_CMD_HORIZONTAL_RIGHT, true); // 26
|
||||
i2c_master_write_byte(cmd, 0x00, true); // Dummy byte
|
||||
i2c_master_write_byte(cmd, 0x00, true); // Define start page address
|
||||
i2c_master_write_byte(cmd, 0x07, true); // Frame frequency
|
||||
i2c_master_write_byte(cmd, 0x07, true); // Define end page address
|
||||
i2c_master_write_byte(cmd, 0x00, true); //
|
||||
i2c_master_write_byte(cmd, 0xFF, true); //
|
||||
i2c_master_write_byte(cmd, OLED_CMD_ACTIVE_SCROLL, true); // 2F
|
||||
}
|
||||
|
||||
if (scroll == SCROLL_LEFT) {
|
||||
i2c_master_write_byte(cmd, OLED_CMD_HORIZONTAL_LEFT, true); // 27
|
||||
i2c_master_write_byte(cmd, 0x00, true); // Dummy byte
|
||||
i2c_master_write_byte(cmd, 0x00, true); // Define start page address
|
||||
i2c_master_write_byte(cmd, 0x07, true); // Frame frequency
|
||||
i2c_master_write_byte(cmd, 0x07, true); // Define end page address
|
||||
i2c_master_write_byte(cmd, 0x00, true); //
|
||||
i2c_master_write_byte(cmd, 0xFF, true); //
|
||||
i2c_master_write_byte(cmd, OLED_CMD_ACTIVE_SCROLL, true); // 2F
|
||||
}
|
||||
|
||||
if (scroll == SCROLL_DOWN) {
|
||||
i2c_master_write_byte(cmd, OLED_CMD_CONTINUOUS_SCROLL, true); // 29
|
||||
i2c_master_write_byte(cmd, 0x00, true); // Dummy byte
|
||||
i2c_master_write_byte(cmd, 0x00, true); // Define start page address
|
||||
i2c_master_write_byte(cmd, 0x07, true); // Frame frequency
|
||||
//i2c_master_write_byte(cmd, 0x01, true); // Define end page address
|
||||
i2c_master_write_byte(cmd, 0x00, true); // Define end page address
|
||||
i2c_master_write_byte(cmd, 0x3F, true); // Vertical scrolling offset
|
||||
|
||||
i2c_master_write_byte(cmd, OLED_CMD_VERTICAL, true); // A3
|
||||
i2c_master_write_byte(cmd, 0x00, true);
|
||||
if (dev->_height == 64)
|
||||
//i2c_master_write_byte(cmd, 0x7F, true);
|
||||
i2c_master_write_byte(cmd, 0x40, true);
|
||||
if (dev->_height == 32)
|
||||
i2c_master_write_byte(cmd, 0x20, true);
|
||||
i2c_master_write_byte(cmd, OLED_CMD_ACTIVE_SCROLL, true); // 2F
|
||||
}
|
||||
|
||||
if (scroll == SCROLL_UP) {
|
||||
i2c_master_write_byte(cmd, OLED_CMD_CONTINUOUS_SCROLL, true); // 29
|
||||
i2c_master_write_byte(cmd, 0x00, true); // Dummy byte
|
||||
i2c_master_write_byte(cmd, 0x00, true); // Define start page address
|
||||
i2c_master_write_byte(cmd, 0x07, true); // Frame frequency
|
||||
//i2c_master_write_byte(cmd, 0x01, true); // Define end page address
|
||||
i2c_master_write_byte(cmd, 0x00, true); // Define end page address
|
||||
i2c_master_write_byte(cmd, 0x01, true); // Vertical scrolling offset
|
||||
|
||||
i2c_master_write_byte(cmd, OLED_CMD_VERTICAL, true); // A3
|
||||
i2c_master_write_byte(cmd, 0x00, true);
|
||||
if (dev->_height == 64)
|
||||
//i2c_master_write_byte(cmd, 0x7F, true);
|
||||
i2c_master_write_byte(cmd, 0x40, true);
|
||||
if (dev->_height == 32)
|
||||
i2c_master_write_byte(cmd, 0x20, true);
|
||||
i2c_master_write_byte(cmd, OLED_CMD_ACTIVE_SCROLL, true); // 2F
|
||||
}
|
||||
|
||||
if (scroll == SCROLL_STOP) {
|
||||
i2c_master_write_byte(cmd, OLED_CMD_DEACTIVE_SCROLL, true); // 2E
|
||||
}
|
||||
|
||||
i2c_master_stop(cmd);
|
||||
espRc = i2c_master_cmd_begin(I2C_NUM, cmd, 10/portTICK_PERIOD_MS);
|
||||
if (espRc == ESP_OK) {
|
||||
ESP_LOGD(tag, "Scroll command succeeded");
|
||||
} else {
|
||||
ESP_LOGE(tag, "Scroll command failed. code: 0x%.2X", espRc);
|
||||
}
|
||||
|
||||
i2c_cmd_link_delete(cmd);
|
||||
}
|
||||
|
254
components/ssd1306/ssd1306_spi.c
Normal file
254
components/ssd1306/ssd1306_spi.c
Normal file
@ -0,0 +1,254 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#include "driver/spi_master.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "ssd1306.h"
|
||||
|
||||
#define TAG "SSD1306"
|
||||
|
||||
#if CONFIG_SPI2_HOST
|
||||
#define HOST_ID SPI2_HOST
|
||||
#elif CONFIG_SPI3_HOST
|
||||
#define HOST_ID SPI3_HOST
|
||||
#else
|
||||
#define HOST_ID SPI2_HOST // If i2c is selected
|
||||
#endif
|
||||
|
||||
static const int SPI_Command_Mode = 0;
|
||||
static const int SPI_Data_Mode = 1;
|
||||
static const int SPI_Frequency = 1000000; // 1MHz
|
||||
|
||||
void spi_master_init(SSD1306_t * dev, int16_t GPIO_MOSI, int16_t GPIO_SCLK, int16_t GPIO_CS, int16_t GPIO_DC, int16_t GPIO_RESET)
|
||||
{
|
||||
esp_err_t ret;
|
||||
|
||||
//gpio_pad_select_gpio( GPIO_CS );
|
||||
gpio_reset_pin( GPIO_CS );
|
||||
gpio_set_direction( GPIO_CS, GPIO_MODE_OUTPUT );
|
||||
gpio_set_level( GPIO_CS, 0 );
|
||||
|
||||
//gpio_pad_select_gpio( GPIO_DC );
|
||||
gpio_reset_pin( GPIO_DC );
|
||||
gpio_set_direction( GPIO_DC, GPIO_MODE_OUTPUT );
|
||||
gpio_set_level( GPIO_DC, 0 );
|
||||
|
||||
if ( GPIO_RESET >= 0 ) {
|
||||
//gpio_pad_select_gpio( GPIO_RESET );
|
||||
gpio_reset_pin( GPIO_RESET );
|
||||
gpio_set_direction( GPIO_RESET, GPIO_MODE_OUTPUT );
|
||||
gpio_set_level( GPIO_RESET, 0 );
|
||||
vTaskDelay( pdMS_TO_TICKS( 100 ) );
|
||||
gpio_set_level( GPIO_RESET, 1 );
|
||||
}
|
||||
|
||||
spi_bus_config_t spi_bus_config = {
|
||||
.mosi_io_num = GPIO_MOSI,
|
||||
.miso_io_num = -1,
|
||||
.sclk_io_num = GPIO_SCLK,
|
||||
.quadwp_io_num = -1,
|
||||
.quadhd_io_num = -1,
|
||||
.max_transfer_sz = 0,
|
||||
.flags = 0
|
||||
};
|
||||
|
||||
ESP_LOGI(TAG, "SPI HOST_ID=%d", HOST_ID);
|
||||
ret = spi_bus_initialize( HOST_ID, &spi_bus_config, SPI_DMA_CH_AUTO );
|
||||
ESP_LOGI(TAG, "spi_bus_initialize=%d",ret);
|
||||
assert(ret==ESP_OK);
|
||||
|
||||
spi_device_interface_config_t devcfg;
|
||||
memset( &devcfg, 0, sizeof( spi_device_interface_config_t ) );
|
||||
devcfg.clock_speed_hz = SPI_Frequency;
|
||||
devcfg.spics_io_num = GPIO_CS;
|
||||
devcfg.queue_size = 1;
|
||||
|
||||
spi_device_handle_t handle;
|
||||
ret = spi_bus_add_device( HOST_ID, &devcfg, &handle);
|
||||
ESP_LOGI(TAG, "spi_bus_add_device=%d",ret);
|
||||
assert(ret==ESP_OK);
|
||||
dev->_dc = GPIO_DC;
|
||||
dev->_SPIHandle = handle;
|
||||
dev->_address = SPIAddress;
|
||||
dev->_flip = false;
|
||||
}
|
||||
|
||||
|
||||
bool spi_master_write_byte(spi_device_handle_t SPIHandle, const uint8_t* Data, size_t DataLength )
|
||||
{
|
||||
spi_transaction_t SPITransaction;
|
||||
|
||||
if ( DataLength > 0 ) {
|
||||
memset( &SPITransaction, 0, sizeof( spi_transaction_t ) );
|
||||
SPITransaction.length = DataLength * 8;
|
||||
SPITransaction.tx_buffer = Data;
|
||||
spi_device_transmit( SPIHandle, &SPITransaction );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool spi_master_write_command(SSD1306_t * dev, uint8_t Command )
|
||||
{
|
||||
static uint8_t CommandByte = 0;
|
||||
CommandByte = Command;
|
||||
gpio_set_level( dev->_dc, SPI_Command_Mode );
|
||||
return spi_master_write_byte( dev->_SPIHandle, &CommandByte, 1 );
|
||||
}
|
||||
|
||||
bool spi_master_write_data(SSD1306_t * dev, const uint8_t* Data, size_t DataLength )
|
||||
{
|
||||
gpio_set_level( dev->_dc, SPI_Data_Mode );
|
||||
return spi_master_write_byte( dev->_SPIHandle, Data, DataLength );
|
||||
}
|
||||
|
||||
|
||||
void spi_init(SSD1306_t * dev, int width, int height)
|
||||
{
|
||||
dev->_width = width;
|
||||
dev->_height = height;
|
||||
dev->_pages = 8;
|
||||
if (dev->_height == 32) dev->_pages = 4;
|
||||
|
||||
spi_master_write_command(dev, OLED_CMD_DISPLAY_OFF); // AE
|
||||
spi_master_write_command(dev, OLED_CMD_SET_MUX_RATIO); // A8
|
||||
if (dev->_height == 64) spi_master_write_command(dev, 0x3F);
|
||||
if (dev->_height == 32) spi_master_write_command(dev, 0x1F);
|
||||
spi_master_write_command(dev, OLED_CMD_SET_DISPLAY_OFFSET); // D3
|
||||
spi_master_write_command(dev, 0x00);
|
||||
spi_master_write_command(dev, OLED_CONTROL_BYTE_DATA_STREAM); // 40
|
||||
if (dev->_flip) {
|
||||
spi_master_write_command(dev, OLED_CMD_SET_SEGMENT_REMAP_0); // A0
|
||||
} else {
|
||||
spi_master_write_command(dev, OLED_CMD_SET_SEGMENT_REMAP_1); // A1
|
||||
}
|
||||
//spi_master_write_command(dev, OLED_CMD_SET_SEGMENT_REMAP); // A1
|
||||
spi_master_write_command(dev, OLED_CMD_SET_COM_SCAN_MODE); // C8
|
||||
spi_master_write_command(dev, OLED_CMD_SET_DISPLAY_CLK_DIV); // D5
|
||||
spi_master_write_command(dev, 0x80);
|
||||
spi_master_write_command(dev, OLED_CMD_SET_COM_PIN_MAP); // DA
|
||||
if (dev->_height == 64) spi_master_write_command(dev, 0x12);
|
||||
if (dev->_height == 32) spi_master_write_command(dev, 0x02);
|
||||
spi_master_write_command(dev, OLED_CMD_SET_CONTRAST); // 81
|
||||
spi_master_write_command(dev, 0xFF);
|
||||
spi_master_write_command(dev, OLED_CMD_DISPLAY_RAM); // A4
|
||||
spi_master_write_command(dev, OLED_CMD_SET_VCOMH_DESELCT); // DB
|
||||
spi_master_write_command(dev, 0x40);
|
||||
spi_master_write_command(dev, OLED_CMD_SET_MEMORY_ADDR_MODE); // 20
|
||||
//spi_master_write_command(dev, OLED_CMD_SET_HORI_ADDR_MODE); // 00
|
||||
spi_master_write_command(dev, OLED_CMD_SET_PAGE_ADDR_MODE); // 02
|
||||
// Set Lower Column Start Address for Page Addressing Mode
|
||||
spi_master_write_command(dev, 0x00);
|
||||
// Set Higher Column Start Address for Page Addressing Mode
|
||||
spi_master_write_command(dev, 0x10);
|
||||
spi_master_write_command(dev, OLED_CMD_SET_CHARGE_PUMP); // 8D
|
||||
spi_master_write_command(dev, 0x14);
|
||||
spi_master_write_command(dev, OLED_CMD_DEACTIVE_SCROLL); // 2E
|
||||
spi_master_write_command(dev, OLED_CMD_DISPLAY_NORMAL); // A6
|
||||
spi_master_write_command(dev, OLED_CMD_DISPLAY_ON); // AF
|
||||
}
|
||||
|
||||
|
||||
void spi_display_image(SSD1306_t * dev, int page, int seg, uint8_t * images, int width)
|
||||
{
|
||||
if (page >= dev->_pages) return;
|
||||
if (seg >= dev->_width) return;
|
||||
|
||||
int _seg = seg + CONFIG_OFFSETX;
|
||||
uint8_t columLow = _seg & 0x0F;
|
||||
uint8_t columHigh = (_seg >> 4) & 0x0F;
|
||||
|
||||
int _page = page;
|
||||
if (dev->_flip) {
|
||||
_page = (dev->_pages - page) - 1;
|
||||
}
|
||||
|
||||
// Set Lower Column Start Address for Page Addressing Mode
|
||||
spi_master_write_command(dev, (0x00 + columLow));
|
||||
// Set Higher Column Start Address for Page Addressing Mode
|
||||
spi_master_write_command(dev, (0x10 + columHigh));
|
||||
// Set Page Start Address for Page Addressing Mode
|
||||
spi_master_write_command(dev, 0xB0 | _page);
|
||||
|
||||
spi_master_write_data(dev, images, width);
|
||||
|
||||
}
|
||||
|
||||
void spi_contrast(SSD1306_t * dev, int contrast) {
|
||||
int _contrast = contrast;
|
||||
if (contrast < 0x0) _contrast = 0;
|
||||
if (contrast > 0xFF) _contrast = 0xFF;
|
||||
|
||||
spi_master_write_command(dev, OLED_CMD_SET_CONTRAST); // 81
|
||||
spi_master_write_command(dev, _contrast);
|
||||
}
|
||||
|
||||
void spi_hardware_scroll(SSD1306_t * dev, ssd1306_scroll_type_t scroll)
|
||||
{
|
||||
|
||||
if (scroll == SCROLL_RIGHT) {
|
||||
spi_master_write_command(dev, OLED_CMD_HORIZONTAL_RIGHT); // 26
|
||||
spi_master_write_command(dev, 0x00); // Dummy byte
|
||||
spi_master_write_command(dev, 0x00); // Define start page address
|
||||
spi_master_write_command(dev, 0x07); // Frame frequency
|
||||
spi_master_write_command(dev, 0x07); // Define end page address
|
||||
spi_master_write_command(dev, 0x00); //
|
||||
spi_master_write_command(dev, 0xFF); //
|
||||
spi_master_write_command(dev, OLED_CMD_ACTIVE_SCROLL); // 2F
|
||||
}
|
||||
|
||||
if (scroll == SCROLL_LEFT) {
|
||||
spi_master_write_command(dev, OLED_CMD_HORIZONTAL_LEFT); // 27
|
||||
spi_master_write_command(dev, 0x00); // Dummy byte
|
||||
spi_master_write_command(dev, 0x00); // Define start page address
|
||||
spi_master_write_command(dev, 0x07); // Frame frequency
|
||||
spi_master_write_command(dev, 0x07); // Define end page address
|
||||
spi_master_write_command(dev, 0x00); //
|
||||
spi_master_write_command(dev, 0xFF); //
|
||||
spi_master_write_command(dev, OLED_CMD_ACTIVE_SCROLL); // 2F
|
||||
}
|
||||
|
||||
if (scroll == SCROLL_DOWN) {
|
||||
spi_master_write_command(dev, OLED_CMD_CONTINUOUS_SCROLL); // 29
|
||||
spi_master_write_command(dev, 0x00); // Dummy byte
|
||||
spi_master_write_command(dev, 0x00); // Define start page address
|
||||
spi_master_write_command(dev, 0x07); // Frame frequency
|
||||
//spi_master_write_command(dev, 0x01); // Define end page address
|
||||
spi_master_write_command(dev, 0x00); // Define end page address
|
||||
spi_master_write_command(dev, 0x3F); // Vertical scrolling offset
|
||||
|
||||
spi_master_write_command(dev, OLED_CMD_VERTICAL); // A3
|
||||
spi_master_write_command(dev, 0x00);
|
||||
if (dev->_height == 64)
|
||||
spi_master_write_command(dev, 0x40);
|
||||
if (dev->_height == 32)
|
||||
spi_master_write_command(dev, 0x20);
|
||||
spi_master_write_command(dev, OLED_CMD_ACTIVE_SCROLL); // 2F
|
||||
}
|
||||
|
||||
if (scroll == SCROLL_UP) {
|
||||
spi_master_write_command(dev, OLED_CMD_CONTINUOUS_SCROLL); // 29
|
||||
spi_master_write_command(dev, 0x00); // Dummy byte
|
||||
spi_master_write_command(dev, 0x00); // Define start page address
|
||||
spi_master_write_command(dev, 0x07); // Frame frequency
|
||||
//spi_master_write_command(dev, 0x01); // Define end page address
|
||||
spi_master_write_command(dev, 0x00); // Define end page address
|
||||
spi_master_write_command(dev, 0x01); // Vertical scrolling offset
|
||||
|
||||
spi_master_write_command(dev, OLED_CMD_VERTICAL); // A3
|
||||
spi_master_write_command(dev, 0x00);
|
||||
if (dev->_height == 64)
|
||||
spi_master_write_command(dev, 0x40);
|
||||
if (dev->_height == 32)
|
||||
spi_master_write_command(dev, 0x20);
|
||||
spi_master_write_command(dev, OLED_CMD_ACTIVE_SCROLL); // 2F
|
||||
}
|
||||
|
||||
if (scroll == SCROLL_STOP) {
|
||||
spi_master_write_command(dev, OLED_CMD_DEACTIVE_SCROLL); // 2E
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user