This repository has been archived on 2023-07-17. You can view files and clone it, but cannot push or open issues or pull requests.
bl_mcu_sdk/bsp/bsp_common/mcu_lcd/ssd1306.c

390 lines
11 KiB
C

#include "ssd1306.h"
#include "hal_i2c.h"
#include "hal_spi.h"
#include "hal_gpio.h"
#include "font.h"
#include "bflb_platform.h"
#define SSD1306_USING_I2C 0
#define SSD1306_USING_SPI 1
#define INTERFACE_SELECT SSD1306_USING_SPI
static uint8_t OLED_GRAM[128][8];
struct device *ssd_1306;
static void ssd1306_write_byte(uint8_t data, uint8_t cmd)
{
#if INTERFACE_SELECT == SSD1306_USING_I2C
i2c_msg_t msg;
if (cmd) {
msg.subaddr = 0x40;
} else {
msg.subaddr = 0x00;
}
msg.buf = &data;
msg.flags = SUB_ADDR_1BYTE | I2C_WR;
msg.len = 1;
msg.slaveaddr = 0x3c;
i2c_transfer(ssd_1306, &msg, 1);
#else
if (cmd) {
CS1_LOW;
DC_HIGH;
} else {
CS1_LOW;
DC_LOW;
}
spi_transmit(ssd_1306, &data, 1, SPI_TRANSFER_TYPE_8BIT);
CS1_HIGH;
DC_HIGH;
#endif
}
void ssd1306_init(void)
{
#if INTERFACE_SELECT == SSD1306_USING_I2C
i2c_register(I2C0_INDEX, "lcd_dev_ifs");
ssd_1306 = device_find("lcd_dev_ifs");
if (ssd_1306) {
device_open(ssd_1306, 0);
}
ssd1306_write_byte(0xAE, SSD1306_CMD); //--turn off oled panel
ssd1306_write_byte(0x00, SSD1306_CMD); //---set low column address
ssd1306_write_byte(0x10, SSD1306_CMD); //---set high column address
ssd1306_write_byte(0x40, SSD1306_CMD); //--set start line address Set Mapping RAM Display Start Line (0x00~0x3F)
ssd1306_write_byte(0x81, SSD1306_CMD); //--set contrast control register
ssd1306_write_byte(0xCF, SSD1306_CMD); // Set SEG Output Current Brightness
ssd1306_write_byte(0xA1, SSD1306_CMD); //--Set SEG/Column Mapping
ssd1306_write_byte(0xC0, SSD1306_CMD); //Set COM/Row Scan Direction
ssd1306_write_byte(0xA6, SSD1306_CMD); //--set normal display
ssd1306_write_byte(0xA8, SSD1306_CMD); //--set multiplex ratio(1 to 64)
ssd1306_write_byte(0x3f, SSD1306_CMD); //--1/64 duty
ssd1306_write_byte(0xD3, SSD1306_CMD); //-set display offset Shift Mapping RAM Counter (0x00~0x3F)
ssd1306_write_byte(0x00, SSD1306_CMD); //-not offset
ssd1306_write_byte(0xd5, SSD1306_CMD); //--set display clock divide ratio/oscillator frequency
ssd1306_write_byte(0x80, SSD1306_CMD); //--set divide ratio, Set Clock as 100 Frames/Sec
ssd1306_write_byte(0xD9, SSD1306_CMD); //--set pre-charge period
ssd1306_write_byte(0xF1, SSD1306_CMD); //Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
ssd1306_write_byte(0xDA, SSD1306_CMD); //--set com pins hardware configuration
ssd1306_write_byte(0x12, SSD1306_CMD);
ssd1306_write_byte(0xDB, SSD1306_CMD); //--set vcomh
ssd1306_write_byte(0x40, SSD1306_CMD); //Set VCOM Deselect Level
ssd1306_write_byte(0x20, SSD1306_CMD); //-Set Page Addressing Mode (0x00/0x01/0x02)
ssd1306_write_byte(0x02, SSD1306_CMD); //
ssd1306_write_byte(0x8D, SSD1306_CMD); //--set Charge Pump enable/disable
ssd1306_write_byte(0x14, SSD1306_CMD); //--set(0x10) disable
ssd1306_write_byte(0xA4, SSD1306_CMD); // Disable Entire Display On (0xa4/0xa5)
ssd1306_write_byte(0xA6, SSD1306_CMD); // Disable Inverse Display On (0xa6/a7)
ssd1306_write_byte(0xAF, SSD1306_CMD); //--turn on oled panel
ssd1306_display_on();
ssd1306_clear_screen(0xff);
#else
gpio_set_mode(OLED_CS_PIN, GPIO_OUTPUT_MODE);
gpio_set_mode(OLED_DC_PIN, GPIO_OUTPUT_MODE);
gpio_set_mode(OLED_RES_PIN, GPIO_OUTPUT_MODE);
gpio_write(OLED_CS_PIN, 1); //CS1
gpio_write(OLED_DC_PIN, 1); //DC
spi_register(SPI0_INDEX, "lcd_dev_ifs");
ssd_1306 = device_find("lcd_dev_ifs");
if (ssd_1306) {
device_open(ssd_1306, DEVICE_OFLAG_STREAM_TX | DEVICE_OFLAG_STREAM_RX);
}
CS1_HIGH;
DC_HIGH;
RES_LOW;
bflb_platform_delay_ms(100);
RES_HIGH;
ssd1306_write_byte(0xAE, SSD1306_CMD);
ssd1306_write_byte(0xD5, SSD1306_CMD);
ssd1306_write_byte(0x50, SSD1306_CMD);
ssd1306_write_byte(0xA8, SSD1306_CMD);
ssd1306_write_byte(0x3F, SSD1306_CMD);
ssd1306_write_byte(0xD3, SSD1306_CMD);
ssd1306_write_byte(0x00, SSD1306_CMD);
ssd1306_write_byte(0x40, SSD1306_CMD);
ssd1306_write_byte(0x8D, SSD1306_CMD);
ssd1306_write_byte(0x14, SSD1306_CMD);
ssd1306_write_byte(0x20, SSD1306_CMD);
ssd1306_write_byte(0x02, SSD1306_CMD);
ssd1306_write_byte(0xA1, SSD1306_CMD);
ssd1306_write_byte(0xC0, SSD1306_CMD);
ssd1306_write_byte(0xDA, SSD1306_CMD);
ssd1306_write_byte(0x12, SSD1306_CMD);
ssd1306_write_byte(0x81, SSD1306_CMD);
ssd1306_write_byte(0xEF, SSD1306_CMD);
ssd1306_write_byte(0xD9, SSD1306_CMD);
ssd1306_write_byte(0xF1, SSD1306_CMD);
ssd1306_write_byte(0xDB, SSD1306_CMD);
ssd1306_write_byte(0x30, SSD1306_CMD);
ssd1306_write_byte(0xA4, SSD1306_CMD);
ssd1306_write_byte(0xA6, SSD1306_CMD);
ssd1306_write_byte(0xAF, SSD1306_CMD);
ssd1306_clear_screen(0);
#endif
}
void ssd1306_display_on(void)
{
ssd1306_write_byte(0x8D, SSD1306_CMD);
ssd1306_write_byte(0x14, SSD1306_CMD);
ssd1306_write_byte(0xAF, SSD1306_CMD);
}
/**
* @brief OLED turns off
*
* @param None
*
* @retval None
**/
void ssd1306_display_off(void)
{
ssd1306_write_byte(0x8D, SSD1306_CMD);
ssd1306_write_byte(0x10, SSD1306_CMD);
ssd1306_write_byte(0xAE, SSD1306_CMD);
}
void ssd1306_refresh_gram(void)
{
uint8_t i, j;
for (i = 0; i < 8; i++) {
ssd1306_write_byte(0xB0 + i, SSD1306_CMD);
ssd1306_write_byte(0x00, SSD1306_CMD);
ssd1306_write_byte(0x10, SSD1306_CMD);
for (j = 0; j < 128; j++) {
ssd1306_write_byte(OLED_GRAM[j][i], SSD1306_DAT);
}
}
}
void ssd1306_clear_screen(uint8_t fill)
{
memset(OLED_GRAM, fill, sizeof(OLED_GRAM));
ssd1306_refresh_gram();
}
/**
* @brief Draws a piont on the screen
*
* @param x: Specifies the X position
* @param y: Specifies the Y position
* @param mode: 0: the point turns off 1: the piont turns on
*
* @retval None
**/
void ssd1306_draw_point(uint8_t x, uint8_t y, uint8_t mode)
{
uint8_t i, j, temp;
if (x > 127 || y > 63)
return;
i = 7 - y / 8;
j = y % 8;
temp = 0x01 << (7 - j);
if (mode == 0)
OLED_GRAM[x][i] &= ~temp;
else
OLED_GRAM[x][i] |= temp;
}
/**
* @brief Displays one character at the specified position
*
* @param x: Specifies the X position
* @param y: Specifies the Y position
* @param size:
* @param mode
* @retval
**/
void ssd1306_display_char(uint8_t x, uint8_t y, uint8_t chr, uint8_t size, uint8_t mode)
{
uint8_t temp, t, t1;
uint8_t y0 = y;
uint8_t csize = (size / 8 + ((size % 8) ? 1 : 0)) * (size / 2);
chr = chr - ' ';
for (t = 0; t < csize; t++) {
switch (size) {
case 12:
temp = asc2_1206[chr][t];
break;
case 16:
temp = asc2_1608[chr][t];
break;
case 24:
temp = asc2_2412[chr][t];
break;
default:
return;
}
for (t1 = 0; t1 < 8; t1++) {
if (temp & 0x80)
ssd1306_draw_point(x, y, mode);
else
ssd1306_draw_point(x, y, !mode);
temp <<= 1;
y++;
if ((y - y0) == size) {
y = y0;
x++;
break;
}
}
}
}
/**
* @brief Displays a string on the screen
*
* @param x: Specifies the X position
* @param y: Specifies the Y position
* @param string: Pointer to a string to display on the screen
*
* @retval None
**/
void ssd1306_display_string(uint8_t x, uint8_t y, const char *string, uint8_t size, uint8_t mode)
{
while (*string != '\0') {
if (x > (SSD1306_WIDTH - size / 2)) {
x = 0;
y += size;
if (y > (SSD1306_HEIGHT - size)) {
y = x = 0;
ssd1306_clear_screen(0x00);
}
}
ssd1306_display_char(x, y, *string, size, mode);
x += size / 2;
string++;
}
}
void ssd1306_display_chinese(uint8_t x, uint8_t y, uint8_t no, uint8_t mode)
{
uint8_t temp1;
uint8_t temp2;
uint8_t t1, t2;
uint8_t x0 = x, y0 = y;
for (t1 = 0; t1 < 16; t1++) {
temp1 = Hzk[2 * no][t1];
for (t2 = 0; t2 < 8; t2++) {
if (temp1 & 0x01)
ssd1306_draw_point(x, y, mode);
else
ssd1306_draw_point(x, y, !mode);
temp1 >>= 1;
y++;
}
y = y0;
x++;
}
x = x0;
y = y0 + 8;
y0 = y;
for (t1 = 0; t1 < 16; t1++) {
temp2 = Hzk[2 * no + 1][t1];
for (t2 = 0; t2 < 8; t2++) {
if (temp2 & 0x01)
ssd1306_draw_point(x, y, mode);
else
ssd1306_draw_point(x, y, !mode);
temp2 >>= 1;
y++;
}
y = y0;
x++;
}
}
void ssd1306_draw_bmp(uint8_t x, uint8_t y, const unsigned char *image, uint8_t index, uint8_t mode)
{
uint8_t temp, t1;
uint16_t i;
uint8_t y0 = y;
for (i = 0; i < 1024; i++) {
temp = image[1024 * index + i];
for (t1 = 0; t1 < 8; t1++) {
if (temp & 0x80)
ssd1306_draw_point(x, y, mode);
else
ssd1306_draw_point(x, y, !mode);
temp <<= 1;
y++;
if ((y - y0) == 64) {
y = y0;
x++;
break;
}
}
}
}
void ssd1306_draw_alpha(uint8_t x, uint8_t y, const unsigned char *image, uint8_t index, uint8_t mode)
{
uint8_t temp, t1;
uint16_t i;
uint8_t y0 = y;
for (i = 0; i < 1024; i++) {
temp = image[1024 * index + i];
for (t1 = 0; t1 < 8; t1++) {
if (temp & 0x80)
ssd1306_draw_point(x, y, mode);
temp <<= 1;
y++;
if ((y - y0) == 64) {
y = y0;
x++;
break;
}
}
}
}
/**
* @brief Fills a rectangle
*
* @param x1: Specifies the X position 1 (X top left position)
* @param y1: Specifies the Y position 1 (Y top left position)
* @param x2: Specifies the X position 2 (X bottom right position)
* @param y3: Specifies the Y position 2 (Y bottom right position)
*
* @retval
**/
void ssd1306_fill_screen(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, uint8_t chDot)
{
uint8_t x, y;
for (x = x1; x <= x2; x++) {
for (y = y1; y <= y2; y++) {
ssd1306_draw_point(x, y, chDot);
}
}
ssd1306_refresh_gram();
}