ref: 21f5ac6f65245a6d5f1b63b0f1a38d4001f1d5dc
dir: /LEAF/Src/ssd1306.c/
/*
* ssd1306.c
*
* Created on: Oct 8, 2019
* Author: jeffsnyder
*/
/*
* ssd1306.c
*
* Created on: Jul 6, 2018
* Author: jeffsnyder
*/
#include "main.h"
#include "ssd1306.h"
unsigned char buffer[512];
//unsigned char buffer [] = {
//
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0xC0, 0xC0, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0xC0, 0xC0, 0xC0,
// 0xC0, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0xC0,
// 0xC0, 0xC0, 0xC0, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80,
// 0xC0, 0xC0, 0xC0, 0xC0, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0,
// 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x80, 0x80, 0xC0, 0xC0, 0xC0, 0xC0, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x1F, 0xFE, 0xF0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80,
// 0xF0, 0xFE, 0x1F, 0x03, 0x00, 0x00, 0x00, 0xF0, 0xFE, 0x0F, 0x03, 0x01, 0x01, 0x00, 0x00, 0x00,
// 0x00, 0x01, 0x01, 0x03, 0x0F, 0xFE, 0xF0, 0x00, 0x00, 0x00, 0xF0, 0xFE, 0x0F, 0x03, 0x01, 0x01,
// 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x06, 0x00, 0x00, 0x00, 0xF0, 0xFE, 0x0F, 0x03, 0x01, 0x01,
// 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x0F, 0xFE, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x0F, 0xFE, 0xF0, 0x00, 0x00, 0x00,
// 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0,
// 0xFE, 0x0F, 0x03, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x06, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x3F, 0xFC, 0xE0, 0xE0, 0xFC, 0x1F,
// 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x3F, 0x78, 0x60, 0xC0, 0xC0, 0x80, 0x80, 0x80,
// 0x80, 0xC0, 0xC0, 0x60, 0x78, 0x3F, 0x07, 0x00, 0x00, 0x00, 0x07, 0x3F, 0x78, 0xE0, 0xC0, 0xC0,
// 0x80, 0x80, 0xC0, 0xC0, 0xE0, 0x70, 0x10, 0x00, 0x00, 0x00, 0x07, 0x3F, 0x78, 0x60, 0xC0, 0xC0,
// 0x80, 0x80, 0x80, 0x80, 0xC0, 0xC0, 0x60, 0x78, 0x3F, 0x07, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
// 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xC0, 0xE0, 0xE0, 0x78, 0x3F, 0x07, 0x00, 0x00, 0x00,
// 0xFF, 0xFF, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x07,
// 0x3F, 0x78, 0xE0, 0xC0, 0xC0, 0x80, 0x80, 0xC0, 0xC0, 0xE0, 0x70, 0x10, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01,
// 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
// 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
// };
#define ssd1306_swap(a, b) { int16_t t = a; a = b; b = t; }
#define WIDTH SSD1306_LCDWIDTH
#define HEIGHT SSD1306_LCDHEIGHT
uint8_t displayBufferChunk[513] __ATTR_RAM_D3;
uint8_t OLED_xpos = 0;
uint8_t OLED_ypos = 0;
uint8_t OLED_i2c_address;
uint8_t OLED_externalVCC;
I2C_HandleTypeDef* OLED_i2c_handle;
void ssd1306_begin(I2C_HandleTypeDef* hi2c, uint8_t vccstate, uint8_t i2caddr)
{
OLED_i2c_address = i2caddr;
OLED_externalVCC = vccstate;
OLED_i2c_handle = hi2c;
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, GPIO_PIN_SET); //PULL RESET LINE HIGH
// VDD (3.3V) goes high at start, lets just chill for a ms
HAL_Delay(1);
// bring reset low
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, GPIO_PIN_RESET); //PULL RESET LINE HIGH
// wait 10ms
HAL_Delay(10);
// bring out of reset
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, GPIO_PIN_SET); //PULL RESET LINE HIGH
// turn on VCC (9V?)
// Init sequence
ssd1306_command(SSD1306_DISPLAYOFF); // 0xAE
ssd1306_command(SSD1306_SETDISPLAYCLOCKDIV); // 0xD5
ssd1306_command(0x80); // the suggested ratio 0x80
ssd1306_command(SSD1306_SETMULTIPLEX); // 0xA8
ssd1306_command(SSD1306_LCDHEIGHT - 1);
ssd1306_command(SSD1306_SETDISPLAYOFFSET); // 0xD3
ssd1306_command(0x0); // no offset
ssd1306_command(SSD1306_SETSTARTLINE | 0x0); // line #0
ssd1306_command(SSD1306_CHARGEPUMP); // 0x8D
if (vccstate == SSD1306_EXTERNALVCC)
{ ssd1306_command(0x10); }
else
{ ssd1306_command(0x14); }
ssd1306_command(SSD1306_MEMORYMODE); // 0x20
ssd1306_command(0x00); // 0x0 act like ks0108
ssd1306_command(SSD1306_SEGREMAP | 0x1);
ssd1306_command(SSD1306_COMSCANDEC);
#if defined SSD1306_128_32
ssd1306_command(SSD1306_SETCOMPINS); // 0xDA
ssd1306_command(0x02);
ssd1306_command(SSD1306_SETCONTRAST); // 0x81
ssd1306_command(0x8F);
#elif defined SSD1306_128_64
ssd1306_command(SSD1306_SETCOMPINS); // 0xDA
ssd1306_command(0x12);
ssd1306_command(SSD1306_SETCONTRAST); // 0x81
if (vccstate == SSD1306_EXTERNALVCC)
{ ssd1306_command(0x9F); }
else
{ ssd1306_command(0xCF); }
#elif defined SSD1306_96_16
ssd1306_command(SSD1306_SETCOMPINS); // 0xDA
ssd1306_command(0x2); //ada x12
ssd1306_command(SSD1306_SETCONTRAST); // 0x81
if (vccstate == SSD1306_EXTERNALVCC)
{ ssd1306_command(0x10); }
else
{ ssd1306_command(0xAF); }
#endif
ssd1306_command(SSD1306_SETPRECHARGE); // 0xd9
if (vccstate == SSD1306_EXTERNALVCC)
{ ssd1306_command(0x22); }
else
{ ssd1306_command(0xF1); }
ssd1306_command(SSD1306_SETVCOMDETECT); // 0xDB
ssd1306_command(0x40);
ssd1306_command(SSD1306_DISPLAYALLON_RESUME); // 0xA4
ssd1306_command(SSD1306_NORMALDISPLAY); // 0xA6
ssd1306_command(SSD1306_DEACTIVATE_SCROLL);
ssd1306_command(SSD1306_DISPLAYON);//--turn on oled panel
}
void sdd1306_invertDisplay(uint8_t i) {
if (i) {
ssd1306_command(SSD1306_INVERTDISPLAY);
} else {
ssd1306_command(SSD1306_NORMALDISPLAY);
}
}
void ssd1306_command(uint8_t c) {
// I2C
// uint8_t control = 0x00; // Co = 0, D/C = 0
uint8_t i2c_message[2] = {0,0};
i2c_message[1] = c;
HAL_I2C_Master_Transmit(OLED_i2c_handle, OLED_i2c_address, i2c_message, 2, 2000);
}
// Dim the display
// dim = true: display is dimmed
// dim = false: display is normal
void ssd1306_dim(uint8_t dim) {
uint8_t contrast;
if (dim) {
contrast = 0; // Dimmed display
} else {
if (OLED_externalVCC == SSD1306_EXTERNALVCC) {
contrast = 0x9F;
} else {
contrast = 0xCF;
}
}
// the range of contrast to too small to be really useful
// it is useful to dim the display
ssd1306_command(SSD1306_SETCONTRAST);
ssd1306_command(contrast);
}
void ssd1306_display_full_buffer(void) {
ssd1306_home();
// for (int i = 0; i < 512; i++)
// {
// displayBufferChunk[0] = 0x40;
// for (int x = 0; x < 16; x++)
// {
// displayBufferChunk[x+1] = buffer[i];
// i++;
// }
// HAL_I2C_Master_Transmit_DMA(OLED_i2c_handle, OLED_i2c_address, displayBufferChunk, 17);
//// HAL_I2C_Master_Transmit(OLED_i2c_handle, OLED_i2c_address, displayBufferChunk, 17, 2000);
//// HAL_Delay(1);
// i--;
// }
displayBufferChunk[0] = 0x40;
for (int i = 0; i < 512; i++)
{
displayBufferChunk[i+1] = buffer[i];
}
HAL_I2C_Master_Transmit_DMA(OLED_i2c_handle, OLED_i2c_address, displayBufferChunk, 513);
}
void ssd1306_home(void) {
ssd1306_move_raw(0,0);
}
void ssd1306_move_raw(uint8_t row, uint8_t column){
if(column > 127) { column = 127; }
if(row > 7) { row = 7; }
ssd1306_command(SSD1306_COLUMNADDR);
ssd1306_command(column); // Column start address (0 = reset)
ssd1306_command(SSD1306_LCDWIDTH-1); // Column end address (127 = reset)
ssd1306_command(SSD1306_PAGEADDR);
ssd1306_command(row); // Page start address (0 = reset)
ssd1306_command(3); // Page end address
}
void ssd1306_move(uint8_t row, uint8_t column) {
if(column > 15) { column = 15; }
if(row > 7) { row = 7; }
ssd1306_move_raw(row,(uint8_t)(column << 3));
}
void ssd1306_write_internal(uint8_t* data, uint16_t numBytes) {
for (uint16_t i = 0; i < numBytes; i++)
{
buffer[i+(OLED_xpos + (OLED_ypos * 128))] = data[i];
}
}
void ssd1306_write(uint8_t* data, uint16_t numBytes) {
uint8_t localBuffer[numBytes+1];
localBuffer[0] = 0x40;
for (uint16_t i = 0; i < numBytes; i++)
{
localBuffer[i+1] = data[i];
}
HAL_I2C_Master_Transmit(OLED_i2c_handle, OLED_i2c_address, localBuffer, numBytes+1, 2000);
}
void ssd1306_write_2X(uint8_t* data, uint16_t numBytes) {
uint8_t localBuffer[(numBytes*2)+1];
localBuffer[0] = 0x40;
for (uint16_t i = 0; i < numBytes; i++)
{
localBuffer[i+1] = data[i] >> 4;
}
HAL_I2C_Master_Transmit(OLED_i2c_handle, OLED_i2c_address, localBuffer, (numBytes*2)+1, 2000);
ssd1306_move(1,0);
for (uint16_t i = 0; i < numBytes; i++)
{
localBuffer[i+1] = data[i] & 0x0f;
}
HAL_I2C_Master_Transmit(OLED_i2c_handle, OLED_i2c_address, localBuffer, (numBytes*2)+1, 2000);
}