Driver and example for SSD1306 128x64 I2C display (#254)

This commit is contained in:
urx 2016-10-28 16:08:37 +04:00 committed by sheinz
parent e71919410d
commit 5b12ba54dc
9 changed files with 644 additions and 0 deletions

View file

@ -0,0 +1,3 @@
PROGRAM=SSD1306_Example
EXTRA_COMPONENTS = extras/ssd1306 extras/i2c
include ../../common.mk

View file

@ -0,0 +1,3 @@
# I2C / SSD1306 OLED LCD Example
To run this example connect the SSD1306 OLED LCD and configure SDA/SCL pins in ssd1306_i2c.c file.

View file

@ -0,0 +1,89 @@
#define image_width 128
#define image_height 64
static unsigned char image_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xf8, 0xc3, 0xc7, 0x0f, 0x00, 0x1e, 0xfc, 0xf0, 0xe7, 0x30, 0xc0, 0x9f,
0x7f, 0xf0, 0x80, 0x0f, 0x18, 0x30, 0xc4, 0x18, 0x80, 0x61, 0x8c, 0x31,
0xe0, 0x30, 0xc0, 0x38, 0x0c, 0x0c, 0x63, 0x08, 0x18, 0x30, 0xc0, 0x30,
0x80, 0x61, 0x0c, 0x33, 0xe0, 0x31, 0xc0, 0x30, 0x0c, 0x0c, 0x63, 0x00,
0x18, 0xf0, 0xc0, 0x30, 0xc0, 0xc0, 0x0c, 0x33, 0x60, 0x31, 0xc0, 0x30,
0x0c, 0x06, 0xe6, 0x01, 0xf8, 0xe3, 0xc7, 0x30, 0xc0, 0xc0, 0x0c, 0xf3,
0x67, 0x33, 0xc0, 0x38, 0x0c, 0x06, 0xc6, 0x0f, 0x18, 0x80, 0xcf, 0x18,
0xcf, 0xc0, 0x8c, 0x31, 0x60, 0x36, 0xcf, 0x1f, 0x0c, 0x06, 0x06, 0x1f,
0x18, 0x00, 0xce, 0x0f, 0xcf, 0xc0, 0xfc, 0x30, 0x60, 0x36, 0xcf, 0x18,
0x0c, 0x06, 0x06, 0x1c, 0x18, 0x00, 0xcc, 0x00, 0x80, 0x61, 0x0c, 0x30,
0x60, 0x3c, 0xc0, 0x30, 0x0c, 0x0c, 0x03, 0x18, 0x18, 0x10, 0xcc, 0x00,
0x80, 0x61, 0x0c, 0x30, 0x60, 0x38, 0xc0, 0x30, 0x0c, 0x0c, 0x23, 0x18,
0xf8, 0xf3, 0xc3, 0x00, 0x00, 0x1e, 0x0c, 0xf0, 0x67, 0x38, 0xc0, 0x60,
0x0c, 0xf0, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x1f, 0xfc, 0x01, 0x1c, 0xf8, 0x81,
0x0f, 0x78, 0x00, 0x0c, 0x80, 0x1f, 0xfe, 0x00, 0xf0, 0x87, 0x3f, 0xfc,
0x07, 0x1f, 0xfc, 0xc3, 0x1f, 0xfc, 0x00, 0x0c, 0xe0, 0x3f, 0xfe, 0x03,
0x38, 0xc4, 0x21, 0x0c, 0x0e, 0x1b, 0x04, 0xc7, 0x18, 0x8e, 0x00, 0x0c,
0x70, 0x20, 0x06, 0x07, 0x18, 0xc0, 0x00, 0x0c, 0x0c, 0x18, 0x00, 0x66,
0x30, 0x07, 0x00, 0x0c, 0x30, 0x00, 0x06, 0x06, 0x18, 0xc0, 0x00, 0x0c,
0x18, 0x18, 0x00, 0x67, 0x30, 0x03, 0x00, 0x0c, 0x18, 0x00, 0x06, 0x0c,
0xf0, 0x81, 0x0f, 0x0c, 0x18, 0x18, 0xf0, 0x61, 0x30, 0x7b, 0x00, 0x0c,
0x18, 0x00, 0x06, 0x0c, 0xe0, 0x07, 0x3f, 0x0c, 0x18, 0x18, 0xf0, 0x63,
0x30, 0xff, 0x00, 0x0c, 0x18, 0x00, 0x06, 0x0c, 0x00, 0x0e, 0x70, 0x0c,
0x18, 0x18, 0x00, 0x67, 0x30, 0xc7, 0x01, 0x0c, 0x18, 0x00, 0x06, 0x0c,
0x00, 0x0c, 0x60, 0x0c, 0x18, 0x18, 0x00, 0x66, 0x30, 0x83, 0x01, 0x0c,
0x18, 0x00, 0x06, 0x0c, 0x00, 0x0c, 0x60, 0x0c, 0x0c, 0x18, 0x00, 0x66,
0x30, 0x83, 0x01, 0x0c, 0x30, 0x00, 0x06, 0x06, 0x08, 0x4e, 0x70, 0x0c,
0x0e, 0x18, 0x04, 0xc7, 0x18, 0xc6, 0x01, 0x0c, 0x70, 0x20, 0x06, 0x07,
0xf8, 0xc7, 0x3f, 0xfc, 0x07, 0xff, 0xfc, 0xc3, 0x1f, 0xfe, 0x00, 0xfc,
0xe3, 0x3f, 0xfe, 0x03, 0xf0, 0x83, 0x1f, 0xfc, 0x01, 0xff, 0xf8, 0x81,
0x0f, 0x78, 0x00, 0xfc, 0x83, 0x1f, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x18,
0x18, 0x7e, 0xc0, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
0x01, 0x00, 0x00, 0x18, 0x18, 0xfe, 0x80, 0x61, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x18, 0x18, 0xc6, 0x81, 0x33,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3d, 0x06, 0x06, 0x18,
0x18, 0x86, 0x01, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
0x7f, 0x06, 0x06, 0x18, 0x18, 0x86, 0x01, 0x1e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x80, 0xe3, 0x0c, 0x03, 0x18, 0x18, 0xc6, 0x01, 0x0e,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc1, 0x0c, 0x03, 0x18,
0x18, 0xfe, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
0xc1, 0x98, 0x01, 0x18, 0x18, 0x7e, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x80, 0xc1, 0x98, 0x01, 0x18, 0x18, 0xc6, 0x00, 0x1b,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc1, 0xf0, 0x00, 0x18,
0x18, 0x86, 0x81, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
0xe3, 0xf0, 0x00, 0x30, 0x0c, 0x86, 0x81, 0x71, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x80, 0x7f, 0x60, 0x00, 0xf0, 0x0f, 0x06, 0xc3, 0x60,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3d, 0x60, 0x00, 0xc0,
0x03, 0x06, 0xe7, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00 };

