You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
787 lines
22 KiB
787 lines
22 KiB
/*********************************************************************
|
|
SSD1306 I2C Library for Raspberry Pi.
|
|
Based on Adafruit SSD1306 Arduino library. Some functions came from Adafruit GFX lib
|
|
|
|
Modified by Ilia Penev
|
|
Tested on Raspberry Pi 2 with 0.96 Yellow/Blue OLED
|
|
*********************************************************************/
|
|
|
|
/*********************************************************************
|
|
This is a library for our Monochrome OLEDs based on SSD1306 drivers
|
|
|
|
Pick one up today in the adafruit shop!
|
|
------> http://www.adafruit.com/category/63_98
|
|
|
|
These displays use SPI to communicate, 4 or 5 pins are required to
|
|
interface
|
|
|
|
Adafruit invests time and resources providing this open source code,
|
|
please support Adafruit and open-source hardware by purchasing
|
|
products from Adafruit!
|
|
|
|
Written by Limor Fried/Ladyada for Adafruit Industries.
|
|
BSD license, check license.txt for more information
|
|
All text above, and the splash screen below must be included in any redistribution
|
|
*********************************************************************/
|
|
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
|
|
#include "ssd1306_i2c.h"
|
|
#include "oled_fonts.h"
|
|
#include "lcd_oled.h"
|
|
|
|
#define true 1
|
|
#define false 0
|
|
|
|
#define rotation 0
|
|
|
|
int8_t cursor_y = 0;
|
|
int8_t cursor_x = 0;
|
|
|
|
// the memory buffer for the LCD. Displays Adafruit logo
|
|
uint8_t buffer[SSD1306_LCDWIDTH * SSD1306_LCDHEIGHT / 8] = {
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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,
|
|
0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x80, 0x80, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
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, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xF8, 0xE0,
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x00, 0xFF,
|
|
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00,
|
|
0x80, 0x80, 0x00, 0x00,
|
|
0x80, 0xFF, 0xFF, 0x80, 0x80, 0x00, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80,
|
|
0x80, 0x00, 0x80, 0x80,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x8C, 0x8E, 0x84,
|
|
0x00, 0x00, 0x80, 0xF8,
|
|
0xF8, 0xF8, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
|
|
0xE0, 0xE0, 0xC0, 0x80,
|
|
0x00, 0xE0, 0xFC, 0xFE, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE,
|
|
0xFF, 0xC7, 0x01, 0x01,
|
|
0x01, 0x01, 0x83, 0xFF, 0xFF, 0x00, 0x00, 0x7C, 0xFE, 0xC7, 0x01, 0x01,
|
|
0x01, 0x01, 0x83, 0xFF,
|
|
0xFF, 0xFF, 0x00, 0x38, 0xFE, 0xC7, 0x83, 0x01, 0x01, 0x01, 0x83, 0xC7,
|
|
0xFF, 0xFF, 0x00, 0x00,
|
|
0x01, 0xFF, 0xFF, 0x01, 0x01, 0x00, 0xFF, 0xFF, 0x07, 0x01, 0x01, 0x01,
|
|
0x00, 0x00, 0x7F, 0xFF,
|
|
0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
|
|
0x00, 0x00, 0x01, 0xFF,
|
|
0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x03, 0x0F, 0x3F, 0x7F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xE7, 0xC7, 0xC7, 0x8F,
|
|
0x8F, 0x9F, 0xBF, 0xFF, 0xFF, 0xC3, 0xC0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFC, 0xFC, 0xFC,
|
|
0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xF8, 0xF8, 0xF0, 0xF0, 0xE0, 0xC0, 0x00,
|
|
0x01, 0x03, 0x03, 0x03,
|
|
0x03, 0x03, 0x01, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03,
|
|
0x03, 0x03, 0x01, 0x01,
|
|
0x03, 0x01, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x03, 0x03, 0x01, 0x01,
|
|
0x03, 0x03, 0x00, 0x00,
|
|
0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x01,
|
|
0x03, 0x03, 0x03, 0x03, 0x03, 0x01, 0x00, 0x00, 0x00, 0x01, 0x03, 0x01,
|
|
0x00, 0x00, 0x00, 0x03,
|
|
0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0x3F, 0x1F, 0x0F,
|
|
0x87, 0xC7, 0xF7, 0xFF, 0xFF, 0x1F, 0x1F, 0x3D, 0xFC, 0xF8, 0xF8, 0xF8,
|
|
0xF8, 0x7C, 0x7D, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x0F, 0x07, 0x00,
|
|
0x30, 0x30, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0xE0, 0xC0, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30,
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0xC0, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0x7F, 0x7F, 0x3F, 0x1F,
|
|
0x0F, 0x07, 0x1F, 0x7F, 0xFF, 0xFF, 0xF8, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFE, 0xF8, 0xE0,
|
|
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0xFE, 0xFE, 0x00, 0x00,
|
|
0x00, 0xFC, 0xFE, 0xFC, 0x0C, 0x06, 0x06, 0x0E, 0xFC, 0xF8, 0x00, 0x00,
|
|
0xF0, 0xF8, 0x1C, 0x0E,
|
|
0x06, 0x06, 0x06, 0x0C, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFE, 0xFE, 0x00,
|
|
0x00, 0x00, 0x00, 0xFC,
|
|
0xFE, 0xFC, 0x00, 0x18, 0x3C, 0x7E, 0x66, 0xE6, 0xCE, 0x84, 0x00, 0x00,
|
|
0x06, 0xFF, 0xFF, 0x06,
|
|
0x06, 0xFC, 0xFE, 0xFC, 0x0C, 0x06, 0x06, 0x06, 0x00, 0x00, 0xFE, 0xFE,
|
|
0x00, 0x00, 0xC0, 0xF8,
|
|
0xFC, 0x4E, 0x46, 0x46, 0x46, 0x4E, 0x7C, 0x78, 0x40, 0x18, 0x3C, 0x76,
|
|
0xE6, 0xCE, 0xCC, 0x80,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x01, 0x07, 0x0F, 0x1F, 0x1F, 0x3F, 0x3F, 0x3F,
|
|
0x3F, 0x1F, 0x0F, 0x03,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x0F, 0x0F, 0x00, 0x00,
|
|
0x00, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00,
|
|
0x03, 0x07, 0x0E, 0x0C,
|
|
0x18, 0x18, 0x0C, 0x06, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x01, 0x0F, 0x0E,
|
|
0x0C, 0x18, 0x0C, 0x0F,
|
|
0x07, 0x01, 0x00, 0x04, 0x0E, 0x0C, 0x18, 0x0C, 0x0F, 0x07, 0x00, 0x00,
|
|
0x00, 0x0F, 0x0F, 0x00,
|
|
0x00, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F,
|
|
0x00, 0x00, 0x00, 0x07,
|
|
0x07, 0x0C, 0x0C, 0x18, 0x1C, 0x0C, 0x06, 0x06, 0x00, 0x04, 0x0E, 0x0C,
|
|
0x18, 0x0C, 0x0F, 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
|
|
};
|
|
|
|
int8_t _vccstate;
|
|
int16_t i2cd;
|
|
|
|
#define ssd1306_swap(a, b) { int16_t t = a; a = b; b = t; }
|
|
|
|
|
|
//Section : 10.1.12 Set Display ON/OFF (AEh/AFh) | Page 37
|
|
void ssd1306_i2c_set_display_off(i2c_t *i2c_dev)
|
|
{
|
|
ssd1306_i2c_command(i2c_dev,SSD1306_DISPLAYOFF);
|
|
}
|
|
|
|
//Section : 10.1.12 Set Display ON/OFF (AEh/AFh) | Page 37
|
|
void ssd1306_i2c_set_display_on(i2c_t *i2c_dev)
|
|
{
|
|
ssd1306_i2c_command(i2c_dev,SSD1306_DISPLAYON);
|
|
}
|
|
|
|
// TODO: Find a ferq Calculator
|
|
// Section : 10.1.16 Set Display Clock Divide Ratio/ Oscillator Frequency (D5h) | Page : 40
|
|
void ssd1306_i2c_set_display_clkDiv_oscFreq(i2c_t *i2c_dev, uint8_t clockDivider, uint8_t oscillatorFreq)
|
|
{
|
|
|
|
uint8_t value = 0;
|
|
|
|
if(oscillatorFreq <= 15)
|
|
{
|
|
if(clockDivider <= 16)
|
|
{
|
|
value = (oscillatorFreq << 4) | clockDivider;
|
|
}
|
|
}
|
|
|
|
ssd1306_i2c_command(i2c_dev,SSD1306_SETDISPLAYCLOCKDIV); // 0xD5
|
|
ssd1306_i2c_command(i2c_dev,value); // the suggested ratio 0x80
|
|
}
|
|
|
|
// Section : 10.1.11 Set Multiplex Ratio (A8h) | Page : 37
|
|
void ssd1306_i2c_set_multiplex_ratio(i2c_t *i2c_dev, uint8_t ratio)
|
|
{
|
|
ssd1306_i2c_command(i2c_dev,SSD1306_SETMULTIPLEX); // 0xA8
|
|
ssd1306_i2c_command(i2c_dev,ratio);
|
|
}
|
|
|
|
// Section : 10.1.15 Set Display Offset (D3h) | Page : 37
|
|
void ssd1306_i2c_set_display_offset(i2c_t *i2c_dev, uint8_t offset)
|
|
{
|
|
ssd1306_i2c_command(i2c_dev,SSD1306_SETDISPLAYOFFSET); // 0xD3
|
|
ssd1306_i2c_command(i2c_dev,offset);
|
|
}
|
|
// Section : 10.1.13 Set Page Start Address for Page Addressing Mode (B0h~B7h) | Page : 37
|
|
void ssd1306_i2c_set_display_start_line(i2c_t *i2c_dev, uint8_t start)
|
|
{
|
|
if(start <= 7)
|
|
{
|
|
ssd1306_i2c_command(i2c_dev,SSD1306_SETSTARTLINE | start);
|
|
}
|
|
}
|
|
|
|
// TODO : Some things are not clear What does 0x10 do ?
|
|
// Section : 2.1 Command Table for Charge Bump Setting | Page : 60
|
|
void ssd1306_i2c_set_chage_pump(i2c_t *i2c_dev, uint8_t voltageSource)
|
|
{
|
|
ssd1306_i2c_command(i2c_dev,SSD1306_CHARGEPUMP); // 0x8D
|
|
if (voltageSource == SSD1306_EXTERNALVCC) {
|
|
ssd1306_i2c_command(i2c_dev,0x10);
|
|
} else {
|
|
ssd1306_i2c_command(i2c_dev,SSD1306_ENABLE_CHAGE_PUMP);
|
|
}
|
|
}
|
|
|
|
// Section :10.1.3 Set Memory Addressing Mode (20h) | Page : 34
|
|
void ssd1306_i2c_set_memory_addressing_mode(i2c_t *i2c_dev, uint8_t mode)
|
|
{
|
|
ssd1306_i2c_command(i2c_dev,SSD1306_MEMORYMODE);
|
|
ssd1306_i2c_command(i2c_dev,mode);
|
|
}
|
|
|
|
// TODO : Not very clear what this functionality does :S
|
|
// Section : 10.1.8 Set Segment Re-map (A0h/A1h)
|
|
void ssd1306_i2c_set_segment_remap(i2c_t *i2c_dev, uint8_t enable)
|
|
{
|
|
if(enable)
|
|
{
|
|
ssd1306_i2c_command(i2c_dev,SSD1306_SEGREMAP | 0x1);
|
|
}
|
|
else
|
|
{
|
|
ssd1306_i2c_command(i2c_dev,SSD1306_SEGREMAP | 0x0);
|
|
}
|
|
}
|
|
// Section : 10.1.14 Set COM Output Scan Direction (C0h/C8h) | Page 37
|
|
void ssd1306_i2c_set_com_scan_direction(i2c_t *i2c_dev, uint8_t incremental)
|
|
{
|
|
if(incremental)
|
|
{
|
|
ssd1306_i2c_command(i2c_dev,SSD1306_COMSCANINC);
|
|
}
|
|
else
|
|
{
|
|
ssd1306_i2c_command(i2c_dev,SSD1306_COMSCANDEC);
|
|
}
|
|
}
|
|
|
|
// Section : 10.1.18 Set COM Pins Hardware Configuration (DAh) | Page : 40
|
|
void ssd1306_i2c_set_com_pins(i2c_t *i2c_dev, uint8_t alignment)
|
|
{
|
|
ssd1306_i2c_command(i2c_dev,SSD1306_SETCOMPINS);
|
|
ssd1306_i2c_command(i2c_dev,alignment);
|
|
}
|
|
|
|
void ssd1306_i2c_set_contrast(i2c_t *i2c_dev, uint8_t contrast)
|
|
{
|
|
ssd1306_i2c_command(i2c_dev,SSD1306_SETCONTRAST); // 0x81
|
|
ssd1306_i2c_command(i2c_dev,contrast);
|
|
}
|
|
|
|
void ssd1306_i2c_set_prechage_period(i2c_t *i2c_dev, uint8_t period)
|
|
{
|
|
ssd1306_i2c_command(i2c_dev,SSD1306_SETPRECHARGE); // 0xd9
|
|
ssd1306_i2c_command(i2c_dev,period);
|
|
}
|
|
|
|
void ssd1306_i2c_set_com_deselect_level(i2c_t *i2c_dev, uint8_t voltageLevel)
|
|
{
|
|
ssd1306_i2c_command(i2c_dev,SSD1306_SETVCOMDETECT); // 0xDB
|
|
ssd1306_i2c_command(i2c_dev,voltageLevel);
|
|
}
|
|
|
|
void ssd1306_i2c_set_display_entire_on(i2c_t *i2c_dev, uint8_t resumeOrForce)
|
|
{
|
|
if(resumeOrForce = SSD1306_DISPLAYALLON_RESUME)
|
|
{
|
|
ssd1306_i2c_command(i2c_dev,SSD1306_DISPLAYALLON_RESUME); // 0xA4
|
|
}
|
|
else
|
|
{
|
|
ssd1306_i2c_command(i2c_dev,SSD1306_DISPLAYALLON); // 0xA4
|
|
}
|
|
|
|
}
|
|
|
|
void ssd1306_i2c_set_display_invert_pixel(i2c_t *i2c_dev, uint8_t inverted)
|
|
{
|
|
if(inverted)
|
|
{
|
|
ssd1306_i2c_command(i2c_dev,SSD1306_INVERTDISPLAY); // 0xA6
|
|
}
|
|
else
|
|
{
|
|
ssd1306_i2c_command(i2c_dev,SSD1306_NORMALDISPLAY); // 0xA6
|
|
}
|
|
}
|
|
|
|
void ssd1306_i2c_set_scroll(i2c_t *i2c_dev, uint8_t onOff)
|
|
{
|
|
if(onOff)
|
|
{
|
|
ssd1306_i2c_command(i2c_dev,SSD1306_ACTIVATE_SCROLL);
|
|
}
|
|
else
|
|
{
|
|
ssd1306_i2c_command(i2c_dev,SSD1306_DEACTIVATE_SCROLL);
|
|
}
|
|
}
|
|
|
|
|
|
void ssd1306_invertDisplay(i2c_t *i2c_dev, uint16_t i)
|
|
{
|
|
if (i) {
|
|
ssd1306_i2c_command(i2c_dev,SSD1306_INVERTDISPLAY);
|
|
} else {
|
|
ssd1306_i2c_command(i2c_dev,SSD1306_NORMALDISPLAY);
|
|
}
|
|
}
|
|
|
|
void ssd1306_i2c_command(i2c_t *i2c_dev,uint16_t c)
|
|
{
|
|
// I2C
|
|
uint16_t control = 0x00; // Co = 0, D/C = 0
|
|
uint8_t i2cDataLenght = 1; // Co = 0, D/C = 0
|
|
uint16_t address = SSD1306_I2C_ADDRESS; // Co = 0, D/C = 0
|
|
i2c_write(i2c_dev, &address, &control, &c, &i2cDataLenght);
|
|
}
|
|
|
|
|
|
// startscrollright
|
|
// Activate a right handed scroll for rows start through stop
|
|
// Hint, the display is 16 rows tall. To scroll the whole display, run:
|
|
// ssd1306_scrollright(0x00, 0x0F)
|
|
void ssd1306_startscrollright(i2c_t *i2c_dev, uint16_t start, uint16_t stop)
|
|
{
|
|
ssd1306_i2c_command(i2c_dev,SSD1306_RIGHT_HORIZONTAL_SCROLL);
|
|
ssd1306_i2c_command(i2c_dev,0X00);
|
|
ssd1306_i2c_command(i2c_dev,start);
|
|
ssd1306_i2c_command(i2c_dev,0X00);
|
|
ssd1306_i2c_command(i2c_dev,stop);
|
|
ssd1306_i2c_command(i2c_dev,0X00);
|
|
ssd1306_i2c_command(i2c_dev,0XFF);
|
|
ssd1306_i2c_command(i2c_dev,SSD1306_ACTIVATE_SCROLL);
|
|
}
|
|
|
|
// startscrollleft
|
|
// Activate a right handed scroll for rows start through stop
|
|
// Hint, the display is 16 rows tall. To scroll the whole display, run:
|
|
// ssd1306_scrollright(0x00, 0x0F)
|
|
void ssd1306_startscrollleft(i2c_t *i2c_dev,uint16_t start, uint16_t stop)
|
|
{
|
|
ssd1306_i2c_command(i2c_dev,SSD1306_LEFT_HORIZONTAL_SCROLL);
|
|
ssd1306_i2c_command(i2c_dev,0X00);
|
|
ssd1306_i2c_command(i2c_dev,start);
|
|
ssd1306_i2c_command(i2c_dev,0X00);
|
|
ssd1306_i2c_command(i2c_dev,stop);
|
|
ssd1306_i2c_command(i2c_dev,0X00);
|
|
ssd1306_i2c_command(i2c_dev,0XFF);
|
|
ssd1306_i2c_command(i2c_dev,SSD1306_ACTIVATE_SCROLL);
|
|
}
|
|
|
|
// startscrolldiagright
|
|
// Activate a diagonal scroll for rows start through stop
|
|
// Hint, the display is 16 rows tall. To scroll the whole display, run:
|
|
// ssd1306_scrollright(0x00, 0x0F)
|
|
void ssd1306_startscrolldiagright(i2c_t *i2c_dev, uint16_t start, uint16_t stop)
|
|
{
|
|
ssd1306_i2c_command(i2c_dev,SSD1306_SET_VERTICAL_SCROLL_AREA);
|
|
ssd1306_i2c_command(i2c_dev,0X00);
|
|
ssd1306_i2c_command(i2c_dev,SSD1306_LCDHEIGHT);
|
|
ssd1306_i2c_command(i2c_dev,SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL);
|
|
ssd1306_i2c_command(i2c_dev,0X00);
|
|
ssd1306_i2c_command(i2c_dev,start);
|
|
ssd1306_i2c_command(i2c_dev,0X00);
|
|
ssd1306_i2c_command(i2c_dev,stop);
|
|
ssd1306_i2c_command(i2c_dev,0X01);
|
|
ssd1306_i2c_command(i2c_dev,SSD1306_ACTIVATE_SCROLL);
|
|
}
|
|
|
|
// startscrolldiagleft
|
|
// Activate a diagonal scroll for rows start through stop
|
|
// Hint, the display is 16 rows tall. To scroll the whole display, run:
|
|
// ssd1306_scrollright(0x00, 0x0F)
|
|
void ssd1306_startscrolldiagleft(i2c_t *i2c_dev, uint16_t start, uint16_t stop)
|
|
{
|
|
ssd1306_i2c_command(i2c_dev,SSD1306_SET_VERTICAL_SCROLL_AREA);
|
|
ssd1306_i2c_command(i2c_dev,0X00);
|
|
ssd1306_i2c_command(i2c_dev,SSD1306_LCDHEIGHT);
|
|
ssd1306_i2c_command(i2c_dev,SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL);
|
|
ssd1306_i2c_command(i2c_dev,0X00);
|
|
ssd1306_i2c_command(i2c_dev,start);
|
|
ssd1306_i2c_command(i2c_dev,0X00);
|
|
ssd1306_i2c_command(i2c_dev,stop);
|
|
ssd1306_i2c_command(i2c_dev,0X01);
|
|
ssd1306_i2c_command(i2c_dev,SSD1306_ACTIVATE_SCROLL);
|
|
}
|
|
|
|
void ssd1306_stopscroll(i2c_t *i2c_dev)
|
|
{
|
|
ssd1306_i2c_command(i2c_dev,SSD1306_DEACTIVATE_SCROLL);
|
|
}
|
|
|
|
|
|
void ssd1306_drawFastHLineInternal(int16_t x, int16_t y, int16_t w, uint16_t color)
|
|
{
|
|
// Do bounds/limit checks
|
|
if (y < 0 || y >= HEIGHT) {
|
|
return;
|
|
}
|
|
// make sure we don't try to draw below 0
|
|
if (x < 0) {
|
|
w += x;
|
|
x = 0;
|
|
}
|
|
// make sure we don't go off the edge of the display
|
|
if ((x + w) > WIDTH) {
|
|
w = (WIDTH - x);
|
|
}
|
|
// if our width is now negative, punt
|
|
if (w <= 0) {
|
|
return;
|
|
}
|
|
// set up the pointer for movement through the buffer
|
|
uint16_t *pBuf = buffer;
|
|
// adjust the buffer pointer for the current row
|
|
pBuf += ((y / 8) * SSD1306_LCDWIDTH);
|
|
// and offset x columns in
|
|
pBuf += x;
|
|
|
|
uint16_t mask = 1 << (y & 7);
|
|
|
|
switch (color) {
|
|
case WHITE:
|
|
while (w--) {
|
|
*pBuf++ |= mask;
|
|
};
|
|
break;
|
|
case BLACK:
|
|
mask = ~mask;
|
|
while (w--) {
|
|
*pBuf++ &= mask;
|
|
};
|
|
break;
|
|
case INVERSE:
|
|
while (w--) {
|
|
*pBuf++ ^= mask;
|
|
};
|
|
break;
|
|
}
|
|
}
|
|
|
|
void ssd1306_drawFastVLineInternal(int16_t x, int16_t __y, int16_t __h, uint16_t color)
|
|
{
|
|
|
|
// do nothing if we're off the left or right side of the screen
|
|
if (x < 0 || x >= WIDTH) {
|
|
return;
|
|
}
|
|
// make sure we don't try to draw below 0
|
|
if (__y < 0) {
|
|
// __y is negative, this will subtract enough from __h to account
|
|
// for __y being 0
|
|
__h += __y;
|
|
__y = 0;
|
|
|
|
}
|
|
// make sure we don't go past the height of the display
|
|
if ((__y + __h) > HEIGHT) {
|
|
__h = (HEIGHT - __y);
|
|
}
|
|
// if our height is now negative, punt
|
|
if (__h <= 0) {
|
|
return;
|
|
}
|
|
// this display doesn't need ints for coordinates, use local byte
|
|
// registers for faster juggling
|
|
uint16_t y = __y;
|
|
uint16_t h = __h;
|
|
|
|
// set up the pointer for fast movement through the buffer
|
|
uint16_t *pBuf = buffer;
|
|
// adjust the buffer pointer for the current row
|
|
pBuf += ((y / 8) * SSD1306_LCDWIDTH);
|
|
// and offset x columns in
|
|
pBuf += x;
|
|
|
|
// do the first partial byte, if necessary - this requires some
|
|
// masking
|
|
uint16_t mod = (y & 7);
|
|
if (mod) {
|
|
// mask off the high n bits we want to set
|
|
mod = 8 - mod;
|
|
|
|
// note - lookup table results in a nearly 10% performance
|
|
// improvement in fill* functions
|
|
// register uint16_t mask = ~(0xFF >> (mod));
|
|
static uint16_t premask[8] =
|
|
{ 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE };
|
|
uint16_t mask = premask[mod];
|
|
|
|
// adjust the mask if we're not going to reach the end of this
|
|
// byte
|
|
if (h < mod) {
|
|
mask &= (0XFF >> (mod - h));
|
|
}
|
|
|
|
switch (color) {
|
|
case WHITE:
|
|
*pBuf |= mask;
|
|
break;
|
|
case BLACK:
|
|
*pBuf &= ~mask;
|
|
break;
|
|
case INVERSE:
|
|
*pBuf ^= mask;
|
|
break;
|
|
}
|
|
|
|
// fast exit if we're done here!
|
|
if (h < mod) {
|
|
return;
|
|
}
|
|
|
|
h -= mod;
|
|
|
|
pBuf += SSD1306_LCDWIDTH;
|
|
}
|
|
// write solid bytes while we can - effectively doing 8 rows at a time
|
|
if (h >= 8) {
|
|
if (color == INVERSE) { // separate copy of the code so we don't
|
|
// impact performance of the black/white
|
|
// write version with an extra comparison
|
|
// per loop
|
|
do {
|
|
*pBuf = ~(*pBuf);
|
|
|
|
// adjust the buffer forward 8 rows worth of data
|
|
pBuf += SSD1306_LCDWIDTH;
|
|
|
|
// adjust h & y (there's got to be a faster way for me to
|
|
// do this, but this should still help a fair bit for now)
|
|
h -= 8;
|
|
}
|
|
while (h >= 8);
|
|
} else {
|
|
// store a local value to work with
|
|
register uint16_t val = (color == WHITE) ? 255 : 0;
|
|
|
|
do {
|
|
// write our value in
|
|
*pBuf = val;
|
|
|
|
// adjust the buffer forward 8 rows worth of data
|
|
pBuf += SSD1306_LCDWIDTH;
|
|
|
|
// adjust h & y (there's got to be a faster way for me to
|
|
// do this, but this should still help a fair bit for now)
|
|
h -= 8;
|
|
}
|
|
while (h >= 8);
|
|
}
|
|
}
|
|
// now do the final partial byte, if necessary
|
|
if (h) {
|
|
mod = h & 7;
|
|
// this time we want to mask the low bits of the byte, vs the high
|
|
// bits we did above
|
|
// register uint16_t mask = (1 << mod) - 1;
|
|
// note - lookup table results in a nearly 10% performance
|
|
// improvement in fill* functions
|
|
static uint16_t postmask[8] =
|
|
{ 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F };
|
|
uint16_t mask = postmask[mod];
|
|
switch (color) {
|
|
case WHITE:
|
|
*pBuf |= mask;
|
|
break;
|
|
case BLACK:
|
|
*pBuf &= ~mask;
|
|
break;
|
|
case INVERSE:
|
|
*pBuf ^= mask;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ssd1306_drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color)
|
|
{
|
|
uint16_t bSwap = false;
|
|
switch (rotation) {
|
|
case 0:
|
|
// 0 degree rotation, do nothing
|
|
break;
|
|
case 1:
|
|
// 90 degree rotation, swap x & y for rotation, then invert x
|
|
bSwap = true;
|
|
ssd1306_swap(x, y);
|
|
x = WIDTH - x - 1;
|
|
break;
|
|
case 2:
|
|
// 180 degree rotation, invert x and y - then shift y around for
|
|
// height.
|
|
x = WIDTH - x - 1;
|
|
y = HEIGHT - y - 1;
|
|
x -= (w - 1);
|
|
break;
|
|
case 3:
|
|
// 270 degree rotation, swap x & y for rotation, then invert y and
|
|
// adjust y for w (not to become h)
|
|
bSwap = true;
|
|
ssd1306_swap(x, y);
|
|
y = HEIGHT - y - 1;
|
|
y -= (w - 1);
|
|
break;
|
|
}
|
|
|
|
if (bSwap) {
|
|
ssd1306_drawFastVLineInternal(x, y, w, color);
|
|
} else {
|
|
ssd1306_drawFastHLineInternal(x, y, w, color);
|
|
}
|
|
}
|
|
|
|
void ssd1306_drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color)
|
|
{
|
|
uint16_t bSwap = false;
|
|
switch (rotation) {
|
|
case 0:
|
|
break;
|
|
case 1:
|
|
// 90 degree rotation, swap x & y for rotation, then invert x and
|
|
// adjust x for h (now to become w)
|
|
bSwap = true;
|
|
ssd1306_swap(x, y);
|
|
x = WIDTH - x - 1;
|
|
x -= (h - 1);
|
|
break;
|
|
case 2:
|
|
// 180 degree rotation, invert x and y - then shift y around for
|
|
// height.
|
|
x = WIDTH - x - 1;
|
|
y = HEIGHT - y - 1;
|
|
y -= (h - 1);
|
|
break;
|
|
case 3:
|
|
// 270 degree rotation, swap x & y for rotation, then invert y
|
|
bSwap = true;
|
|
ssd1306_swap(x, y);
|
|
y = HEIGHT - y - 1;
|
|
break;
|
|
}
|
|
|
|
if (bSwap) {
|
|
ssd1306_drawFastHLineInternal(x, y, h, color);
|
|
} else {
|
|
ssd1306_drawFastVLineInternal(x, y, h, color);
|
|
}
|
|
}
|
|
|
|
void ssd1306_fillRect(int16_t x, int16_t y, int16_t w, int16_t h, int16_t fillcolor)
|
|
{
|
|
|
|
// Bounds check
|
|
if ((x >= WIDTH) || (y >= HEIGHT))
|
|
return;
|
|
|
|
// Y bounds check
|
|
if (y + h > HEIGHT) {
|
|
h = HEIGHT - y - 1;
|
|
}
|
|
// X bounds check
|
|
if (x + w > WIDTH) {
|
|
w = WIDTH - x - 1;
|
|
}
|
|
|
|
switch (rotation) {
|
|
case 1:
|
|
swap_values(x, y);
|
|
x = WIDTH - x - 1;
|
|
break;
|
|
case 2:
|
|
x = WIDTH - x - 1;
|
|
y = HEIGHT - y - 1;
|
|
break;
|
|
case 3:
|
|
swap_values(x, y);
|
|
y = HEIGHT - y - 1;
|
|
break;
|
|
}
|
|
int16_t i;
|
|
for (i = 0; i < h; i++)
|
|
ssd1306_drawFastHLine(x, y + i, w, fillcolor);
|
|
}
|
|
|
|
int16_t textsize = 1;
|
|
int16_t wrap = 1;
|
|
|
|
void ssd1306_setTextSize(int16_t s)
|
|
{
|
|
textsize = (s > 0) ? s : 1;
|
|
}
|
|
|
|
void ssd1306_write(int16_t c)
|
|
{
|
|
if (c == '\n') {
|
|
cursor_y += textsize * 8;
|
|
cursor_x = 0;
|
|
} else if (c == '\r') {
|
|
// skip em
|
|
} else {
|
|
ssd1306_drawChar(cursor_x, cursor_y, c, WHITE, textsize);
|
|
cursor_x += textsize * 6;
|
|
if (wrap && (cursor_x > (WIDTH - textsize * 6))) {
|
|
cursor_y += textsize * 8;
|
|
cursor_x = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ssd1306_drawString(int8_t *str)
|
|
{
|
|
int16_t i, end;
|
|
end = 5;
|
|
for (i = 0; i < end; i++)
|
|
ssd1306_write(str[i]);
|
|
}
|
|
|
|
// Draw a character
|
|
void ssd1306_drawChar(int16_t x, int16_t y, uint8_t c, int16_t color, int16_t size)
|
|
{
|
|
//Adapted and optimized for oled_lcd.c
|
|
}
|
|
|
|
// the most basic function, set a single pixel
|
|
void ssd1306_drawPixel(int16_t x, int16_t y, uint16_t color)
|
|
{
|
|
//Adapted and optimized for oled_lcd.c
|
|
}
|
|
|
|
// clear everything
|
|
void ssd1306_clearDisplay()
|
|
{
|
|
//Adapted and optimized for oled_lcd.c
|
|
}
|
|
|
|
// Init SSD1306
|
|
void ssd1306_begin(i2c_t *i2c_dev, uint16_t i2caddr)
|
|
{
|
|
//Adapted and optimized for oled_lcd.c
|
|
}
|
|
|
|
void ssd1306_display(i2c_t *i2c_dev)
|
|
{
|
|
//Adapted and optimized for oled_lcd.c
|
|
}
|