linux-embedded-examples/ssd1306/ssd1306.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));
}