Stairs/module/src/lib/VeryTinySSD1306.c

518 lines
11 KiB
C

/*
* Stairs lighting
* Copyright 2017 (c) Mark van Renswoude
*
* https://git.x2software.net/pub/Stairs
*
* Port of Stephen Denne's Tiny4kOLED to C
* and without the Arduino framework dependency.
* https://github.com/technoblogy/tiny-i2c
*/
#include "VeryTinySSD1306.h"
#include <avr/pgmspace.h>
#include "VeryTinyI2C.h"
#define SSD1306_PAGES 4
#define SSD1306_COMMAND 0x00
#define SSD1306_DATA 0x40
// ----------------------------------------------------------------------------
// Some code based on "IIC_without_ACK" by http://www.14blog.com/archives/1358
const uint8_t ssd1306_init_sequence [] PROGMEM = { // Initialization Sequence
// 0xAE, // Display OFF (sleep mode)
// 0x20, 0b10, // Set Memory Addressing Mode
// 00=Horizontal Addressing Mode; 01=Vertical Addressing Mode;
// 10=Page Addressing Mode (RESET); 11=Invalid
// 0xB0, // Set Page Start Address for Page Addressing Mode, 0-7
0xC8, // Set COM Output Scan Direction
// 0x00, // ---set low column address
// 0x10, // ---set high column address
// 0x40, // --set start line address
// 0x81, 0x7F, // Set contrast control register
0xA1, // Set Segment Re-map. A0=address mapped; A1=address 127 mapped.
// 0xA6, // Set display mode. A6=Normal; A7=Inverse
0xA8, 0x1F, // Set multiplex ratio(1 to 64)
// 0xA4, // Output RAM to Display
// 0xA4=Output follows RAM content; 0xA5,Output ignores RAM content
// 0xD3, 0x00, // Set display offset. 00 = no offset
// 0xD5, 0x80, // --set display clock divide ratio/oscillator frequency
// 0xD9, 0x22, // Set pre-charge period
0xDA, 0x02, // Set com pins hardware configuration
// 0xDB, 0x20, // --set vcomh 0x20 = 0.77xVcc
0x8D, 0x14 // Set DC-DC enable
};
const DCfont *oledFont = 0;
uint8_t oledX = 0, oledY = 0;
uint8_t renderingFrame = 0xB0, drawingFrame = 0x40;
void ssd1306_send_command_start(void)
{
i2c_start(SSD1306, 0);
i2c_write(SSD1306_COMMAND);
}
void ssd1306_send_data_start(void)
{
i2c_start(SSD1306, 0);
i2c_write(SSD1306_DATA);
}
void ssd1306_send_command_byte(uint8_t byte)
{
if (i2c_write(byte) == 0)
{
i2c_stop();
ssd1306_send_command_start();
i2c_write(byte);
}
}
void ssd1306_send_data_byte(uint8_t byte)
{
if (i2c_write(byte) == 0)
{
i2c_stop();
ssd1306_send_data_start();
i2c_write(byte);
}
}
void ssd1306_send_command(uint8_t command)
{
ssd1306_send_command_start();
i2c_write(command);
i2c_stop();
}
void ssd1306_send_command2(uint8_t command1, uint8_t command2)
{
ssd1306_send_command_start();
i2c_write(command1);
i2c_write(command2);
i2c_stop();
}
void ssd1306_send_command3(uint8_t command1, uint8_t command2, uint8_t command3)
{
ssd1306_send_command_start();
i2c_write(command1);
i2c_write(command2);
i2c_write(command3);
i2c_stop();
}
void ssd1306_send_command6(uint8_t command1, uint8_t command2, uint8_t command3, uint8_t command4, uint8_t command5, uint8_t command6)
{
ssd1306_send_command_start();
i2c_write(command1);
i2c_write(command2);
i2c_write(command3);
i2c_write(command4);
i2c_write(command5);
i2c_write(command6);
i2c_stop();
}
void ssd1306_send_command7(uint8_t command1, uint8_t command2, uint8_t command3, uint8_t command4, uint8_t command5, uint8_t command6, uint8_t command7)
{
ssd1306_send_command_start();
i2c_write(command1);
i2c_write(command2);
i2c_write(command3);
i2c_write(command4);
i2c_write(command5);
i2c_write(command6);
i2c_write(command7);
i2c_stop();
}
void ssd1306_begin_default(void)
{
ssd1306_begin(sizeof(ssd1306_init_sequence), ssd1306_init_sequence);
}
void ssd1306_begin(uint8_t init_sequence_length, const uint8_t init_sequence [])
{
i2c_init();
ssd1306_send_command_start();
for (uint8_t i = 0; i < init_sequence_length; i++)
{
ssd1306_send_command_byte(pgm_read_byte(&init_sequence[i]));
}
i2c_stop();
}
void ssd1306_setFont(const DCfont *font)
{
oledFont = font;
}
void ssd1306_setCursor(uint8_t x, uint8_t y)
{
ssd1306_send_command3(renderingFrame | (y & 0x07), 0x10 | ((x & 0xf0) >> 4), x & 0x0f);
oledX = x;
oledY = y;
}
void ssd1306_clear(void)
{
ssd1306_fill(0x00);
}
void ssd1306_fill(uint8_t fill)
{
for (uint8_t m = 0; m < SSD1306_PAGES; m++)
{
ssd1306_setCursor(0, m);
ssd1306_fillToEOL(fill);
}
ssd1306_setCursor(0, 0);
}
void ssd1306_newLine_height(uint8_t fontHeight)
{
oledY+=fontHeight;
if (oledY > SSD1306_PAGES - fontHeight)
{
oledY = SSD1306_PAGES - fontHeight;
}
ssd1306_setCursor(0, oledY);
}
void ssd1306_newLine(void)
{
ssd1306_newLine_height(oledFont->height);
}
uint8_t ssd1306_write(uint8_t c)
{
if (!oledFont)
return 1;
if (c == '\r')
return 1;
uint8_t h = oledFont->height;
if (c == '\n')
{
ssd1306_newLine_height(h);
return 1;
}
uint8_t w = oledFont->width;
if (oledX > ((uint8_t)128 - w))
{
ssd1306_newLine_height(h);
}
uint16_t offset = ((uint16_t)c - oledFont->first) * w * h;
uint8_t line = h;
do
{
ssd1306_send_data_start();
for (uint8_t i = 0; i < w; i++)
{
ssd1306_send_data_byte(pgm_read_byte(&(oledFont->bitmap[offset++])));
}
i2c_stop();
if (h == 1)
{
oledX+=w;
}
else
{
if (line > 1)
{
ssd1306_setCursor(oledX, oledY + 1);
}
else
{
ssd1306_setCursor(oledX + w, oledY - (h - 1));
}
}
}
while (--line);
return 1;
}
void ssd1306_bitmap(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, const uint8_t bitmap[])
{
uint16_t j = 0;
for (uint8_t y = y0; y < y1; y++)
{
ssd1306_setCursor(x0,y);
ssd1306_send_data_start();
for (uint8_t x = x0; x < x1; x++)
{
ssd1306_send_data_byte(pgm_read_byte(&bitmap[j++]));
}
i2c_stop();
}
ssd1306_setCursor(0, 0);
}
void ssd1306_clearToEOL(void)
{
ssd1306_fillToEOL(0x00);
}
void ssd1306_fillToEOL(uint8_t fill)
{
ssd1306_fillLength(fill, 128 - oledX);
}
void ssd1306_fillLength(uint8_t fill, uint8_t length)
{
oledX += length;
ssd1306_send_data_start();
do
{
ssd1306_send_data_byte(fill);
}
while (--length);
i2c_stop();
}
void ssd1306_startData(void)
{
ssd1306_send_data_start();
}
void ssd1306_sendData(const uint8_t data)
{
ssd1306_send_data_byte(data);
}
void ssd1306_endData(void)
{
i2c_stop();
}
// Double Buffering Commands
void ssd1306_switchRenderFrame(void)
{
renderingFrame ^= 0x04;
}
void ssd1306_switchDisplayFrame(void)
{
drawingFrame ^= 0x20;
ssd1306_send_command(drawingFrame);
}
void ssd1306_switchFrame(void)
{
ssd1306_switchDisplayFrame();
ssd1306_switchRenderFrame();
}
uint8_t ssd1306_currentRenderFrame(void)
{
return (renderingFrame >> 2) & 0x01;
}
uint8_t ssd1306_currentDisplayFrame(void)
{
return (drawingFrame >> 5) & 0x01;
}
// 1. Fundamental Command Table
void ssd1306_setContrast(uint8_t contrast)
{
ssd1306_send_command2(0x81,contrast);
}
void ssd1306_setEntireDisplayOn(bool enable)
{
if (enable)
ssd1306_send_command(0xA5);
else
ssd1306_send_command(0xA4);
}
void ssd1306_setInverse(bool enable)
{
if (enable)
ssd1306_send_command(0xA7);
else
ssd1306_send_command(0xA6);
}
void ssd1306_off(void)
{
ssd1306_send_command(0xAE);
}
void ssd1306_on(void)
{
ssd1306_send_command(0xAF);
}
// 2. Scrolling Command Table
void ssd1306_scrollRight(uint8_t startPage, uint8_t interval, uint8_t endPage)
{
ssd1306_send_command7(0x26, 0x00, startPage, interval, endPage, 0x00, 0xFF);
}
void ssd1306_scrollLeft(uint8_t startPage, uint8_t interval, uint8_t endPage)
{
ssd1306_send_command7(0x27, 0x00, startPage, interval, endPage, 0x00, 0xFF);
}
void ssd1306_scrollRightOffset(uint8_t startPage, uint8_t interval, uint8_t endPage, uint8_t offset)
{
ssd1306_send_command6(0x29, 0x00, startPage, interval, endPage, offset);
}
void ssd1306_scrollLeftOffset(uint8_t startPage, uint8_t interval, uint8_t endPage, uint8_t offset)
{
ssd1306_send_command6(0x2A, 0x00, startPage, interval, endPage, offset);
}
void ssd1306_deactivateScroll(void)
{
ssd1306_send_command(0x2E);
}
void ssd1306_activateScroll(void)
{
ssd1306_send_command(0x2F);
}
void ssd1306_setVerticalScrollArea(uint8_t top, uint8_t rows)
{
ssd1306_send_command3(0xA3, top, rows);
}
// 3. Addressing Setting Command Table
void ssd1306_setColumnStartAddress(uint8_t startAddress)
{
ssd1306_send_command2(startAddress & 0x0F, startAddress >> 4);
}
void ssd1306_setMemoryAddressingMode(uint8_t mode)
{
ssd1306_send_command2(0x20, mode & 0x03);
}
void ssd1306_setColumnAddress(uint8_t startAddress, uint8_t endAddress)
{
ssd1306_send_command3(0x21, startAddress & 0x7F, endAddress & 0x7F);
}
void ssd1306_setPageAddress(uint8_t startPage, uint8_t endPage)
{
ssd1306_send_command3(0x22, startPage & 0x07, endPage & 0x07);
}
void ssd1306_setPageStartAddress(uint8_t startPage)
{
ssd1306_send_command(0xB0 | (startPage & 0x07));
}
// 4. Hardware Configuration (Panel resolution and layout related) Command Table
void ssd1306_setDisplayStartLine(uint8_t startLine)
{
ssd1306_send_command(0x40 | (startLine & 0x3F));
}
void ssd1306_setSegmentRemap(uint8_t remap)
{
ssd1306_send_command(0xA0 | (remap & 0x01));
}
void ssd1306_setMultiplexRatio(uint8_t mux)
{
ssd1306_send_command2(0xA8, (mux - 1) & 0x3F);
}
void ssd1306_setComOutputDirection(uint8_t direction)
{
ssd1306_send_command(0xC0 | ((direction & 0x01)<<3));
}
void ssd1306_setDisplayOffset(uint8_t offset)
{
ssd1306_send_command2(0xD3, offset & 0x3F);
}
void ssd1306_setComPinsHardwareConfiguration(uint8_t alternative, uint8_t enableLeftRightRemap)
{
ssd1306_send_command2(0xDA, ((enableLeftRightRemap & 0x01) << 5) | ((alternative & 0x01) << 4) | 0x02 );
}
// 5. Timing and Driving Scheme Setting Command table
void ssd1306_setDisplayClock(uint8_t divideRatio, uint8_t oscillatorFrequency)
{
ssd1306_send_command2(0xD5, ((oscillatorFrequency & 0x0F) << 4) | ((divideRatio -1) & 0x0F));
}
void ssd1306_setPrechargePeriod(uint8_t phaseOnePeriod, uint8_t phaseTwoPeriod)
{
ssd1306_send_command2(0xD9, ((phaseTwoPeriod & 0x0F) << 4) | (phaseOnePeriod & 0x0F));
}
void ssd1306_setVcomhDeselectLevel(uint8_t level)
{
ssd1306_send_command2(0xDB, (level & 0x07) << 4);
}
void ssd1306_nop(void)
{
ssd1306_send_command(0xE3);
}
// 6. Advance Graphic Command table
void ssd1306_fadeOut(uint8_t interval)
{
ssd1306_send_command2(0x23, (0x20 | (interval & 0x0F)));
}
void ssd1306_blink(uint8_t interval)
{
ssd1306_send_command2(0x23, (0x30 | (interval & 0x0F)));
}
void ssd1306_disableFadeOutAndBlinking(void)
{
ssd1306_send_command2(0x23, 0x00);
}
void ssd1306_enableZoomIn(void)
{
ssd1306_send_command2(0xD6, 0x01);
}
void ssd1306_disableZoomIn(void)
{
ssd1306_send_command2(0xD6, 0x00);
}
// Charge Pump Settings
void ssd1306_enableChargePump(void)
{
ssd1306_send_command2(0x8D, 0x14);
}
void ssd1306_disableChargePump(void)
{
ssd1306_send_command2(0x8D, 0x10);
}