View file

@ -0,0 +1,65 @@
#include "espressif/esp_common.h"
#include "esp/uart.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include <string.h>
#include "i2c/i2c.h"
#include "ssd1306/ssd1306.h"
#include "image.xbm"
/* Change this according to you schematics */
#define SCL_PIN GPIO_ID_PIN((14))
#define SDA_PIN GPIO_ID_PIN((12))
/* Local frame buffer */
static uint8_t buffer[SSD1306_ROWS * SSD1306_COLS / 8];
static void ssd1306_task(void *pvParameters)
{
printf("%s: Started user interface task\n", __FUNCTION__);
vTaskDelay(1000/portTICK_RATE_MS);
if (ssd1306_load_xbm(image_bits, buffer))
goto error_loop;
ssd1306_set_whole_display_lighting(false);
while (1) {
vTaskDelay(2000 / portTICK_RATE_MS);
printf("%s: steel alive\n", __FUNCTION__);
}
error_loop:
printf("%s: error while loading framebuffer into SSD1306\n", __func__);
for(;;){
vTaskDelay(2000 / portTICK_RATE_MS);
printf("%s: error loop\n", __FUNCTION__);
}
}
void user_init(void)
{
// Setup HW
uart_set_baud(0, 115200);
printf("SDK version:%s\n", sdk_system_get_sdk_version());
i2c_init(SCL_PIN, SDA_PIN);
if (ssd1306_init()){
for (;;) {
printf("%s: failed to init SSD1306 lcd\n", __func__);
vTaskDelay(1000/portTICK_RATE_MS);
}
}
ssd1306_set_whole_display_lighting(true);
vTaskDelay(1000/portTICK_RATE_MS);
// Create user interface task
xTaskCreate(ssd1306_task, "ssd1306_task", 256, NULL, 2, NULL);
}

