STM32_SSD1306/ssd1306.c
2021-07-01 14:38:54 +02:00

211 lines
5.9 KiB
C

#include "ssd1306.h"
// Screenbuffer
static uint8_t SSD1306_Buffer[SSD1306_WIDTH * SSD1306_HEIGHT / 8];
// Screen object
static SSD1306_t SSD1306;
//
// Send a byte to the command register
//
static uint8_t ssd1306_WriteCommand(I2C_HandleTypeDef *hi2c, uint8_t command)
{
return HAL_I2C_Mem_Write(hi2c, SSD1306_I2C_ADDR, 0x00, 1, &command, 1, 10);
}
//
// Initialize the oled screen
//
uint8_t ssd1306_Init(I2C_HandleTypeDef *hi2c)
{
// Wait for the screen to boot
HAL_Delay(100);
int status = 0;
// Init LCD
status += ssd1306_WriteCommand(hi2c, 0xAE); // Display off
status += ssd1306_WriteCommand(hi2c, 0x20); // Set Memory Addressing Mode
status += ssd1306_WriteCommand(hi2c, 0x10); // 00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,Invalid
status += ssd1306_WriteCommand(hi2c, 0xB0); // Set Page Start Address for Page Addressing Mode,0-7
status += ssd1306_WriteCommand(hi2c, 0xC8); // Set COM Output Scan Direction
status += ssd1306_WriteCommand(hi2c, 0x00); // Set low column address
status += ssd1306_WriteCommand(hi2c, 0x10); // Set high column address
status += ssd1306_WriteCommand(hi2c, 0x40); // Set start line address
status += ssd1306_WriteCommand(hi2c, 0x81); // set contrast control register
status += ssd1306_WriteCommand(hi2c, 0xFF);
status += ssd1306_WriteCommand(hi2c, 0xA1); // Set segment re-map 0 to 127
status += ssd1306_WriteCommand(hi2c, 0xA6); // Set normal display
status += ssd1306_WriteCommand(hi2c, 0xA8); // Set multiplex ratio(1 to 64)
status += ssd1306_WriteCommand(hi2c, 0x3F);
status += ssd1306_WriteCommand(hi2c, 0xA4); // 0xa4,Output follows RAM content;0xa5,Output ignores RAM content
status += ssd1306_WriteCommand(hi2c, 0xD3); // Set display offset
status += ssd1306_WriteCommand(hi2c, 0x00); // No offset
status += ssd1306_WriteCommand(hi2c, 0xD5); // Set display clock divide ratio/oscillator frequency
status += ssd1306_WriteCommand(hi2c, 0xF0); // Set divide ratio
status += ssd1306_WriteCommand(hi2c, 0xD9); // Set pre-charge period
status += ssd1306_WriteCommand(hi2c, 0x22);
status += ssd1306_WriteCommand(hi2c, 0xDA); // Set com pins hardware configuration
status += ssd1306_WriteCommand(hi2c, 0x12);
status += ssd1306_WriteCommand(hi2c, 0xDB); // Set vcomh
status += ssd1306_WriteCommand(hi2c, 0x20); // 0x20,0.77xVcc
status += ssd1306_WriteCommand(hi2c, 0x8D); // Set DC-DC enable
status += ssd1306_WriteCommand(hi2c, 0x14); //
status += ssd1306_WriteCommand(hi2c, 0xAF); // Turn on SSD1306 panel
if (status != 0) {
return 1;
}
// Clear screen
ssd1306_Fill(Black);
// Flush buffer to screen
ssd1306_UpdateScreen(hi2c);
// Set default values for screen object
SSD1306.CurrentX = 0;
SSD1306.CurrentY = 0;
SSD1306.Initialized = 1;
return 0;
}
//
// Fill the whole screen with the given color
//
void ssd1306_Fill(SSD1306_COLOR color)
{
// Fill screenbuffer with a constant value (color)
uint32_t i;
for(i = 0; i < sizeof(SSD1306_Buffer); i++)
{
SSD1306_Buffer[i] = (color == Black) ? 0x00 : 0xFF;
}
}
//
// Write the screenbuffer with changed to the screen
//
void ssd1306_UpdateScreen(I2C_HandleTypeDef *hi2c)
{
uint8_t i;
for (i = 0; i < 8; i++) {
ssd1306_WriteCommand(hi2c, 0xB0 + i);
ssd1306_WriteCommand(hi2c, 0x00);
ssd1306_WriteCommand(hi2c, 0x10);
HAL_I2C_Mem_Write(hi2c, SSD1306_I2C_ADDR, 0x40, 1, &SSD1306_Buffer[SSD1306_WIDTH * i], SSD1306_WIDTH, 100);
}
}
//
// Draw one pixel in the screenbuffer
// X => X Coordinate
// Y => Y Coordinate
// color => Pixel color
//
void ssd1306_DrawPixel(uint8_t x, uint8_t y, SSD1306_COLOR color)
{
if (x >= SSD1306_WIDTH || y >= SSD1306_HEIGHT)
{
// Don't write outside the buffer
return;
}
// Check if pixel should be inverted
if (SSD1306.Inverted)
{
color = (SSD1306_COLOR)!color;
}
// Draw in the correct color
if (color == White)
{
SSD1306_Buffer[x + (y / 8) * SSD1306_WIDTH] |= 1 << (y % 8);
}
else
{
SSD1306_Buffer[x + (y / 8) * SSD1306_WIDTH] &= ~(1 << (y % 8));
}
}
//
// Draw 1 char to the screen buffer
// ch => Character to write
// Font => Font to use
// color => Black or White
//
char ssd1306_WriteChar(char ch, FontDef Font, SSD1306_COLOR color)
{
uint32_t i, b, j;
// Check remaining space on current line
if (SSD1306_WIDTH <= (SSD1306.CurrentX + Font.FontWidth) ||
SSD1306_HEIGHT <= (SSD1306.CurrentY + Font.FontHeight))
{
// Not enough space on current line
return 0;
}
// Translate font to screenbuffer
for (i = 0; i < Font.FontHeight; i++)
{
b = Font.data[(ch - 32) * Font.FontHeight + i];
for (j = 0; j < Font.FontWidth; j++)
{
if ((b << j) & 0x8000)
{
ssd1306_DrawPixel(SSD1306.CurrentX + j, (SSD1306.CurrentY + i), (SSD1306_COLOR) color);
}
else
{
ssd1306_DrawPixel(SSD1306.CurrentX + j, (SSD1306.CurrentY + i), (SSD1306_COLOR)!color);
}
}
}
// The current space is now taken
SSD1306.CurrentX += Font.FontWidth;
// Return written char for validation
return ch;
}
//
// Write full string to screenbuffer
//
char ssd1306_WriteString(char* str, FontDef Font, SSD1306_COLOR color)
{
// Write until null-byte
while (*str)
{
if (ssd1306_WriteChar(*str, Font, color) != *str)
{
// Char could not be written
return *str;
}
// Next char
str++;
}
// Everything ok
return *str;
}
//
// Set cursor position
//
void ssd1306_SetCursor(uint8_t x, uint8_t y)
{
SSD1306.CurrentX = x;
SSD1306.CurrentY = y;
}