1
0

first time code commit

This commit is contained in:
armlabs 2020-02-13 10:55:42 +08:00 committed by GitHub
parent 591e6e8625
commit e672704de6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 1198 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*.o
ssd1306_bin

15
Makefile Normal file
View File

@ -0,0 +1,15 @@
CC=gcc
CFLAGS=-I ./
LDFLAGS=-static
OBJS=main.o ssd1306.o linux_i2c.o
BIN=ssd1306_bin
%.o:%.c
$(CC) -c -o $@ $< $(CFLAGS)
$(BIN):$(OBJS)
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LDFLAGS)
clean:
rm -f ./*.o $(BIN)

118
Readme.md Normal file
View File

@ -0,0 +1,118 @@
# OLED SSD1306 Linux driver
This is plain c code using linux I2C device node (/dev/i2c-X X for 0,1,2,3...).
Please make sure the linux has run "modprobe i2c-dev".
128x64 and 128x32 are supporting and using I2C interface ONLY
## Files
**linux_i2c.c** source code for i2c control in linux device node.
**linux_i2c.h** header file for i2c control in linux.
**ssd1306.c** i2c protocol functions to control oled SSD1306.
**ssd1306.h** header file for i2c protocol functions and defined commands in SSD1306.
**font.h** font header file define 5x7 small font and 8x8 normal font. ascii value from 0x20(SPACE) to 0x7e(~).
**main.c** main file to take params and control oled SSD1306.
**Makefile** plain Makefile to build the source code. It works in raspberry pi.
**Readme.md** this readme file.
## How to compile
Require make and gcc. If you use cross compile, please self define $(CC).
Type "make" to build binary "ssd1306_bin".
Type "make clean" to clean the project.
## How to use
- always init oled module ONCE when power up.
- set the device node address EVERYTIME if not using default value /dev/i2c-0
- the init oled module always reset XY cursor to (0,0)
- all params can set together
- clear screen if new text need to write, otherwise wording overlapping happened
- resolution value stored in /tmp/.ssd1306_oled_type with format like "128x64" or "128x32" or "64x48"
- always do display rotation first and then filling text. otherwise the text cause mirror
- make sure the XY cursor setting in correct location before printing text
### Params
```sh
-I init oled (128x32 or 128x64 or 64x48)
-c clear (line number or all)
-d 0/display off 1/display on
-f 0/small font 5x7 1/normal font 8x8 (default small font)
-h help message
-i 0/normal oled 1/invert oled
-l put your line to display
-m put your strings to oled
-n I2C device node address (0,1,2..., default 0)
-r 0/normal 180/rotate
-x x position
-y y position
```
## Example
### init the OLED once
- resolution 128x64
```sh
$ ./ssd1306_bin -I 128x64
```
- resolution 128x32
```sh
$ ./ssd1306_bin -I 128x32
```
- resolution 64x48
```sh
$ ./ssd1306_bin -I 64x48
```
### clear display
- clear 1st line
```sh
./ssd1306_bin -c 0
```
- clear 2nd line
```sh
$ ./ssd1306_bin -c 1
```
- clear 4th line
```sh
$ ./ssd1306_bin -c 3
```
- clear whole screen
```sh
$ ./ssd1306_bin -c
```
### display on/off
- turn off display
```sh
$ ./ssd1306_bin -d 0
```
- turn on display
```sh
$ ./ssd1306_bin -d 1
```
### inverting display
- normal oled (0 is off, 1 is on)
```sh
$ ./ssd1306_bin -i 0
```
- invert oled (0 is on, 1 is off)
```sh
$ ./ssd1306_bin -i 1
```
### print words
- write line "Hello World"
```sh
$ ./ssd1306_bin -l "Hello World"
```
- write message "alpha\nbravo\ncharlie\ndelta" (please place \n for next line)
```sh
$ ./ssd1306_bin -m "alpha\nbravo\ncharlie\ndelta"
```
### I2C device address (default is /dev/i2c-0)
- using /dev/i2c-1
```sh
$ ./ssd1306_bin -n 1
```
### rotate display
- normal orientation
```sh
$ ./ssd1306_bin -r 0
```
- turn 180 orientation
```sh
$ ./ssd1306_bin -r 180
```
### set cursor location
- set XY cursor 8,1(x is column, 8 columns skipping, y is row, 2nd line)
```sh
$ ./ssd1306_bin -x 8 -y 1
```

213
font.h Normal file
View File

@ -0,0 +1,213 @@
#ifndef __FONT_H
#define __FONT_H
#include <stdint.h>
#include <inttypes.h>
const uint8_t font5x7[] = {
0x00, 0x00, 0x00, 0x00, 0x00, // SPACE
0x00, 0x00, 0x5F, 0x00, 0x00, // !
0x00, 0x03, 0x00, 0x03, 0x00, // "
0x14, 0x3E, 0x14, 0x3E, 0x14, // #
0x24, 0x2A, 0x7F, 0x2A, 0x12, // $
0x43, 0x33, 0x08, 0x66, 0x61, // %
0x36, 0x49, 0x55, 0x22, 0x50, // &
0x00, 0x05, 0x03, 0x00, 0x00, // '
0x00, 0x1C, 0x22, 0x41, 0x00, // (
0x00, 0x41, 0x22, 0x1C, 0x00, // )
0x14, 0x08, 0x3E, 0x08, 0x14, // *
0x08, 0x08, 0x3E, 0x08, 0x08, // +
0x00, 0x50, 0x30, 0x00, 0x00, // ,
0x08, 0x08, 0x08, 0x08, 0x08, // -
0x00, 0x60, 0x60, 0x00, 0x00, // .
0x20, 0x10, 0x08, 0x04, 0x02, // /
0x3E, 0x51, 0x49, 0x45, 0x3E, // 0
0x00, 0x04, 0x02, 0x7F, 0x00, // 1
0x42, 0x61, 0x51, 0x49, 0x46, // 2
0x22, 0x41, 0x49, 0x49, 0x36, // 3
0x18, 0x14, 0x12, 0x7F, 0x10, // 4
0x27, 0x45, 0x45, 0x45, 0x39, // 5
0x3E, 0x49, 0x49, 0x49, 0x32, // 6
0x01, 0x01, 0x71, 0x09, 0x07, // 7
0x36, 0x49, 0x49, 0x49, 0x36, // 8
0x26, 0x49, 0x49, 0x49, 0x3E, // 9
0x00, 0x36, 0x36, 0x00, 0x00, // :
0x00, 0x56, 0x36, 0x00, 0x00, // ;
0x08, 0x14, 0x22, 0x41, 0x00, // <
0x14, 0x14, 0x14, 0x14, 0x14, // =
0x00, 0x41, 0x22, 0x14, 0x08, // >
0x02, 0x01, 0x51, 0x09, 0x06, // ?
0x3E, 0x41, 0x59, 0x55, 0x5E, // @
0x7E, 0x09, 0x09, 0x09, 0x7E, // A
0x7F, 0x49, 0x49, 0x49, 0x36, // B
0x3E, 0x41, 0x41, 0x41, 0x22, // C
0x7F, 0x41, 0x41, 0x41, 0x3E, // D
0x7F, 0x49, 0x49, 0x49, 0x41, // E
0x7F, 0x09, 0x09, 0x09, 0x01, // F
0x3E, 0x41, 0x41, 0x49, 0x3A, // G
0x7F, 0x08, 0x08, 0x08, 0x7F, // H
0x00, 0x41, 0x7F, 0x41, 0x00, // I
0x30, 0x40, 0x40, 0x40, 0x3F, // J
0x7F, 0x08, 0x14, 0x22, 0x41, // K
0x7F, 0x40, 0x40, 0x40, 0x40, // L
0x7F, 0x02, 0x0C, 0x02, 0x7F, // M
0x7F, 0x02, 0x04, 0x08, 0x7F, // N
0x3E, 0x41, 0x41, 0x41, 0x3E, // O
0x7F, 0x09, 0x09, 0x09, 0x06, // P
0x1E, 0x21, 0x21, 0x21, 0x5E, // Q
0x7F, 0x09, 0x09, 0x09, 0x76, // R
0x26, 0x49, 0x49, 0x49, 0x32, // S
0x01, 0x01, 0x7F, 0x01, 0x01, // T
0x3F, 0x40, 0x40, 0x40, 0x3F, // U
0x1F, 0x20, 0x40, 0x20, 0x1F, // V
0x7F, 0x20, 0x10, 0x20, 0x7F, // W
0x41, 0x22, 0x1C, 0x22, 0x41, // X
0x07, 0x08, 0x70, 0x08, 0x07, // Y
0x61, 0x51, 0x49, 0x45, 0x43, // Z
0x00, 0x7F, 0x41, 0x00, 0x00, // [
0x02, 0x04, 0x08, 0x10, 0x20, // backslash
0x00, 0x00, 0x41, 0x7F, 0x00, // ]
0x04, 0x02, 0x01, 0x02, 0x04, // ^
0x40, 0x40, 0x40, 0x40, 0x40, // _
0x00, 0x01, 0x02, 0x04, 0x00, // `
0x20, 0x54, 0x54, 0x54, 0x78, // a
0x7F, 0x44, 0x44, 0x44, 0x38, // b
0x38, 0x44, 0x44, 0x44, 0x44, // c
0x38, 0x44, 0x44, 0x44, 0x7F, // d
0x38, 0x54, 0x54, 0x54, 0x18, // e
0x04, 0x04, 0x7E, 0x05, 0x05, // f
0x08, 0x54, 0x54, 0x54, 0x3C, // g
0x7F, 0x08, 0x04, 0x04, 0x78, // h
0x00, 0x44, 0x7D, 0x40, 0x00, // i
0x20, 0x40, 0x44, 0x3D, 0x00, // j
0x7F, 0x10, 0x28, 0x44, 0x00, // k
0x00, 0x41, 0x7F, 0x40, 0x00, // l
0x7C, 0x04, 0x78, 0x04, 0x78, // m
0x7C, 0x08, 0x04, 0x04, 0x78, // n
0x38, 0x44, 0x44, 0x44, 0x38, // o
0x7C, 0x14, 0x14, 0x14, 0x08, // p
0x08, 0x14, 0x14, 0x14, 0x7C, // q
0x00, 0x7C, 0x08, 0x04, 0x04, // r
0x48, 0x54, 0x54, 0x54, 0x20, // s
0x04, 0x04, 0x3F, 0x44, 0x44, // t
0x3C, 0x40, 0x40, 0x20, 0x7C, // u
0x1C, 0x20, 0x40, 0x20, 0x1C, // v
0x3C, 0x40, 0x30, 0x40, 0x3C, // w
0x44, 0x28, 0x10, 0x28, 0x44, // x
0x0C, 0x50, 0x50, 0x50, 0x3C, // y
0x44, 0x64, 0x54, 0x4C, 0x44, // z
0x00, 0x08, 0x36, 0x41, 0x41, // {
0x00, 0x00, 0x7F, 0x00, 0x00, // |
0x41, 0x41, 0x36, 0x08, 0x00, // }
0x02, 0x01, 0x02, 0x04, 0x02 // ~
};
const uint8_t font8x8[] = {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // <space>
0x00,0x00,0x00,0x00,0x5F,0x00,0x00,0x00, // !
0x00,0x00,0x00,0x03,0x00,0x03,0x00,0x00, // "
0x00,0x24,0x7E,0x24,0x24,0x7E,0x24,0x00, // #
0x00,0x2E,0x2A,0x7F,0x2A,0x3A,0x00,0x00, // $
0x00,0x46,0x26,0x10,0x08,0x64,0x62,0x00, // %
0x00,0x20,0x54,0x4A,0x54,0x20,0x50,0x00, // &
0x00,0x00,0x00,0x04,0x02,0x00,0x00,0x00, // '
0x00,0x00,0x00,0x3C,0x42,0x00,0x00,0x00, // (
0x00,0x00,0x00,0x42,0x3C,0x00,0x00,0x00, // )
0x00,0x10,0x54,0x38,0x54,0x10,0x00,0x00, // *
0x00,0x10,0x10,0x7C,0x10,0x10,0x00,0x00, // +
0x00,0x00,0x00,0x80,0x60,0x00,0x00,0x00, // ,
0x00,0x10,0x10,0x10,0x10,0x10,0x00,0x00, // -
0x00,0x00,0x00,0x60,0x60,0x00,0x00,0x00, // .
0x00,0x40,0x20,0x10,0x08,0x04,0x00,0x00, // /
0x3C,0x62,0x52,0x4A,0x46,0x3C,0x00,0x00, // 0
0x44,0x42,0x7E,0x40,0x40,0x00,0x00,0x00, // 1
0x64,0x52,0x52,0x52,0x52,0x4C,0x00,0x00, // 2
0x24,0x42,0x42,0x4A,0x4A,0x34,0x00,0x00, // 3
0x30,0x28,0x24,0x7E,0x20,0x20,0x00,0x00, // 4
0x2E,0x4A,0x4A,0x4A,0x4A,0x32,0x00,0x00, // 5
0x3C,0x4A,0x4A,0x4A,0x4A,0x30,0x00,0x00, // 6
0x02,0x02,0x62,0x12,0x0A,0x06,0x00,0x00, // 7
0x34,0x4A,0x4A,0x4A,0x4A,0x34,0x00,0x00, // 8
0x0C,0x52,0x52,0x52,0x52,0x3C,0x00,0x00, // 9
0x00,0x00,0x00,0x48,0x00,0x00,0x00,0x00, // :
0x00,0x00,0x80,0x64,0x00,0x00,0x00,0x00, // ;
0x00,0x00,0x10,0x28,0x44,0x00,0x00,0x00, // <
0x00,0x28,0x28,0x28,0x28,0x28,0x00,0x00, // =
0x00,0x00,0x44,0x28,0x10,0x00,0x00,0x00, // >
0x00,0x04,0x02,0x02,0x52,0x0A,0x04,0x00, // ?
0x00,0x3C,0x42,0x5A,0x56,0x5A,0x1C,0x00, // @
0x7C,0x12,0x12,0x12,0x12,0x7C,0x00,0x00, // A
0x7E,0x4A,0x4A,0x4A,0x4A,0x34,0x00,0x00, // B
0x3C,0x42,0x42,0x42,0x42,0x24,0x00,0x00, // C
0x7E,0x42,0x42,0x42,0x24,0x18,0x00,0x00, // D
0x7E,0x4A,0x4A,0x4A,0x4A,0x42,0x00,0x00, // E
0x7E,0x0A,0x0A,0x0A,0x0A,0x02,0x00,0x00, // F
0x3C,0x42,0x42,0x52,0x52,0x34,0x00,0x00, // G
0x7E,0x08,0x08,0x08,0x08,0x7E,0x00,0x00, // H
0x00,0x42,0x42,0x7E,0x42,0x42,0x00,0x00, // I
0x30,0x40,0x40,0x40,0x40,0x3E,0x00,0x00, // J
0x7E,0x08,0x08,0x14,0x22,0x40,0x00,0x00, // K
0x7E,0x40,0x40,0x40,0x40,0x40,0x00,0x00, // L
0x7E,0x04,0x08,0x08,0x04,0x7E,0x00,0x00, // M
0x7E,0x04,0x08,0x10,0x20,0x7E,0x00,0x00, // N
0x3C,0x42,0x42,0x42,0x42,0x3C,0x00,0x00, // O
0x7E,0x12,0x12,0x12,0x12,0x0C,0x00,0x00, // P
0x3C,0x42,0x52,0x62,0x42,0x3C,0x00,0x00, // Q
0x7E,0x12,0x12,0x12,0x32,0x4C,0x00,0x00, // R
0x24,0x4A,0x4A,0x4A,0x4A,0x30,0x00,0x00, // S
0x02,0x02,0x02,0x7E,0x02,0x02,0x02,0x00, // T
0x3E,0x40,0x40,0x40,0x40,0x3E,0x00,0x00, // U
0x1E,0x20,0x40,0x40,0x20,0x1E,0x00,0x00, // V
0x3E,0x40,0x20,0x20,0x40,0x3E,0x00,0x00, // W
0x42,0x24,0x18,0x18,0x24,0x42,0x00,0x00, // X
0x02,0x04,0x08,0x70,0x08,0x04,0x02,0x00, // Y
0x42,0x62,0x52,0x4A,0x46,0x42,0x00,0x00, // Z
0x00,0x00,0x7E,0x42,0x42,0x00,0x00,0x00, // [
0x00,0x04,0x08,0x10,0x20,0x40,0x00,0x00, // <backslash>
0x00,0x00,0x42,0x42,0x7E,0x00,0x00,0x00, // ]
0x00,0x08,0x04,0x7E,0x04,0x08,0x00,0x00, // ^
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00, // _
0x3C,0x42,0x99,0xA5,0xA5,0x81,0x42,0x3C, // `
0x00,0x20,0x54,0x54,0x54,0x78,0x00,0x00, // a
0x00,0x7E,0x48,0x48,0x48,0x30,0x00,0x00, // b
0x00,0x00,0x38,0x44,0x44,0x44,0x00,0x00, // c
0x00,0x30,0x48,0x48,0x48,0x7E,0x00,0x00, // d
0x00,0x38,0x54,0x54,0x54,0x48,0x00,0x00, // e
0x00,0x00,0x00,0x7C,0x0A,0x02,0x00,0x00, // f
0x00,0x18,0xA4,0xA4,0xA4,0xA4,0x7C,0x00, // g
0x00,0x7E,0x08,0x08,0x08,0x70,0x00,0x00, // h
0x00,0x00,0x00,0x48,0x7A,0x40,0x00,0x00, // i
0x00,0x00,0x40,0x80,0x80,0x7A,0x00,0x00, // j
0x00,0x7E,0x18,0x24,0x40,0x00,0x00,0x00, // k
0x00,0x00,0x00,0x3E,0x40,0x40,0x00,0x00, // l
0x00,0x7C,0x04,0x78,0x04,0x78,0x00,0x00, // m
0x00,0x7C,0x04,0x04,0x04,0x78,0x00,0x00, // n
0x00,0x38,0x44,0x44,0x44,0x38,0x00,0x00, // o
0x00,0xFC,0x24,0x24,0x24,0x18,0x00,0x00, // p
0x00,0x18,0x24,0x24,0x24,0xFC,0x80,0x00, // q
0x00,0x00,0x78,0x04,0x04,0x04,0x00,0x00, // r
0x00,0x48,0x54,0x54,0x54,0x20,0x00,0x00, // s
0x00,0x00,0x04,0x3E,0x44,0x40,0x00,0x00, // t
0x00,0x3C,0x40,0x40,0x40,0x3C,0x00,0x00, // u
0x00,0x0C,0x30,0x40,0x30,0x0C,0x00,0x00, // v
0x00,0x3C,0x40,0x38,0x40,0x3C,0x00,0x00, // w
0x00,0x44,0x28,0x10,0x28,0x44,0x00,0x00, // x
0x00,0x1C,0xA0,0xA0,0xA0,0x7C,0x00,0x00, // y
0x00,0x44,0x64,0x54,0x4C,0x44,0x00,0x00, // z
0x00,0x08,0x08,0x76,0x42,0x42,0x00,0x00, // {
0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x00, // |
0x00,0x42,0x42,0x76,0x08,0x08,0x00,0x00, // }
0x00,0x00,0x04,0x02,0x04,0x02,0x00,0x00 // ~
};
#endif

70
linux_i2c.c Normal file
View File

@ -0,0 +1,70 @@
#include <stdint.h>
#include <stdlib.h>
#include <inttypes.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/i2c-dev.h>
static int file_i2c = 0;
uint8_t _i2c_init(int i2c, int dev_addr)
{
if (file_i2c == 0)
{
char filename[32];
sprintf(filename, "/dev/i2c-%d", i2c); // I2C bus number passed
file_i2c = open(filename, O_RDWR);
if (file_i2c < 0)
{
file_i2c = 0;
return 1;
}
if (ioctl(file_i2c, I2C_SLAVE, dev_addr) < 0) // set slave address
{
close(file_i2c);
file_i2c = 0;
return 1;
}
return 0;
}
// assume done init already
return 0;
}
uint8_t _i2c_close()
{
if (file_i2c != 0)
{
close(file_i2c);
file_i2c = 0;
return 0;
}
return 1;
}
uint8_t _i2c_write(uint8_t* ptr, int16_t len)
{
if (file_i2c == 0 || ptr == 0 || len <= 0)
return 1;
int32_t rc;
rc = write(file_i2c, ptr, len);
return 0;
}
uint8_t _i2c_read(uint8_t *ptr, int16_t len)
{
if (file_i2c == 0 || ptr == 0 || len <= 0)
return 1;
int32_t rc;
rc = read(file_i2c, ptr, len);
return 0;
}

8
linux_i2c.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef __LINUX_I2C_H__
#define __LINUX_I2C_H__
uint8_t _i2c_init(int i2c, int dev_addr);
uint8_t _i2c_close();
uint8_t _i2c_write(uint8_t* ptr, int16_t len);
uint8_t _i2c_read(uint8_t *ptr, int16_t len);
#endif

224
main.c Normal file
View File

@ -0,0 +1,224 @@
#include <stdint.h>
#include <stdlib.h>
#include <inttypes.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <ssd1306.h>
void print_help()
{
printf("help message\n\n");
printf("-I\t\tinit oled (128x32 or 128x64 or 64x48)\n");
printf("-c\t\tclear (line number or all)\n");
printf("-d\t\t0/display off 1/display on\n");
printf("-f\t\t0/small font 5x7 1/normal font 8x8 (default normal font)\n");
printf("-h\t\thelp message\n");
printf("-i\t\t0/normal oled 1/invert oled\n");
printf("-l\t\tput your line to display\n");
printf("-m\t\tput your strings to oled\n");
printf("-n\t\tI2C device node address (0,1,2..., default 0)\n");
printf("-r\t\t0/normal 180/rotate\n");
printf("-x\t\tx position\n");
printf("-y\t\ty position\n");
}
int main(int argc, char **argv)
{
uint8_t i2c_node_address = 0;
int x = -1;
int y = -1;
uint8_t line[25] = {0};
uint8_t msg[200] = {0};
uint8_t oled_type[10] = {0};
int clear_line = -1;
int clear_all = -1;
int orientation = -1;
int inverted = -1;
int display = -1;
int font = 0;
int cmd_opt = 0;
while(cmd_opt != -1)
{
cmd_opt = getopt(argc, argv, "I:c::d:f:hi:l:m:n:r:x:y:");
/* Lets parse */
switch (cmd_opt) {
case 'I':
strncpy(oled_type, optarg, sizeof(oled_type));
break;
case 'c':
if (optarg)
{
clear_line = atoi(optarg);
}
else
{
clear_all = 1;
}
break;
case 'd':
display = atoi(optarg);
break;
case 'f':
font = atoi(optarg);
break;
case 'h':
print_help();
return 0;
case 'i':
inverted = atoi(optarg);
break;
case 'l':
strncpy(line, optarg, sizeof(line));
break;
case 'm':
strncpy(msg, optarg, sizeof(msg));
break;
case 'n':
i2c_node_address = (uint8_t)atoi(optarg);
break;
case 'r':
orientation = atoi(optarg);
if (orientation != 0 && orientation != 180)
{
printf("orientation value must be 0 or 180\n");
return 1;
}
break;
case 'x':
x = atoi(optarg);
break;
case 'y':
y = atoi(optarg);
break;
case -1:
// just ignore
break;
/* Error handle: Mainly missing arg or illegal option */
case '?':
if (optopt == 'I')
{
printf("prams -%c missing oled type (128x64/128x32/64x48)\n", optopt);
return 1;
}
else if (optopt == 'd' || optopt == 'f' || optopt == 'i')
{
printf("prams -%c missing 0 or 1 fields\n", optopt);
return 1;
}
else if (optopt == 'l' || optopt == 'm')
{
printf("prams -%c missing string\n", optopt);
return 1;
}
else if (optopt == 'n')
{
printf("prams -%c missing 0,1,2... I2C device node number\n", optopt);
return 1;
}
else if (optopt == 'r')
{
printf("prams -%c missing 0 or 180 fields\n", optopt);
return 1;
}
else if (optopt == 'x' || optopt == 'y')
{
printf("prams -%c missing coordinate values\n", optopt);
return 1;
}
break;
default:
print_help();
return 1;
}
}
uint8_t rc = 0;
// open the I2C device node
rc = ssd1306_init(i2c_node_address);
if (rc != 0)
{
printf("no oled attached to /dev/i2c-%d\n", i2c_node_address);
return 1;
}
// init oled module
if (oled_type[0] != 0)
{
if (strcmp(oled_type, "128x64") == 0)
rc += ssd1306_oled_default_config(64, 128);
else if (strcmp(oled_type, "128x32") == 0)
rc += ssd1306_oled_default_config(32, 128);
else if (strcmp(oled_type, "64x48") == 0)
rc += ssd1306_oled_default_config(48, 64);
}
else if (ssd1306_oled_load_resolution() != 0)
{
printf("please do init oled module with correction resolution first!\n");
return 1;
}
// clear display
if (clear_all > -1)
{
rc += ssd1306_oled_clear_screen();
}
else if (clear_line > -1)
{
rc += ssd1306_oled_clear_line(clear_line);
}
// set rotate orientation
if (orientation > -1)
{
rc += ssd1306_oled_set_rotate(orientation);
}
// set oled inverted
if (inverted > -1)
{
rc += ssd1306_oled_display_flip(inverted);
}
// set display on off
if (display > -1)
{
rc += ssd1306_oled_onoff(display);
}
// set cursor XY
if (x > -1 && y > -1)
{
rc += ssd1306_oled_set_XY(x, y);
}
else if (x > -1)
{
rc += ssd1306_oled_set_X(x);
}
else if (y > -1)
{
rc += ssd1306_oled_set_Y(y);
}
// print text
if (msg[0] != 0)
{
rc += ssd1306_oled_write_string(font, msg);
}
else if (line[0] != 0)
{
rc += ssd1306_oled_write_line(font, line);
}
// close the I2C device node
ssd1306_end();
return rc;
}