22
extras/ssd1306/LICENSE Normal file
View file

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015 Frank Bargstedt
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

27
extras/ssd1306/README.md Normal file
View file

@ -0,0 +1,27 @@
# Driver for I2C SSD1306 128x64 OLED LCD
This driver is written for usage with the ESP8266 and FreeRTOS ([esp-open-rtos](https://github.com/SuperHouse/esp-open-rtos)).
### Usage
Before using the SSD1306 LCD module, the function `i2c_init(SCL_PIN, SDA_PIN)` needs to be called to setup the I2C interface and then you must call ssd1306_init().
#### Example
```
#define SCL_PIN GPIO_ID_PIN(0)
#define SDA_PIN GPIO_ID_PIN(2)
...
i2c_init(SCL_PIN, SDA_PIN);
if (ssd1306_init()) {
// An error occured, while performing SSD1306 init init (E.g device not found etc.)
}
// rest of the code
```

View file

@ -0,0 +1,9 @@
# Component makefile for extras/ssd1306
# expected anyone using ssd1306 driver includes it as 'ssd1306/ssd1306.h'
INC_DIRS += $(ssd1306_ROOT)..
# args for passing into compile rule generation
ssd1306_SRC_DIR = $(ssd1306_ROOT)
$(eval $(call component_compile_rules,ssd1306))

376
extras/ssd1306/ssd1306.c Normal file
View file

@ -0,0 +1,376 @@
#include <stdio.h>
#include <i2c/i2c.h>
#include <FreeRTOS.h>
#include <task.h>
#include "ssd1306.h"
/* SSD1306 commands */
#define SSD1306_SET_MEM_ADDR_MODE (0x20)
#define SSD1306_ADDR_MODE_HORIZ (0x0)
#define SSD1306_ADDR_MODE_VERT (0x1)
#define SSD1306_ADDR_MODE_PAGE (0x2)
#define SSD1306_SET_COL_ADDR (0x21)
#define SSD1306_SET_PAGE_ADDR (0x22)
#define SSD1306_SET_DISP_START_LINE (0x40)
#define SSD1306_SET_CONTRAST (0x81)
#define SSD1306_SET_SEGMENT_REMAP0 (0xA0)
#define SSD1306_SET_SEGMENT_REMAP1 (0xA1)
#define SSD1306_SET_ENTIRE_DISP_ON (0xA5)
#define SSD1306_SET_ENTIRE_DISP_OFF (0xA4)
#define SSD1306_SET_INVERSION_OFF (0xA6)
#define SSD1306_SET_INVERSION_ON (0xA7)
#define SSD1306_SET_MUX_RATIO (0xA8)
#define SSD1306_MUX_RATIO_MASK (0x3F)
#define SSD1306_SET_DISPLAY_OFF (0xAE)
#define SSD1306_SET_DISPLAY_ON (0xAF)
#define SSD1306_SET_SCAN_DIR_FWD (0xC0)
#define SSD1306_SET_SCAN_DIR_BWD (0xC8)
#define SSD1306_SET_DISPLAY_OFFSET (0xD3)
#define SSD1306_SET_OSC_FREQ (0xD5)
#define SSD1306_SET_PRE_CHRG_PER (0xD9)
#define SSD1306_SET_COM_PINS_HW_CFG (0xDA)
#define SSD1306_COM_PINS_HW_CFG_MASK (0x32)
#define SSD1306_SEQ_COM_PINS_CFG (0x02)
#define SSD1306_ALT_COM_PINS_CFG (0x12)
#define SSD1306_COM_LR_REMAP_OFF (0x02)
#define SSD1306_COM_LR_REMAP_ON (0x22)
#define SSD1306_SET_DESEL_LVL (0xDB)
#define SSD1306_SET_NOP (0xE3)
#define SSD1306_SET_CHARGE_PUMP (0x8D)
#define SSD1306_CHARGE_PUMP_EN (0x14)
#define SSD1306_CHARGE_PUMP_DIS (0x10)
#ifdef SSD1306_DEBUG
#define debug(fmt, ...) printf("%s" fmt "\n", "SSD1306", ## __VA_ARGS__);
#else
#define debug(fmt, ...)
#endif
/* Issue a command to SSD1306 device
* format such follows:
* |S|Slave Address|W|ACK|0x00|Command|Ack|P|
*
* in case of two-bytes command here will be Data byte
* right after command byte.
*/
int ssd1306_command(uint8_t cmd)
{
i2c_start();
if (!i2c_write(SSD1306_I2C_ADDR << 1)) {
debug("Error while xmitting I2C slave address\n");
i2c_stop();
return -EIO;
}
if (!i2c_write(0x00)) {
debug("Error while xmitting transmission type\n");
i2c_stop();
return -EIO;
}
if (!i2c_write(cmd)) {
debug("Error while xmitting command: 0x%02X\n", cmd);
i2c_stop();
return -EIO;
}
i2c_stop();
return 0;
}
/* Perform default init routine according
* to SSD1306 datasheet from adafruit.com */
int ssd1306_init()
{
if (!ssd1306_display_on(false) &&
!ssd1306_set_osc_freq(0x80) &&
!ssd1306_set_mux_ratio(SSD1306_ROWS-1) &&
!ssd1306_set_display_offset(0x0) &&
!ssd1306_set_display_start_line(0x0) &&
!ssd1306_set_charge_pump_enabled(true) &&
!ssd1306_set_mem_addr_mode(SSD1306_ADDR_MODE_HORIZ) &&
!ssd1306_set_segment_remapping_enabled(false) &&
!ssd1306_set_scan_direction_fwd(true) &&
!ssd1306_set_com_pin_hw_config(SSD1306_ALT_COM_PINS_CFG) &&
!ssd1306_set_contrast(0x9f) &&
!ssd1306_set_precharge_period(0xf1) &&
!ssd1306_set_deseltct_lvl(0x40) &&
!ssd1306_set_whole_display_lighting(true) &&
!ssd1306_set_inversion(false) &&
!ssd1306_display_on(true)) {
return 0;
}
return -EIO;
}
/*
* frame buffer of SSD1306 consists of 8 pages of 128 bits each
*
*/
int ssd1306_load_frame_buffer(uint8_t buf[], uint16_t len)
{
uint16_t i;
uint8_t j;
ssd1306_set_column_addr(0, 127);
ssd1306_set_page_addr(0, 7);
for (i=0; i<len; i++) {
i2c_start();
if (!i2c_write(SSD1306_I2C_ADDR << 1)) {
debug("Error while xmitting I2C slave address\n");
i2c_stop();
return -EIO;
}
if (!i2c_write(0x40)) {
debug("Error while xmitting transmission type\n");
i2c_stop();
return -EIO;
}
for (j=0;j<16;j++) {
if (!i2c_write(buf[i])) {
debug("Error while writing to GDDRAM\n");
i2c_stop();
return -EIO;
}
i++;
}
i--;
i2c_stop();
taskYIELD();
}
return 0;
}
int ssd1306_clear_screen()
{
uint16_t i = 0;
uint8_t j = 0;
ssd1306_set_column_addr(0, 127);
ssd1306_set_page_addr(0, 7);
while (i < (SSD1306_ROWS*SSD1306_COLS/8)) {
i2c_start();
if (!i2c_write(SSD1306_I2C_ADDR << 1)) {
debug("Error while xmitting I2C slave address\n");
i2c_stop();
return -EIO;
}
if (!i2c_write(0x40)) {
debug("Error while xmitting transmission type\n");
i2c_stop();
return -EIO;
}
/* write 16 bytes of data and then give resources to another task */
while (j < 16) {
if (!i2c_write(0x0)) {
debug("Error while writing to GDDRAM\n");
i2c_stop();
return -EIO;
}
i++;
j++;
}
i--;
j = 0;
i2c_stop();
taskYIELD();
}
return 0;
}
int ssd1306_display_on(bool on)
{
if (on)
return ssd1306_command(SSD1306_SET_DISPLAY_ON);
return ssd1306_command(SSD1306_SET_DISPLAY_OFF);
}
int ssd1306_set_display_start_line(uint8_t start)
{
return ssd1306_command(SSD1306_SET_DISP_START_LINE | start);
}
int ssd1306_set_display_offset(uint8_t offset)
{
int err = 0;
if ((err = ssd1306_command(SSD1306_SET_DISPLAY_OFFSET)))
return err;
return ssd1306_command(offset);
}
int ssd1306_set_charge_pump_enabled(bool enabled)
{
int err = 0;
if ((err = ssd1306_command(SSD1306_SET_CHARGE_PUMP)))
return err;
if (enabled)
return ssd1306_command(SSD1306_CHARGE_PUMP_EN);
return ssd1306_command(SSD1306_CHARGE_PUMP_DIS);
}
int ssd1306_set_mem_addr_mode(uint8_t mode)
{
if (mode >= 0x3)
return -EINVAL;
int err = 0;
if ((err = ssd1306_command(SSD1306_SET_MEM_ADDR_MODE)))
return err;
return ssd1306_command(mode);
}
int ssd1306_set_segment_remapping_enabled(bool on)
{
if (on)
return ssd1306_command(SSD1306_SET_SEGMENT_REMAP1);
return ssd1306_command(SSD1306_SET_SEGMENT_REMAP0);
}
int ssd1306_set_scan_direction_fwd(bool fwd)
{
if (fwd)
return ssd1306_command(SSD1306_SET_SCAN_DIR_FWD);
return ssd1306_command(SSD1306_SET_SCAN_DIR_BWD);
}
int ssd1306_set_com_pin_hw_config(uint8_t config)
{
int err = 0;
if ((err = ssd1306_command(SSD1306_SET_COM_PINS_HW_CFG)))
return err;
return ssd1306_command(config & SSD1306_COM_PINS_HW_CFG_MASK);
}
int ssd1306_set_contrast(uint8_t contrast)
{
int err = 0;
if ((err = ssd1306_command(SSD1306_SET_CONTRAST)))
return err;
return ssd1306_command(contrast);
}
int ssd1306_set_inversion(bool on)
{
if (on)
return ssd1306_command(SSD1306_SET_INVERSION_ON);
return ssd1306_command(SSD1306_SET_INVERSION_OFF);
}
int ssd1306_set_osc_freq(uint8_t osc_freq)
{
int err = 0;
if ((err = ssd1306_command(SSD1306_SET_OSC_FREQ)))
return err;
return ssd1306_command(osc_freq);
}
int ssd1306_set_mux_ratio(uint8_t ratio)
{
if (ratio < 15)
return -EINVAL;
int err = 0;
if ((err = ssd1306_command(SSD1306_SET_MUX_RATIO)))
return err;
return ssd1306_command(ratio);
}
int ssd1306_set_column_addr(uint8_t start, uint8_t stop)
{
int err = 0;
if ((err = ssd1306_command(SSD1306_SET_COL_ADDR)))
return err;
if ((err = ssd1306_command(start)))
return err;
return ssd1306_command(stop);
}
int ssd1306_set_page_addr(uint8_t start, uint8_t stop)
{
int err = 0;
if ((err = ssd1306_command(SSD1306_SET_PAGE_ADDR)))
return err;
if ((err = ssd1306_command(start)))
return err;
return ssd1306_command(stop);
}
int ssd1306_set_precharge_period(uint8_t prchrg)
{
int err = 0;
if ((err = ssd1306_command(SSD1306_SET_PRE_CHRG_PER)))
return err;
return ssd1306_command(prchrg);
}
int ssd1306_set_deseltct_lvl(uint8_t lvl)
{
int err = 0;
if ((err = ssd1306_command(SSD1306_SET_DESEL_LVL)))
return err;
return ssd1306_command(lvl);
}
int ssd1306_set_whole_display_lighting(bool light)
{
if (light)
return ssd1306_command(SSD1306_SET_ENTIRE_DISP_ON);
return ssd1306_command(SSD1306_SET_ENTIRE_DISP_OFF);
}
/* one byte of xbm - 8 dots in line of picture source
* one byte of fb - 8 rows for 1 column of screen
*/
int ssd1306_load_xbm(uint8_t *xbm, uint8_t *fb)
{
uint8_t bit = 0;
int row = 0;
int column = 0;
for (row = 0; row < SSD1306_ROWS; row ++) {
for (column = 0; column < SSD1306_COLS/8; column++) {
uint16_t xbm_offset = row * 16 + column;
for (bit = 0; bit < 8; bit++) {
if (*(xbm + xbm_offset) & 1 << bit) {
*(fb + SSD1306_COLS*(row/8)+column*8+bit) |= 1 << row%8;
}
}
}
}
return ssd1306_load_frame_buffer(fb, SSD1306_ROWS*SSD1306_COLS/8);
}

50
extras/ssd1306/ssd1306.h Normal file
View file

@ -0,0 +1,50 @@
#ifndef _SSD1306__H_
#define _SSD1306__H_
#include <stdint.h>
#include <stdbool.h>
#include <errno.h>
// shifted
#define SSD1306_I2C_ADDR (0x3C)
#define SSD1306_ROWS (64)
#define SSD1306_COLS (128)
/* Issue single command on SSD1306 */
int ssd1306_command(uint8_t cmd);
/* Default init for SSD1306 */
int ssd1306_init();
/* Load picture in xbm format into SSD1306 RAM
* xbm - pointer to xbm picture array
* fb - pointer fo local buffer for storing converted xbm image
*/
int ssd1306_load_xbm(uint8_t *xbm, uint8_t *fb);
/* Load local framebuffer into SSD1306 RAM */
int ssd1306_load_frame_buffer(uint8_t buf[], uint16_t len);
/* Clears SSD1306 ram */
int ssd1306_clear_screen();
int ssd1306_display_on(bool on);
int ssd1306_set_display_start_line(uint8_t start);
int ssd1306_set_display_offset(uint8_t offset);
int ssd1306_set_charge_pump_enabled(bool enabled);
int ssd1306_set_mem_addr_mode(uint8_t mode);
int ssd1306_set_segment_remapping_enabled(bool on);
int ssd1306_set_scan_direction_fwd(bool fwd);
int ssd1306_set_com_pin_hw_config(uint8_t config);
int ssd1306_set_contrast(uint8_t contrast);
int ssd1306_set_inversion(bool on);
int ssd1306_set_osc_freq(uint8_t osc_freq);
int ssd1306_set_mux_ratio(uint8_t ratio);
int ssd1306_set_column_addr(uint8_t start, uint8_t stop);
int ssd1306_set_page_addr(uint8_t start, uint8_t stop);
int ssd1306_set_precharge_period(uint8_t prchrg);
int ssd1306_set_deseltct_lvl(uint8_t lvl);
int ssd1306_set_whole_display_lighting(bool light);
#endif // _SSD1306__H_