/**********************************************************************
|
* Copyright: (C)2021 LingYun IoT System Studio <www.weike-iot.com>
|
* Author: GuoWenxue<guowenxue@gmail.com> QQ: 281143292
|
* Description: BearKE1 NB-IoT Board OLED Hardware Abstract Layer source code
|
*
|
* ChangeLog:
|
* Version Date Author Description
|
* V1.0.0 2021.08.10 GuoWenxue Release initial version
|
***********************************************************************/
|
|
#include "hal_oled.h"
|
#include "font_ascii.h"
|
|
enum
|
{
|
OLED_CMD = 0,
|
OLED_DATA,
|
};
|
|
/*
|
*+-------------------------------------------------+
|
*| GPIO simulate I2C for OLED function API |
|
*+-------------------------------------------------+
|
*/
|
|
#define CONFIG_OLED_USE_GPIO_I2C /* use GPIO simulate I2C API */
|
|
typedef struct i2c_gpio_s
|
{
|
GPIO_TypeDef *group;
|
uint16_t scl; /* SCL */
|
uint16_t sda; /* SDA */
|
} i2c_gpio_t;
|
|
/* OLED I2C interface connected pins */
|
static i2c_gpio_t oled_i2c =
|
{
|
.group = GPIOB,
|
.scl = GPIO_PIN_8, /* SCL Pin: PB8 */
|
.sda = GPIO_PIN_9, /* SDA Pin: PB9 */
|
};
|
|
#define OLED_IIC_GPIO_Init() \
|
{ GPIO_InitTypeDef GPIO_InitStruct = {0}; \
|
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; \
|
GPIO_InitStruct.Pull = GPIO_PULLUP; \
|
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; \
|
GPIO_InitStruct.Pin = oled_i2c.sda; \
|
HAL_GPIO_Init(oled_i2c.group, &GPIO_InitStruct); \
|
GPIO_InitStruct.Pin = oled_i2c.scl; \
|
HAL_GPIO_Init(oled_i2c.group, &GPIO_InitStruct); \
|
}
|
|
#define OLED_SCL_H() HAL_GPIO_WritePin(oled_i2c.group, oled_i2c.scl, GPIO_PIN_SET)
|
#define OLED_SCL_L() HAL_GPIO_WritePin(oled_i2c.group, oled_i2c.scl, GPIO_PIN_RESET)
|
#define OLED_SDA_H() HAL_GPIO_WritePin(oled_i2c.group, oled_i2c.sda, GPIO_PIN_SET)
|
#define OLED_SDA_L() HAL_GPIO_WritePin(oled_i2c.group, oled_i2c.sda, GPIO_PIN_RESET)
|
|
|
/* StartCondition(S) */
|
void IIC_Start(void)
|
{
|
/* StartCondition(S): A high to low transition on the SDA line while SCL is high.
|
_______
|
SCL: |___
|
_____
|
SDA: |_____
|
*/
|
OLED_SCL_H();
|
OLED_SDA_H();
|
OLED_SDA_L();
|
OLED_SCL_L();
|
}
|
|
/* StopCondition(P) */
|
void IIC_Stop(void)
|
{
|
/* StopCondition(P): A low to high transition on the SDA line while SCL is high.
|
_____
|
SCL: ___|
|
_____
|
SDA: _____|
|
*/
|
OLED_SCL_H();
|
OLED_SDA_L();
|
OLED_SDA_H();
|
}
|
|
void Write_IIC_Byte(uint8_t byte)
|
{
|
uint8_t i;
|
uint8_t dat;
|
|
dat=byte;
|
|
/* Data line changes must happened when SCL is low */
|
OLED_SCL_L();
|
|
/* 1Byte=8bit, MSB send: bit[7]-->bit[0] */
|
for(i=0; i<8; i++)
|
{
|
if( dat&0x80 )
|
OLED_SDA_H();
|
else
|
OLED_SDA_L();
|
|
OLED_SCL_H();
|
OLED_SCL_L();
|
|
/* prepare for next bit */
|
dat=dat<<1;
|
}
|
|
/* clk #9 for ACK but don't care it */
|
OLED_SCL_H();
|
OLED_SCL_L();
|
}
|
|
static void IIC_Write_Command(uint8_t command)
|
{
|
/* Send I2C start signal */
|
IIC_Start();
|
|
/* Send OLED I2C slave write address, SA0=0, R/W#=0 */
|
Write_IIC_Byte(OLED_I2CWR_ADDR);
|
|
/* send command value */
|
Write_IIC_Byte(0x00);
|
Write_IIC_Byte(command);
|
|
/* Send I2C stop signal */
|
IIC_Stop();
|
}
|
|
static void IIC_Write_Data(uint8_t data)
|
{
|
/* Send I2C start signal */
|
IIC_Start();
|
|
/* Send OLED I2C slave write address, SA0=0, R/W#=0 */
|
Write_IIC_Byte(OLED_I2CWR_ADDR);
|
|
/* send data value */
|
Write_IIC_Byte(0x40);
|
Write_IIC_Byte(data);
|
|
/* Send I2C stop signal */
|
IIC_Stop();
|
}
|
|
|
/* OLED write a byte command data or command */
|
void OLED_WR_Byte(uint8_t data, uint8_t type)
|
{
|
if( OLED_CMD==type )
|
{
|
IIC_Write_Command(data);
|
}
|
else
|
{
|
IIC_Write_Data(data);
|
}
|
}
|
|
/*
|
*+-------------------------------------------------+
|
*| OLED initial/control function API |
|
*+-------------------------------------------------+
|
*/
|
|
/* Turn OLED display onʾ */
|
void OLED_Display_On(void)
|
{
|
OLED_WR_Byte(0X8D, OLED_CMD); //SET DCDC command
|
OLED_WR_Byte(0X14, OLED_CMD); //DCDC ON
|
OLED_WR_Byte(0XAF, OLED_CMD); //DISPLAY ON
|
}
|
|
/* Turn OLED display off */
|
void OLED_Display_Off(void)
|
{
|
OLED_WR_Byte(0X8D, OLED_CMD); //SET DCDC command
|
OLED_WR_Byte(0X10, OLED_CMD); //DCDC OFF
|
OLED_WR_Byte(0XAE, OLED_CMD); //DISPLAY OFF
|
}
|
|
/* Clear OLED, it will be black */
|
void OLED_Clear(void)
|
{
|
uint8_t i, j;
|
|
/* update display */
|
for(i=0;i<8;i++)
|
{
|
OLED_WR_Byte (0xb0+i, OLED_CMD); // set page address: 0~7
|
OLED_WR_Byte (0x00, OLED_CMD); // set display address, column address lower bytes;ַ
|
OLED_WR_Byte (0x10, OLED_CMD); // set display address, column address higher bytes;
|
|
for(j=0; j<128; j++)
|
OLED_WR_Byte(0, OLED_DATA);
|
}
|
|
OLED_Set_Pos(0, 0);
|
}
|
|
void OLED_On(void)
|
{
|
uint8_t i, j;
|
|
/* update display */
|
for(i=0; i<8; i++)
|
{
|
OLED_WR_Byte (0xb0+i, OLED_CMD); // set page address: 0~7
|
OLED_WR_Byte (0x00, OLED_CMD); // set display address, row address lower bytes;ַ
|
OLED_WR_Byte (0x10, OLED_CMD); // set display address, row address higher bytes;
|
|
for(j=0; j<128; j++)
|
OLED_WR_Byte(1, OLED_DATA);
|
}
|
}
|
|
void OLED_Init(void)
|
{
|
#ifdef CONFIG_OLED_USE_GPIO_I2C
|
OLED_IIC_GPIO_Init(); /* initial GPIO status for I2C pins */
|
#endif
|
|
HAL_Delay(200);
|
|
OLED_WR_Byte(0xAE,OLED_CMD); // Disable
|
|
OLED_WR_Byte(0x40,OLED_CMD); //---set low column address
|
OLED_WR_Byte(0xB0,OLED_CMD); //---set high column address
|
|
OLED_WR_Byte(0xC8,OLED_CMD);
|
|
OLED_WR_Byte(0x81,OLED_CMD);
|
OLED_WR_Byte(0xff,OLED_CMD);
|
|
OLED_WR_Byte(0xa1,OLED_CMD);
|
|
OLED_WR_Byte(0xa6,OLED_CMD);
|
|
OLED_WR_Byte(0xa8,OLED_CMD);
|
OLED_WR_Byte(0x1f,OLED_CMD);
|
|
OLED_WR_Byte(0xd3,OLED_CMD);
|
OLED_WR_Byte(0x00,OLED_CMD);
|
|
OLED_WR_Byte(0xd5,OLED_CMD);
|
OLED_WR_Byte(0xf0,OLED_CMD);
|
|
OLED_WR_Byte(0xd9,OLED_CMD);
|
OLED_WR_Byte(0x22,OLED_CMD);
|
|
OLED_WR_Byte(0xda,OLED_CMD);
|
OLED_WR_Byte(0x02,OLED_CMD);
|
|
OLED_WR_Byte(0xdb,OLED_CMD);
|
OLED_WR_Byte(0x49,OLED_CMD);
|
|
OLED_WR_Byte(0x8d,OLED_CMD);
|
OLED_WR_Byte(0x14,OLED_CMD);
|
|
OLED_WR_Byte(0xaf,OLED_CMD);
|
|
OLED_Clear();
|
}
|
|
/*
|
*+-------------------------------------------------+
|
*| OLED display function API |
|
*+-------------------------------------------------+
|
*/
|
|
/* set OLED display position */
|
void OLED_Set_Pos(uint8_t x, uint8_t y)
|
{
|
OLED_WR_Byte(0xb0+y, OLED_CMD);
|
OLED_WR_Byte(((x&0xf0)>>4)|0x10, OLED_CMD);
|
OLED_WR_Byte((x&0x0f), OLED_CMD);
|
}
|
|
/* show a character on OLED as $Char_Size */
|
void OLED_ShowChar(uint8_t x, uint8_t y, uint8_t chr, uint8_t char_Size)
|
{
|
uint8_t c=0,i=0;
|
|
c=chr-' '; // get offset value
|
|
if( x>X_WIDTH-1 )
|
{
|
x=0;
|
y=y+2;
|
}
|
|
if(char_Size ==16)
|
{
|
OLED_Set_Pos(x,y);
|
|
for(i=0; i<8; i++)
|
OLED_WR_Byte(F8X16[c*16+i],OLED_DATA);
|
|
OLED_Set_Pos(x,y+1);
|
|
for(i=0;i<8;i++)
|
OLED_WR_Byte(F8X16[c*16+i+8],OLED_DATA);
|
}
|
else
|
{
|
OLED_Set_Pos(x,y);
|
for(i=0;i<6;i++)
|
OLED_WR_Byte(F6x8[c][i],OLED_DATA);
|
}
|
}
|
|
/* show a string on OLED */
|
void OLED_ShowString(uint8_t x, uint8_t y, char *chr, uint8_t font_size)
|
{
|
uint8_t j=0;
|
|
while( chr[j]!='\0' )
|
{
|
OLED_ShowChar(x, y, chr[j], font_size);
|
|
x+=8;
|
|
if(x>120)
|
{
|
x=0;
|
y+=2;
|
}
|
|
j++;
|
}
|
}
|
|
/* Show Chinese on OLED */
|
void OLED_ShowChinese(uint8_t (*Hzk)[32], uint8_t x, uint8_t y, uint8_t no)
|
{
|
uint8_t t,adder=0;
|
|
OLED_Set_Pos(x, y);
|
for(t=0;t<16;t++)
|
{
|
OLED_WR_Byte(Hzk[2*no][t],OLED_DATA);
|
adder+=1;
|
}
|
|
OLED_Set_Pos(x,y+1);
|
for(t=0;t<16;t++)
|
{
|
OLED_WR_Byte(Hzk[2*no+1][t],OLED_DATA);
|
adder+=1;
|
}
|
}
|
|
/* Show BMP images(128x64) on OLED, x: 0~127 y:0~7 */
|
void OLED_DrawBMP(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t *BMP)
|
{
|
uint32_t j=0;
|
uint8_t x,y;
|
|
if( y1%8==0 )
|
y = y1/8;
|
else
|
y = y1/8+1;
|
|
for(y=y0; y<y1; y++)
|
{
|
OLED_Set_Pos(x0, y);
|
for(x=x0;x<x1;x++)
|
{
|
OLED_WR_Byte(BMP[j++],OLED_DATA);
|
}
|
}
|
}
|