463
ssd1306.c Normal file
View File

@ -0,0 +1,463 @@
#include <stdint.h>
#include <stdlib.h>
#include <inttypes.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux_i2c.h>
#include <ssd1306.h>
#include <font.h>
const uint8_t init_oled_type_file[] = "/tmp/.ssd1306_oled_type";
static uint8_t data_buf[1024];
static int16_t data_len = 0;
static uint8_t max_lines = 0;
static uint8_t max_columns = 0;
static uint8_t global_x = 0;
static uint8_t global_y = 0;
uint8_t ssd1306_init(uint8_t i2c_dev)
{
uint8_t rc;
rc = _i2c_init(i2c_dev, SSD1306_I2C_ADDR);
if (rc > 0)
return rc;
// test i2c connection
uint8_t cmd = SSD1306_COMM_CONTROL_BYTE;
uint8_t result = 0;
_i2c_write(&cmd, 1);
_i2c_read(&result, 1);
if (result == 0)
return 1;
return 0;
}
uint8_t ssd1306_end()
{
return _i2c_close();
}
uint8_t ssd1306_oled_onoff(uint8_t onoff)
{
data_buf[0] = SSD1306_COMM_CONTROL_BYTE;
if (onoff == 0)
data_buf[1] = SSD1306_COMM_DISPLAY_OFF;
else
data_buf[1] = SSD1306_COMM_DISPLAY_ON;
return _i2c_write(data_buf, 2);
}
uint8_t ssd1306_oled_horizontal_flip(uint8_t flip)
{
data_buf[0] = SSD1306_COMM_CONTROL_BYTE;
if (flip == 0)
data_buf[1] = SSD1306_COMM_HORIZ_NORM;
else
data_buf[1] = SSD1306_COMM_HORIZ_FLIP;
return _i2c_write(data_buf, 2);
}
uint8_t ssd1306_oled_display_flip(uint8_t flip)
{
data_buf[0] = SSD1306_COMM_CONTROL_BYTE;
if (flip == 0)
data_buf[1] = SSD1306_COMM_DISP_NORM;
else
data_buf[1] = SSD1306_COMM_DISP_INVERSE;
return _i2c_write(data_buf, 2);
}
// 128x32 please use value 32
// 128x64 please use value 64
uint8_t ssd1306_oled_multiplex(uint8_t row)
{
data_buf[0] = SSD1306_COMM_CONTROL_BYTE;
data_buf[1] = SSD1306_COMM_MULTIPLEX;
data_buf[2] = row - 1;
return _i2c_write(data_buf, 3);
}
// offset range 0x00~0x3f
uint8_t ssd1306_oled_vert_shift(uint8_t offset)
{
data_buf[0] = SSD1306_COMM_CONTROL_BYTE;
data_buf[1] = SSD1306_COMM_VERT_OFFSET;
data_buf[2] = offset;
return _i2c_write(data_buf, 3);
}
// default value for clk is 0x80
uint8_t ssd1306_oled_set_clock(uint8_t clk)
{
data_buf[0] = SSD1306_COMM_CONTROL_BYTE;
data_buf[1] = SSD1306_COMM_CLK_SET;
data_buf[2] = clk;
return _i2c_write(data_buf, 3);
}
// default value for precharge is 0xf1
uint8_t ssd1306_oled_set_precharge(uint8_t precharge)
{
data_buf[0] = SSD1306_COMM_CONTROL_BYTE;
data_buf[1] = SSD1306_COMM_PRECHARGE;
data_buf[2] = precharge;
return _i2c_write(data_buf, 3);
}
// default value for deselect is 0x40
uint8_t ssd1306_oled_set_deselect(uint8_t voltage)
{
data_buf[0] = SSD1306_COMM_CONTROL_BYTE;
data_buf[1] = SSD1306_COMM_DESELECT_LV;
data_buf[2] = voltage;
return _i2c_write(data_buf, 3);
}
// default value for com pin is 0x02
uint8_t ssd1306_oled_set_com_pin(uint8_t value)
{
data_buf[0] = SSD1306_COMM_CONTROL_BYTE;
data_buf[1] = SSD1306_COMM_COM_PIN;
data_buf[2] = value;
return _i2c_write(data_buf, 3);
}
// default value use SSD1306_PAGE_MODE
uint8_t ssd1306_oled_set_mem_mode(uint8_t mode)
{
data_buf[0] = SSD1306_COMM_CONTROL_BYTE;
data_buf[1] = SSD1306_COMM_MEMORY_MODE;
data_buf[2] = mode;
return _i2c_write(data_buf, 3);
}
uint8_t ssd1306_oled_set_col(uint8_t start, uint8_t end)
{
data_buf[0] = SSD1306_COMM_CONTROL_BYTE;
data_buf[1] = SSD1306_COMM_SET_COL_ADDR;
data_buf[2] = start;
data_buf[3] = end;
return _i2c_write(data_buf, 4);
}
uint8_t ssd1306_oled_set_page(uint8_t start, uint8_t end)
{
data_buf[0] = SSD1306_COMM_CONTROL_BYTE;
data_buf[1] = SSD1306_COMM_SET_PAGE_ADDR;
data_buf[2] = start;
data_buf[3] = end;
return _i2c_write(data_buf, 4);
}
// default contrast value is 0x7f
uint8_t ssd1306_oled_set_constrast(uint8_t value)
{
data_buf[0] = SSD1306_COMM_CONTROL_BYTE;
data_buf[1] = SSD1306_COMM_CONTRAST;
data_buf[2] = value;
return _i2c_write(data_buf, 3);
}
uint8_t ssd1306_oled_scroll_onoff(uint8_t onoff)
{
data_buf[0] = SSD1306_COMM_CONTROL_BYTE;
if (onoff == 0)
data_buf[1] = SSD1306_COMM_DISABLE_SCROLL;
else
data_buf[1] = SSD1306_COMM_ENABLE_SCROLL;
return _i2c_write(data_buf, 2);
}
uint8_t ssd1306_oled_set_X(uint8_t x)
{
if (x >= max_columns)
return 1;
global_x = x;
data_buf[0] = SSD1306_COMM_CONTROL_BYTE;
data_buf[1] = SSD1306_COMM_LOW_COLUMN | (x & 0x0f);
data_buf[2] = SSD1306_COMM_HIGH_COLUMN | ((x >> 4) & 0x0f);
return _i2c_write(data_buf, 3);
}
uint8_t ssd1306_oled_set_Y(uint8_t y)
{
if (y >= (max_lines / 8))
return 1;
global_y = y;
data_buf[0] = SSD1306_COMM_CONTROL_BYTE;
data_buf[1] = SSD1306_COMM_PAGE_NUMBER | (y & 0x0f);
return _i2c_write(data_buf, 2);
}
uint8_t ssd1306_oled_set_XY(uint8_t x, uint8_t y)
{
if (x >= max_columns || y >= (max_lines / 8))
return 1;
global_x = x;
global_y = y;
data_buf[0] = SSD1306_COMM_CONTROL_BYTE;
data_buf[1] = SSD1306_COMM_PAGE_NUMBER | (y & 0x0f);
data_buf[2] = SSD1306_COMM_LOW_COLUMN | (x & 0x0f);
data_buf[3] = SSD1306_COMM_HIGH_COLUMN | ((x >> 4) & 0x0f);
return _i2c_write(data_buf, 4);
}
uint8_t ssd1306_oled_set_rotate(uint8_t degree)
{
// only degree 0 and 180
if (degree == 0)
{
data_buf[0] = SSD1306_COMM_CONTROL_BYTE;
data_buf[1] = SSD1306_COMM_HORIZ_FLIP;
data_buf[2] = SSD1306_COMM_SCAN_REVS;
return _i2c_write(data_buf, 3);
}
else if (degree == 180)
{
data_buf[0] = SSD1306_COMM_CONTROL_BYTE;
data_buf[1] = SSD1306_COMM_HORIZ_NORM;
data_buf[2] = SSD1306_COMM_SCAN_NORM;
return _i2c_write(data_buf, 3);
}
else
return 1;
}
uint8_t ssd1306_oled_default_config(uint8_t oled_lines, uint8_t oled_columns)
{
if (oled_lines != SSD1306_128_64_LINES && oled_lines != SSD1306_128_32_LINES && SSD1306_64_48_LINES)
oled_lines = SSD1306_128_64_LINES;
if (oled_columns != SSD1306_128_64_COLUMNS && oled_lines != SSD1306_128_32_COLUMNS && SSD1306_64_48_COLUMNS)
oled_columns = SSD1306_128_64_COLUMNS;
max_lines = oled_lines;
max_columns = oled_columns;
global_x = 0;
global_y = 0;
if (ssd1306_oled_save_resolution(max_columns, max_lines) != 0)
return 1;
uint16_t i = 0;
data_buf[i++] = SSD1306_COMM_CONTROL_BYTE; //command control byte
data_buf[i++] = SSD1306_COMM_DISPLAY_OFF; //display off
data_buf[i++] = SSD1306_COMM_DISP_NORM; //Set Normal Display (default)
data_buf[i++] = SSD1306_COMM_CLK_SET; //SETDISPLAYCLOCKDIV
data_buf[i++] = 0x80; // the suggested ratio 0x80
data_buf[i++] = SSD1306_COMM_MULTIPLEX; //SSD1306_SETMULTIPLEX
data_buf[i++] = oled_lines - 1; // height is 32 or 64 (always -1)
data_buf[i++] = SSD1306_COMM_VERT_OFFSET; //SETDISPLAYOFFSET
data_buf[i++] = 0; //no offset
data_buf[i++] = SSD1306_COMM_START_LINE; //SETSTARTLINE
data_buf[i++] = SSD1306_COMM_CHARGE_PUMP; //CHARGEPUMP
data_buf[i++] = 0x14; //turn on charge pump
data_buf[i++] = SSD1306_COMM_MEMORY_MODE; //MEMORYMODE
data_buf[i++] = SSD1306_PAGE_MODE; // page mode
data_buf[i++] = SSD1306_COMM_HORIZ_NORM; //SEGREMAP Mirror screen horizontally (A0)
data_buf[i++] = SSD1306_COMM_SCAN_NORM; //COMSCANDEC Rotate screen vertically (C0)
data_buf[i++] = SSD1306_COMM_COM_PIN; //HARDWARE PIN
data_buf[i++] = 0x02; //normal
data_buf[i++] = SSD1306_COMM_CONTRAST; //SETCONTRAST
data_buf[i++] = 0x7f; // default contract value
data_buf[i++] = SSD1306_COMM_PRECHARGE; //SETPRECHARGE
data_buf[i++] = 0xf1; // default precharge value
data_buf[i++] = SSD1306_COMM_DESELECT_LV; //SETVCOMDETECT
data_buf[i++] = 0x40; // default deselect value
data_buf[i++] = SSD1306_COMM_RESUME_RAM; //DISPLAYALLON_RESUME
data_buf[i++] = SSD1306_COMM_DISP_NORM; //NORMALDISPLAY
data_buf[i++] = SSD1306_COMM_DISPLAY_ON; //DISPLAY ON
data_buf[i++] = SSD1306_COMM_DISABLE_SCROLL;//Stop scroll
return _i2c_write(data_buf, i);
}
uint8_t ssd1306_oled_write_line(uint8_t size, uint8_t* ptr)
{
uint16_t i = 0;
uint16_t index = 0;
uint8_t* font_table = 0;
uint8_t font_table_width = 0;
if (ptr == 0)
return 1;
if (size == SSD1306_FONT_SMALL) // 5x7
{
font_table = (uint8_t*)font5x7;
font_table_width = 5;
}
else if (size == SSD1306_FONT_NORMAL) // 8x8
{
font_table = (uint8_t*)font8x8;
font_table_width = 8;
}
else
return 1;
data_buf[i++] = SSD1306_DATA_CONTROL_BYTE;
// font table range in ascii table is from 0x20(space) to 0x7e(~)
while (ptr[index] != 0 && i <= 1024)
{
if ((ptr[index] < ' ') || (ptr[index] > '~'))
return 1;
uint8_t* font_ptr = &font_table[(ptr[index] - 0x20) * font_table_width];
uint8_t j = 0;
for (j = 0; j < font_table_width; j++)
{
data_buf[i++] = font_ptr[j];
if (i > 1024)
return 1;
}
// insert 1 col space for small font size)
if (size == SSD1306_FONT_SMALL)
data_buf[i++] = 0x00;
index++;
}
return _i2c_write(data_buf, i);
}
uint8_t ssd1306_oled_write_string(uint8_t size, uint8_t* ptr)
{
uint8_t rc = 0;
if (ptr == 0)
return 1;
uint8_t* line = 0;
uint8_t* cr = 0;
uint8_t buf[20];
line = ptr;
do {
memset(buf, 0, 20);
cr = strstr(line, "\\n");
if (cr != NULL)
{
strncpy(buf, line, cr - line);
}
else
{
strcpy(buf, line);
}
// set cursor position
ssd1306_oled_set_XY(global_x, global_y);
rc += ssd1306_oled_write_line(size, buf);
if (cr != NULL)
{
line = &cr[2];
global_x = 0;
global_y++;
if (global_y >= (max_lines / 8))
global_y = 0;
}
else
line = NULL;
}while (line != NULL);
return rc;
}
uint8_t ssd1306_oled_clear_line(uint8_t row)
{
uint8_t i;
if (row >= (max_lines / 8))
return 1;
ssd1306_oled_set_XY(0, row);
data_buf[0] = SSD1306_DATA_CONTROL_BYTE;
for (i = 0; i < max_columns; i++)
data_buf[i+1] = 0x00;
return _i2c_write(data_buf, 1 + max_columns);
}
uint8_t ssd1306_oled_clear_screen()
{
uint8_t rc = 0;
uint8_t i;
for (i = 0; i < (max_lines / 8); i++)
{
rc += ssd1306_oled_clear_line(i);
}
return rc;
}
uint8_t ssd1306_oled_save_resolution(uint8_t column, uint8_t row)
{
FILE* fp;
fp = fopen(init_oled_type_file, "w");
if (fp == NULL)
{
// file create failed
return 1;
}
fprintf(fp, "%hhux%hhu", column, row);
fclose(fp);
return 0;
}
uint8_t ssd1306_oled_load_resolution()
{
FILE* fp;
fp = fopen(init_oled_type_file, "r");
if (fp == NULL)
{
// file not exists
return 1;
}
// file exists
fscanf(fp, "%hhux%hhu", &max_columns, &max_lines);
fclose(fp);
return 0;
}

