227 lines
4.8 KiB
C
227 lines
4.8 KiB
C
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <unistd.h>
|
||
|
#include <sys/wait.h>
|
||
|
#include <stdint.h>
|
||
|
#include <string.h>
|
||
|
#include <sys/time.h>
|
||
|
#include <unistd.h>
|
||
|
|
||
|
#include "libsoc_spi.h"
|
||
|
#include "libsoc_gpio.h"
|
||
|
#include "ssd1306.h"
|
||
|
|
||
|
#define width 128
|
||
|
#define height 64
|
||
|
#define pages 8
|
||
|
|
||
|
void command(ssd1306 *oled, char cmd)
|
||
|
{
|
||
|
uint8_t command[1] = {0};
|
||
|
|
||
|
command[0] = cmd;
|
||
|
libsoc_gpio_set_level(oled->dc, LOW);
|
||
|
libsoc_spi_write(oled->spi_dev, command, 1);
|
||
|
}
|
||
|
|
||
|
void SSD1306_begin(ssd1306 *oled)
|
||
|
{
|
||
|
libsoc_gpio_set_level(oled->res, HIGH);
|
||
|
usleep(1000);
|
||
|
libsoc_gpio_set_level(oled->res, LOW);
|
||
|
usleep(1000);
|
||
|
libsoc_gpio_set_level(oled->res, HIGH);
|
||
|
|
||
|
command(oled, SSD1306_DISPLAYOFF);
|
||
|
command(oled, SSD1306_SETDISPLAYCLOCKDIV);
|
||
|
command(oled, 0x80); /* the suggested ratio 0x80 */
|
||
|
|
||
|
command(oled, SSD1306_SETMULTIPLEX);
|
||
|
command(oled, 0x3F);
|
||
|
command(oled, SSD1306_SETDISPLAYOFFSET);
|
||
|
command(oled, 0x0); /* no offset */
|
||
|
command(oled, SSD1306_SETSTARTLINE | 0x0); /* line #0 */
|
||
|
command(oled, SSD1306_CHARGEPUMP);
|
||
|
command(oled, (oled->switch_capvcc == SSD1306_EXTERNALVCC) ? 0x10 : 0x14);
|
||
|
|
||
|
command(oled, SSD1306_MEMORYMODE);
|
||
|
command(oled, 0x00); /* 0x0 act like ks0108 */
|
||
|
|
||
|
command(oled, SSD1306_SEGREMAP | 0x1);
|
||
|
command(oled, SSD1306_COMSCANDEC);
|
||
|
command(oled, SSD1306_SETCOMPINS);
|
||
|
command(oled, 0x12); /* TODO - calculate based on _rawHieght ? */
|
||
|
command(oled, SSD1306_SETCONTRAST);
|
||
|
command(oled, (oled->switch_capvcc == SSD1306_EXTERNALVCC) ? 0x9F : 0xCF);
|
||
|
command(oled, SSD1306_SETPRECHARGE);
|
||
|
command(oled, (oled->switch_capvcc == SSD1306_EXTERNALVCC) ? 0x22 : 0xF1);
|
||
|
command(oled, SSD1306_SETVCOMDETECT);
|
||
|
command(oled, 0x40);
|
||
|
command(oled, SSD1306_DISPLAYALLON_RESUME);
|
||
|
command(oled, SSD1306_NORMALDISPLAY);
|
||
|
command(oled, SSD1306_DISPLAYON);
|
||
|
}
|
||
|
|
||
|
void SSD1306_clear(ssd1306 *oled)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
for(i = 0; i < sizeof(oled->buffer); i++) {
|
||
|
oled->buffer[i] = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void SSD1306_pixel(ssd1306 *oled,
|
||
|
int x,
|
||
|
int y,
|
||
|
char color)
|
||
|
{
|
||
|
if (x > width || y > height)
|
||
|
return ;
|
||
|
|
||
|
if (color)
|
||
|
oled->buffer[x+(y/8)*width] |= 1<<(y%8);
|
||
|
else
|
||
|
oled->buffer[x+(y/8)*width] &= ~(1<<(y%8));
|
||
|
}
|
||
|
|
||
|
void SSD1306_char1616(ssd1306 *oled,
|
||
|
uint8_t x,
|
||
|
uint8_t y,
|
||
|
uint8_t chChar)
|
||
|
{
|
||
|
uint8_t i, j;
|
||
|
uint8_t chTemp = 0, y0 = y, chMode = 0;
|
||
|
|
||
|
for (i = 0; i < 32; i ++) {
|
||
|
chTemp = Font1612[chChar - 0x30][i];
|
||
|
for (j = 0; j < 8; j ++) {
|
||
|
chMode = chTemp & 0x80? 1 : 0;
|
||
|
SSD1306_pixel(oled, x, y, chMode);
|
||
|
chTemp <<= 1;
|
||
|
y ++;
|
||
|
if ((y - y0) == 16) {
|
||
|
y = y0;
|
||
|
x ++;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void SSD1306_char3216(ssd1306 *oled,
|
||
|
uint8_t x,
|
||
|
uint8_t y,
|
||
|
uint8_t chChar)
|
||
|
{
|
||
|
uint8_t i, j;
|
||
|
uint8_t chTemp = 0, y0 = y, chMode = 0;
|
||
|
|
||
|
for (i = 0; i < 64; i ++) {
|
||
|
chTemp = Font3216[chChar - 0x30][i];
|
||
|
for (j = 0; j < 8; j ++) {
|
||
|
chMode = chTemp & 0x80 ? 1 : 0;
|
||
|
SSD1306_pixel(oled, x, y, chMode);
|
||
|
chTemp <<= 1;
|
||
|
y ++;
|
||
|
if ((y - y0) == 32) {
|
||
|
y = y0;
|
||
|
x ++;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void SSD1306_char(ssd1306 *oled,
|
||
|
unsigned char x,
|
||
|
unsigned char y,
|
||
|
char acsii,
|
||
|
char size,
|
||
|
char mode)
|
||
|
{
|
||
|
char temp;
|
||
|
unsigned char i, j, y0 = y;
|
||
|
unsigned char ch = acsii - ' ';
|
||
|
|
||
|
for(i = 0; i < size; i++) {
|
||
|
if (size == 12) {
|
||
|
if (mode)temp = Font1206[ch][i];
|
||
|
else temp = ~Font1206[ch][i];
|
||
|
} else {
|
||
|
if (mode)
|
||
|
temp = Font1608[ch][i];
|
||
|
else
|
||
|
temp = ~Font1608[ch][i];
|
||
|
}
|
||
|
for(j = 0; j < 8; j++) {
|
||
|
if (temp & 0x80)
|
||
|
SSD1306_pixel(oled, x, y, 1);
|
||
|
else
|
||
|
SSD1306_pixel(oled, x, y, 0);
|
||
|
|
||
|
temp <<= 1;
|
||
|
y++;
|
||
|
|
||
|
if ((y - y0) == size) {
|
||
|
y = y0;
|
||
|
x++;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void SSD1306_string(ssd1306 *oled,
|
||
|
uint8_t x,
|
||
|
uint8_t y,
|
||
|
const char *pString,
|
||
|
uint8_t Size,
|
||
|
uint8_t Mode)
|
||
|
{
|
||
|
while (*pString != '\0') {
|
||
|
if (x > (width - Size / 2)) {
|
||
|
x = 0;
|
||
|
y += Size;
|
||
|
if (y > (height - Size)) {
|
||
|
y = x = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
SSD1306_char(oled, x, y, *pString, Size, Mode);
|
||
|
x += Size / 2;
|
||
|
pString ++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void SSD1306_bitmap(ssd1306 *oled,
|
||
|
unsigned char x,
|
||
|
unsigned char y,
|
||
|
const unsigned char *pBmp,
|
||
|
char chWidth,
|
||
|
char chHeight)
|
||
|
{
|
||
|
unsigned char i, j, byteWidth = (chWidth + 7) / 8;
|
||
|
|
||
|
for (j = 0; j < chHeight; j++) {
|
||
|
for (i = 0; i < chWidth; i ++) {
|
||
|
if (*(pBmp + j * byteWidth + i / 8) & (128 >> (i & 7)))
|
||
|
SSD1306_pixel(oled, x + i, y + j, 1);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void SSD1306_display(ssd1306 *oled)
|
||
|
{
|
||
|
command(oled, SSD1306_COLUMNADDR);
|
||
|
command(oled, 0); /* cloumn start address */
|
||
|
command(oled, width - 1); /*cloumn end address */
|
||
|
command(oled, SSD1306_PAGEADDR);
|
||
|
command(oled, 0); /* page atart address */
|
||
|
command(oled, pages - 1); /* page end address */
|
||
|
|
||
|
libsoc_gpio_set_level(oled->dc, HIGH);
|
||
|
/* TODO: get the correct size of buf */
|
||
|
libsoc_spi_write(oled->spi_dev, oled->buffer, sizeof(oled->buffer));
|
||
|
}
|