single repo
This commit is contained in:
187
pico-ssd1306/ssd1306.cpp
Normal file
187
pico-ssd1306/ssd1306.cpp
Normal file
@@ -0,0 +1,187 @@
|
||||
#include "ssd1306.h"
|
||||
|
||||
namespace pico_ssd1306 {
|
||||
SSD1306::SSD1306(i2c_inst *i2CInst, uint16_t Address, Size size) {
|
||||
// Set class instanced variables
|
||||
this->i2CInst = i2CInst;
|
||||
this->address = Address;
|
||||
this->size = size;
|
||||
|
||||
this->width = 128;
|
||||
|
||||
if (size == Size::W128xH32) {
|
||||
this->height = 32;
|
||||
} else {
|
||||
this->height = 64;
|
||||
}
|
||||
|
||||
// display is not inverted by default
|
||||
this->inverted = false;
|
||||
|
||||
// this is a list of setup commands for the display
|
||||
uint8_t setup[] = {
|
||||
SSD1306_DISPLAY_OFF,
|
||||
SSD1306_LOWCOLUMN,
|
||||
SSD1306_HIGHCOLUMN,
|
||||
SSD1306_STARTLINE,
|
||||
|
||||
SSD1306_MEMORYMODE,
|
||||
SSD1306_MEMORYMODE_HORZONTAL,
|
||||
|
||||
SSD1306_CONTRAST,
|
||||
0xFF,
|
||||
|
||||
SSD1306_INVERTED_OFF,
|
||||
|
||||
SSD1306_MULTIPLEX,
|
||||
63,
|
||||
|
||||
SSD1306_DISPLAYOFFSET,
|
||||
0x00,
|
||||
|
||||
SSD1306_DISPLAYCLOCKDIV,
|
||||
0x80,
|
||||
|
||||
SSD1306_PRECHARGE,
|
||||
0x22,
|
||||
|
||||
SSD1306_COMPINS,
|
||||
0x12,
|
||||
|
||||
SSD1306_VCOMDETECT,
|
||||
0x40,
|
||||
|
||||
SSD1306_CHARGEPUMP,
|
||||
0x14,
|
||||
|
||||
SSD1306_DISPLAYALL_ON_RESUME,
|
||||
SSD1306_DISPLAY_ON
|
||||
};
|
||||
|
||||
// send each one of the setup commands
|
||||
for (uint8_t &command: setup) {
|
||||
this->cmd(command);
|
||||
}
|
||||
|
||||
// clear the buffer and send it to the display
|
||||
// if not done display shows garbage data
|
||||
this->clear();
|
||||
this->sendBuffer();
|
||||
|
||||
}
|
||||
|
||||
void SSD1306::setPixel(int16_t x, int16_t y, WriteMode mode) {
|
||||
// return if position out of bounds
|
||||
if ((x < 0) || (x >= this->width) || (y < 0) || (y >= this->height)) return;
|
||||
|
||||
// byte to be used for buffer operation
|
||||
uint8_t byte;
|
||||
|
||||
// display with 32 px height requires doubling of set bits, reason to this is explained in readme
|
||||
// this shifts 1 to byte based on y coordinate
|
||||
// remember that buffer is a one dimension array, so we have to calculate offset from coordinates
|
||||
if (size == Size::W128xH32) {
|
||||
y = (y << 1) + 1;
|
||||
byte = 1 << (y & 7);
|
||||
char byte_offset = byte >> 1;
|
||||
byte = byte | byte_offset;
|
||||
} else {
|
||||
byte = 1 << (y & 7);
|
||||
}
|
||||
|
||||
// check the write mode and manipulate the frame buffer
|
||||
if (mode == WriteMode::ADD) {
|
||||
this->frameBuffer.byteOR(x + (y / 8) * this->width, byte);
|
||||
} else if (mode == WriteMode::SUBTRACT) {
|
||||
this->frameBuffer.byteAND(x + (y / 8) * this->width, ~byte);
|
||||
} else if (mode == WriteMode::INVERT) {
|
||||
this->frameBuffer.byteXOR(x + (y / 8) * this->width, byte);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void SSD1306::sendBuffer() {
|
||||
this->cmd(SSD1306_PAGEADDR); //Set page address from min to max
|
||||
this->cmd(0x00);
|
||||
this->cmd(0x07);
|
||||
this->cmd(SSD1306_COLUMNADDR); //Set column address from min to max
|
||||
this->cmd(0x00);
|
||||
this->cmd(127);
|
||||
|
||||
// create a temporary buffer of size of buffer plus 1 byte for startline command aka 0x40
|
||||
unsigned char data[FRAMEBUFFER_SIZE + 1];
|
||||
|
||||
data[0] = SSD1306_STARTLINE;
|
||||
|
||||
// copy framebuffer to temporary buffer
|
||||
memcpy(data + 1, frameBuffer.get(), FRAMEBUFFER_SIZE);
|
||||
|
||||
// send data to device
|
||||
i2c_write_blocking(this->i2CInst, this->address, data, FRAMEBUFFER_SIZE + 1, false);
|
||||
}
|
||||
|
||||
void SSD1306::clear() {
|
||||
this->frameBuffer.clear();
|
||||
}
|
||||
|
||||
void SSD1306::setOrientation(bool orientation) {
|
||||
// remap columns and rows scan direction, effectively flipping the image on display
|
||||
if (orientation) {
|
||||
this->cmd(SSD1306_CLUMN_REMAP_OFF);
|
||||
this->cmd(SSD1306_COM_REMAP_OFF);
|
||||
} else {
|
||||
this->cmd(SSD1306_CLUMN_REMAP_ON);
|
||||
this->cmd(SSD1306_COM_REMAP_ON);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SSD1306::addBitmapImage(int16_t anchorX, int16_t anchorY, uint8_t image_width, uint8_t image_height,
|
||||
uint8_t *image,
|
||||
WriteMode mode) {
|
||||
uint8_t byte;
|
||||
// goes over every single bit in image and sets pixel data on its coordinates
|
||||
for (uint8_t y = 0; y < image_height; y++) {
|
||||
for (uint8_t x = 0; x < image_width / 8; x++) {
|
||||
byte = image[y * (image_width / 8) + x];
|
||||
for (uint8_t z = 0; z < 8; z++) {
|
||||
if ((byte >> (7 - z)) & 1) {
|
||||
this->setPixel(x * 8 + z + anchorX, y + anchorY, mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SSD1306::invertDisplay() {
|
||||
this->cmd(SSD1306_INVERTED_OFF | !this->inverted);
|
||||
inverted = !inverted;
|
||||
}
|
||||
|
||||
void SSD1306::cmd(unsigned char command) {
|
||||
// 0x00 is a byte indicating to ssd1306 that a command is being sent
|
||||
uint8_t data[2] = {0x00, command};
|
||||
i2c_write_blocking(this->i2CInst, this->address, data, 2, false);
|
||||
}
|
||||
|
||||
|
||||
void SSD1306::setContrast(unsigned char contrast) {
|
||||
this->cmd(SSD1306_CONTRAST);
|
||||
this->cmd(contrast);
|
||||
}
|
||||
|
||||
void SSD1306::setBuffer(unsigned char * buffer) {
|
||||
this->frameBuffer.setBuffer(buffer);
|
||||
}
|
||||
|
||||
void SSD1306::turnOff() {
|
||||
this->cmd(SSD1306_DISPLAY_OFF);
|
||||
}
|
||||
|
||||
void SSD1306::turnOn() {
|
||||
this->cmd(SSD1306_DISPLAY_ON);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user