85
ssd1306.h Normal file
View File

@ -0,0 +1,85 @@
#ifndef __SSD1306_H__
#define __SSD1306_H__
#define SSD1306_I2C_ADDR 0x3c
#define SSD1306_COMM_CONTROL_BYTE 0x00
#define SSD1306_DATA_CONTROL_BYTE 0x40
#define SSD1306_COMM_DISPLAY_OFF 0xae
#define SSD1306_COMM_DISPLAY_ON 0xaf
#define SSD1306_COMM_HORIZ_NORM 0xa0
#define SSD1306_COMM_HORIZ_FLIP 0xa1
#define SSD1306_COMM_RESUME_RAM 0xa4
#define SSD1306_COMM_IGNORE_RAM 0xa5
#define SSD1306_COMM_DISP_NORM 0xa6
#define SSD1306_COMM_DISP_INVERSE 0xa7
#define SSD1306_COMM_MULTIPLEX 0xa8
#define SSD1306_COMM_VERT_OFFSET 0xd3
#define SSD1306_COMM_CLK_SET 0xd5
#define SSD1306_COMM_PRECHARGE 0xd9
#define SSD1306_COMM_COM_PIN 0xda
#define SSD1306_COMM_DESELECT_LV 0xdb
#define SSD1306_COMM_CONTRAST 0x81
#define SSD1306_COMM_DISABLE_SCROLL 0x2e
#define SSD1306_COMM_ENABLE_SCROLL 0x2f
#define SSD1306_COMM_PAGE_NUMBER 0xb0
#define SSD1306_COMM_LOW_COLUMN 0x00
#define SSD1306_COMM_HIGH_COLUMN 0x10
#define SSD1306_COMM_START_LINE 0x40
#define SSD1306_COMM_CHARGE_PUMP 0x8d
#define SSD1306_COMM_SCAN_NORM 0xc0
#define SSD1306_COMM_SCAN_REVS 0xc8
#define SSD1306_COMM_MEMORY_MODE 0x20
#define SSD1306_COMM_SET_COL_ADDR 0x21
#define SSD1306_COMM_SET_PAGE_ADDR 0x22
#define SSD1306_HORI_MODE 0x00
#define SSD1306_VERT_MODE 0x01
#define SSD1306_PAGE_MODE 0x02
#define SSD1306_FONT_SMALL 0x00
#define SSD1306_FONT_NORMAL 0x01
#define SSD1306_128_64_LINES 64
#define SSD1306_128_32_LINES 32
#define SSD1306_64_48_LINES 48
#define SSD1306_128_64_COLUMNS 128
#define SSD1306_128_32_COLUMNS 128
#define SSD1306_64_48_COLUMNS 64
uint8_t ssd1306_init(uint8_t i2c_dev);
uint8_t ssd1306_end();
uint8_t ssd1306_oled_onoff(uint8_t onoff);
uint8_t ssd1306_oled_horizontal_flip(uint8_t flip);
uint8_t ssd1306_oled_display_flip(uint8_t flip);
uint8_t ssd1306_oled_multiplex(uint8_t row);
uint8_t ssd1306_oled_vert_shift(uint8_t offset);
uint8_t ssd1306_oled_set_clock(uint8_t clk);
uint8_t ssd1306_oled_set_precharge(uint8_t precharge);
uint8_t ssd1306_oled_set_deselect(uint8_t voltage);
uint8_t ssd1306_oled_set_com_pin(uint8_t value);
uint8_t ssd1306_oled_set_mem_mode(uint8_t mode);
uint8_t ssd1306_oled_set_col(uint8_t start, uint8_t end);
uint8_t ssd1306_oled_set_page(uint8_t start, uint8_t end);
uint8_t ssd1306_oled_set_constrast(uint8_t value);
uint8_t ssd1306_oled_scroll_onoff(uint8_t onoff);
uint8_t ssd1306_oled_set_X(uint8_t x);
uint8_t ssd1306_oled_set_Y(uint8_t y);
uint8_t ssd1306_oled_set_XY(uint8_t x, uint8_t y);
uint8_t ssd1306_oled_set_rotate(uint8_t degree);
uint8_t ssd1306_oled_default_config(uint8_t oled_lines, uint8_t oled_columns);
uint8_t ssd1306_oled_write_line(uint8_t size, uint8_t* ptr);
uint8_t ssd1306_oled_write_string(uint8_t size, uint8_t* ptr);
uint8_t ssd1306_oled_clear_line(uint8_t row);
uint8_t ssd1306_oled_clear_screen();
uint8_t ssd1306_oled_save_resolution(uint8_t column, uint8_t row);
uint8_t ssd1306_oled_load_resolution();
#endif