├── .gitignore ├── LICENSE ├── Makefile ├── Readme.md ├── font.h ├── linux_i2c.c ├── linux_i2c.h ├── main.c ├── ssd1306.c └── ssd1306.h /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.d 3 | ssd1306_bin 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 armlabs 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CFLAGS=-I ./ -Wall -Werror 3 | LDFLAGS=-static 4 | OBJS=main.o ssd1306.o linux_i2c.o 5 | BIN=ssd1306_bin 6 | 7 | default: $(BIN) 8 | .PHONY: default clean 9 | 10 | # Adapted from scottmcpeak.com/autodepend/autodepend.html 11 | -include $(OBJS:.o=.d) 12 | %.o: %.c 13 | $(CC) -c $(CFLAGS) $< -o $*.o 14 | $(CC) -MM $(CFLAGS) $< > $*.d 15 | @cp -f $*.d $*.d.tmp 16 | @sed -e 's/.*://' -e 's/\\$$//' < $*.d.tmp | fmt -1 | \ 17 | sed -e 's/^ *//' -e 's/$$/:/' >> $*.d 18 | @rm -f $*.d.tmp 19 | 20 | $(BIN):$(OBJS) 21 | $(CC) $(CFLAGS) -o $@ $(OBJS) $(LDFLAGS) 22 | 23 | clean: 24 | rm -f *.o *.d $(BIN) 25 | 26 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # OLED SSD1306 Linux driver 2 | This is plain c code using linux I2C device node (/dev/i2c-X X for 0,1,2,3...). 3 | Please make sure the linux has run "modprobe i2c-dev". 4 | 128x64 and 128x32 are supporting and using I2C interface ONLY 5 | ## Files 6 | **linux_i2c.c** source code for i2c control in linux device node. 7 | **linux_i2c.h** header file for i2c control in linux. 8 | **ssd1306.c** i2c protocol functions to control oled SSD1306. 9 | **ssd1306.h** header file for i2c protocol functions and defined commands in SSD1306. 10 | **font.h** font header file define 5x7 small font and 8x8 normal font. ascii value from 0x20(SPACE) to 0x7e(~). 11 | **main.c** main file to take params and control oled SSD1306. 12 | **Makefile** plain Makefile to build the source code. It works in raspberry pi. 13 | **Readme.md** this readme file. 14 | ## How to compile 15 | Require make and gcc. If you use cross compile, please self define $(CC). 16 | Type "make" to build binary "ssd1306_bin". 17 | Type "make clean" to clean the project. 18 | ## How to use 19 | - always init oled module ONCE when power up. 20 | - set the device node address EVERYTIME if not using default value /dev/i2c-0 21 | - the init oled module always reset XY cursor to (0,0) 22 | - all params can set together 23 | - clear screen if new text need to write, otherwise wording overlapping happened 24 | - resolution value stored in /tmp/.ssd1306_oled_type with format like "128x64" or "128x32" or "64x48" 25 | - always do display rotation first and then filling text. otherwise the text cause mirror 26 | - make sure the XY cursor setting in correct location before printing text 27 | ### Params 28 | ```sh 29 | -I init oled (128x32 or 128x64 or 64x48) 30 | -c clear (line number or all) 31 | -d 0/display off 1/display on 32 | -f 0/small font 5x7 1/normal font 8x8 (default small font) 33 | -h help message 34 | -i 0/normal oled 1/invert oled 35 | -l put your line to display 36 | -m put your strings to oled 37 | -n I2C device node address (0,1,2..., default 0) 38 | -r 0/normal 180/rotate 39 | -x x position 40 | -y y position 41 | ``` 42 | ## Example 43 | ### init the OLED once 44 | - resolution 128x64 45 | ```sh 46 | $ ./ssd1306_bin -I 128x64 47 | ``` 48 | - resolution 128x32 49 | ```sh 50 | $ ./ssd1306_bin -I 128x32 51 | ``` 52 | - resolution 64x48 53 | ```sh 54 | $ ./ssd1306_bin -I 64x48 55 | ``` 56 | ### clear display 57 | - clear 1st line 58 | ```sh 59 | ./ssd1306_bin -c0 60 | ``` 61 | - clear 2nd line 62 | ```sh 63 | $ ./ssd1306_bin -c1 64 | ``` 65 | - clear 4th line 66 | ```sh 67 | $ ./ssd1306_bin -c3 68 | ``` 69 | - clear whole screen 70 | ```sh 71 | $ ./ssd1306_bin -c 72 | ``` 73 | ### display on/off 74 | - turn off display 75 | ```sh 76 | $ ./ssd1306_bin -d 0 77 | ``` 78 | - turn on display 79 | ```sh 80 | $ ./ssd1306_bin -d 1 81 | ``` 82 | ### inverting display 83 | - normal oled (0 is off, 1 is on) 84 | ```sh 85 | $ ./ssd1306_bin -i 0 86 | ``` 87 | - invert oled (0 is on, 1 is off) 88 | ```sh 89 | $ ./ssd1306_bin -i 1 90 | ``` 91 | ### print words 92 | - write line "Hello World" 93 | ```sh 94 | $ ./ssd1306_bin -l "Hello World" 95 | ``` 96 | - write message "alpha\nbravo\ncharlie\ndelta" (please place \n for next line) 97 | ```sh 98 | $ ./ssd1306_bin -m "alpha\nbravo\ncharlie\ndelta" 99 | ``` 100 | ### I2C device address (default is /dev/i2c-0) 101 | - using /dev/i2c-1 102 | ```sh 103 | $ ./ssd1306_bin -n 1 104 | ``` 105 | ### rotate display 106 | - normal orientation 107 | ```sh 108 | $ ./ssd1306_bin -r 0 109 | ``` 110 | - turn 180 orientation 111 | ```sh 112 | $ ./ssd1306_bin -r 180 113 | ``` 114 | ### set cursor location 115 | - set XY cursor 8,1(x is column, 8 columns skipping, y is row, 2nd line) 116 | ```sh 117 | $ ./ssd1306_bin -x 8 -y 1 118 | ``` 119 | -------------------------------------------------------------------------------- /font.h: -------------------------------------------------------------------------------- 1 | #ifndef __FONT_H 2 | #define __FONT_H 3 | 4 | #include 5 | #include 6 | 7 | const uint8_t font5x7[] = { 8 | 0x00, 0x00, 0x00, 0x00, 0x00, // SPACE 9 | 0x00, 0x00, 0x5F, 0x00, 0x00, // ! 10 | 0x00, 0x03, 0x00, 0x03, 0x00, // " 11 | 0x14, 0x3E, 0x14, 0x3E, 0x14, // # 12 | 0x24, 0x2A, 0x7F, 0x2A, 0x12, // $ 13 | 0x43, 0x33, 0x08, 0x66, 0x61, // % 14 | 0x36, 0x49, 0x55, 0x22, 0x50, // & 15 | 0x00, 0x05, 0x03, 0x00, 0x00, // ' 16 | 0x00, 0x1C, 0x22, 0x41, 0x00, // ( 17 | 0x00, 0x41, 0x22, 0x1C, 0x00, // ) 18 | 0x14, 0x08, 0x3E, 0x08, 0x14, // * 19 | 0x08, 0x08, 0x3E, 0x08, 0x08, // + 20 | 0x00, 0x50, 0x30, 0x00, 0x00, // , 21 | 0x08, 0x08, 0x08, 0x08, 0x08, // - 22 | 0x00, 0x60, 0x60, 0x00, 0x00, // . 23 | 0x20, 0x10, 0x08, 0x04, 0x02, // / 24 | 25 | 0x3E, 0x51, 0x49, 0x45, 0x3E, // 0 26 | 0x00, 0x04, 0x02, 0x7F, 0x00, // 1 27 | 0x42, 0x61, 0x51, 0x49, 0x46, // 2 28 | 0x22, 0x41, 0x49, 0x49, 0x36, // 3 29 | 0x18, 0x14, 0x12, 0x7F, 0x10, // 4 30 | 0x27, 0x45, 0x45, 0x45, 0x39, // 5 31 | 0x3E, 0x49, 0x49, 0x49, 0x32, // 6 32 | 0x01, 0x01, 0x71, 0x09, 0x07, // 7 33 | 0x36, 0x49, 0x49, 0x49, 0x36, // 8 34 | 0x26, 0x49, 0x49, 0x49, 0x3E, // 9 35 | 0x00, 0x36, 0x36, 0x00, 0x00, // : 36 | 0x00, 0x56, 0x36, 0x00, 0x00, // ; 37 | 0x08, 0x14, 0x22, 0x41, 0x00, // < 38 | 0x14, 0x14, 0x14, 0x14, 0x14, // = 39 | 0x00, 0x41, 0x22, 0x14, 0x08, // > 40 | 0x02, 0x01, 0x51, 0x09, 0x06, // ? 41 | 42 | 0x3E, 0x41, 0x59, 0x55, 0x5E, // @ 43 | 0x7E, 0x09, 0x09, 0x09, 0x7E, // A 44 | 0x7F, 0x49, 0x49, 0x49, 0x36, // B 45 | 0x3E, 0x41, 0x41, 0x41, 0x22, // C 46 | 0x7F, 0x41, 0x41, 0x41, 0x3E, // D 47 | 0x7F, 0x49, 0x49, 0x49, 0x41, // E 48 | 0x7F, 0x09, 0x09, 0x09, 0x01, // F 49 | 0x3E, 0x41, 0x41, 0x49, 0x3A, // G 50 | 0x7F, 0x08, 0x08, 0x08, 0x7F, // H 51 | 0x00, 0x41, 0x7F, 0x41, 0x00, // I 52 | 0x30, 0x40, 0x40, 0x40, 0x3F, // J 53 | 0x7F, 0x08, 0x14, 0x22, 0x41, // K 54 | 0x7F, 0x40, 0x40, 0x40, 0x40, // L 55 | 0x7F, 0x02, 0x0C, 0x02, 0x7F, // M 56 | 0x7F, 0x02, 0x04, 0x08, 0x7F, // N 57 | 0x3E, 0x41, 0x41, 0x41, 0x3E, // O 58 | 59 | 0x7F, 0x09, 0x09, 0x09, 0x06, // P 60 | 0x1E, 0x21, 0x21, 0x21, 0x5E, // Q 61 | 0x7F, 0x09, 0x09, 0x09, 0x76, // R 62 | 0x26, 0x49, 0x49, 0x49, 0x32, // S 63 | 0x01, 0x01, 0x7F, 0x01, 0x01, // T 64 | 0x3F, 0x40, 0x40, 0x40, 0x3F, // U 65 | 0x1F, 0x20, 0x40, 0x20, 0x1F, // V 66 | 0x7F, 0x20, 0x10, 0x20, 0x7F, // W 67 | 0x41, 0x22, 0x1C, 0x22, 0x41, // X 68 | 0x07, 0x08, 0x70, 0x08, 0x07, // Y 69 | 0x61, 0x51, 0x49, 0x45, 0x43, // Z 70 | 0x00, 0x7F, 0x41, 0x00, 0x00, // [ 71 | 0x02, 0x04, 0x08, 0x10, 0x20, // backslash 72 | 0x00, 0x00, 0x41, 0x7F, 0x00, // ] 73 | 0x04, 0x02, 0x01, 0x02, 0x04, // ^ 74 | 0x40, 0x40, 0x40, 0x40, 0x40, // _ 75 | 76 | 0x00, 0x01, 0x02, 0x04, 0x00, // ` 77 | 0x20, 0x54, 0x54, 0x54, 0x78, // a 78 | 0x7F, 0x44, 0x44, 0x44, 0x38, // b 79 | 0x38, 0x44, 0x44, 0x44, 0x44, // c 80 | 0x38, 0x44, 0x44, 0x44, 0x7F, // d 81 | 0x38, 0x54, 0x54, 0x54, 0x18, // e 82 | 0x04, 0x04, 0x7E, 0x05, 0x05, // f 83 | 0x08, 0x54, 0x54, 0x54, 0x3C, // g 84 | 0x7F, 0x08, 0x04, 0x04, 0x78, // h 85 | 0x00, 0x44, 0x7D, 0x40, 0x00, // i 86 | 0x20, 0x40, 0x44, 0x3D, 0x00, // j 87 | 0x7F, 0x10, 0x28, 0x44, 0x00, // k 88 | 0x00, 0x41, 0x7F, 0x40, 0x00, // l 89 | 0x7C, 0x04, 0x78, 0x04, 0x78, // m 90 | 0x7C, 0x08, 0x04, 0x04, 0x78, // n 91 | 0x38, 0x44, 0x44, 0x44, 0x38, // o 92 | 93 | 0x7C, 0x14, 0x14, 0x14, 0x08, // p 94 | 0x08, 0x14, 0x14, 0x14, 0x7C, // q 95 | 0x00, 0x7C, 0x08, 0x04, 0x04, // r 96 | 0x48, 0x54, 0x54, 0x54, 0x20, // s 97 | 0x04, 0x04, 0x3F, 0x44, 0x44, // t 98 | 0x3C, 0x40, 0x40, 0x20, 0x7C, // u 99 | 0x1C, 0x20, 0x40, 0x20, 0x1C, // v 100 | 0x3C, 0x40, 0x30, 0x40, 0x3C, // w 101 | 0x44, 0x28, 0x10, 0x28, 0x44, // x 102 | 0x0C, 0x50, 0x50, 0x50, 0x3C, // y 103 | 0x44, 0x64, 0x54, 0x4C, 0x44, // z 104 | 0x00, 0x08, 0x36, 0x41, 0x41, // { 105 | 0x00, 0x00, 0x7F, 0x00, 0x00, // | 106 | 0x41, 0x41, 0x36, 0x08, 0x00, // } 107 | 0x02, 0x01, 0x02, 0x04, 0x02 // ~ 108 | }; 109 | 110 | const uint8_t font8x8[] = { 111 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 112 | 0x00,0x00,0x00,0x00,0x5F,0x00,0x00,0x00, // ! 113 | 0x00,0x00,0x00,0x03,0x00,0x03,0x00,0x00, // " 114 | 0x00,0x24,0x7E,0x24,0x24,0x7E,0x24,0x00, // # 115 | 0x00,0x2E,0x2A,0x7F,0x2A,0x3A,0x00,0x00, // $ 116 | 0x00,0x46,0x26,0x10,0x08,0x64,0x62,0x00, // % 117 | 0x00,0x20,0x54,0x4A,0x54,0x20,0x50,0x00, // & 118 | 0x00,0x00,0x00,0x04,0x02,0x00,0x00,0x00, // ' 119 | 0x00,0x00,0x00,0x3C,0x42,0x00,0x00,0x00, // ( 120 | 0x00,0x00,0x00,0x42,0x3C,0x00,0x00,0x00, // ) 121 | 0x00,0x10,0x54,0x38,0x54,0x10,0x00,0x00, // * 122 | 0x00,0x10,0x10,0x7C,0x10,0x10,0x00,0x00, // + 123 | 0x00,0x00,0x00,0x80,0x60,0x00,0x00,0x00, // , 124 | 0x00,0x10,0x10,0x10,0x10,0x10,0x00,0x00, // - 125 | 0x00,0x00,0x00,0x60,0x60,0x00,0x00,0x00, // . 126 | 0x00,0x40,0x20,0x10,0x08,0x04,0x00,0x00, // / 127 | 128 | 0x3C,0x62,0x52,0x4A,0x46,0x3C,0x00,0x00, // 0 129 | 0x44,0x42,0x7E,0x40,0x40,0x00,0x00,0x00, // 1 130 | 0x64,0x52,0x52,0x52,0x52,0x4C,0x00,0x00, // 2 131 | 0x24,0x42,0x42,0x4A,0x4A,0x34,0x00,0x00, // 3 132 | 0x30,0x28,0x24,0x7E,0x20,0x20,0x00,0x00, // 4 133 | 0x2E,0x4A,0x4A,0x4A,0x4A,0x32,0x00,0x00, // 5 134 | 0x3C,0x4A,0x4A,0x4A,0x4A,0x30,0x00,0x00, // 6 135 | 0x02,0x02,0x62,0x12,0x0A,0x06,0x00,0x00, // 7 136 | 0x34,0x4A,0x4A,0x4A,0x4A,0x34,0x00,0x00, // 8 137 | 0x0C,0x52,0x52,0x52,0x52,0x3C,0x00,0x00, // 9 138 | 0x00,0x00,0x00,0x48,0x00,0x00,0x00,0x00, // : 139 | 0x00,0x00,0x80,0x64,0x00,0x00,0x00,0x00, // ; 140 | 0x00,0x00,0x10,0x28,0x44,0x00,0x00,0x00, // < 141 | 0x00,0x28,0x28,0x28,0x28,0x28,0x00,0x00, // = 142 | 0x00,0x00,0x44,0x28,0x10,0x00,0x00,0x00, // > 143 | 0x00,0x04,0x02,0x02,0x52,0x0A,0x04,0x00, // ? 144 | 145 | 0x00,0x3C,0x42,0x5A,0x56,0x5A,0x1C,0x00, // @ 146 | 0x7C,0x12,0x12,0x12,0x12,0x7C,0x00,0x00, // A 147 | 0x7E,0x4A,0x4A,0x4A,0x4A,0x34,0x00,0x00, // B 148 | 0x3C,0x42,0x42,0x42,0x42,0x24,0x00,0x00, // C 149 | 0x7E,0x42,0x42,0x42,0x24,0x18,0x00,0x00, // D 150 | 0x7E,0x4A,0x4A,0x4A,0x4A,0x42,0x00,0x00, // E 151 | 0x7E,0x0A,0x0A,0x0A,0x0A,0x02,0x00,0x00, // F 152 | 0x3C,0x42,0x42,0x52,0x52,0x34,0x00,0x00, // G 153 | 0x7E,0x08,0x08,0x08,0x08,0x7E,0x00,0x00, // H 154 | 0x00,0x42,0x42,0x7E,0x42,0x42,0x00,0x00, // I 155 | 0x30,0x40,0x40,0x40,0x40,0x3E,0x00,0x00, // J 156 | 0x7E,0x08,0x08,0x14,0x22,0x40,0x00,0x00, // K 157 | 0x7E,0x40,0x40,0x40,0x40,0x40,0x00,0x00, // L 158 | 0x7E,0x04,0x08,0x08,0x04,0x7E,0x00,0x00, // M 159 | 0x7E,0x04,0x08,0x10,0x20,0x7E,0x00,0x00, // N 160 | 0x3C,0x42,0x42,0x42,0x42,0x3C,0x00,0x00, // O 161 | 162 | 0x7E,0x12,0x12,0x12,0x12,0x0C,0x00,0x00, // P 163 | 0x3C,0x42,0x52,0x62,0x42,0x3C,0x00,0x00, // Q 164 | 0x7E,0x12,0x12,0x12,0x32,0x4C,0x00,0x00, // R 165 | 0x24,0x4A,0x4A,0x4A,0x4A,0x30,0x00,0x00, // S 166 | 0x02,0x02,0x02,0x7E,0x02,0x02,0x02,0x00, // T 167 | 0x3E,0x40,0x40,0x40,0x40,0x3E,0x00,0x00, // U 168 | 0x1E,0x20,0x40,0x40,0x20,0x1E,0x00,0x00, // V 169 | 0x3E,0x40,0x20,0x20,0x40,0x3E,0x00,0x00, // W 170 | 0x42,0x24,0x18,0x18,0x24,0x42,0x00,0x00, // X 171 | 0x02,0x04,0x08,0x70,0x08,0x04,0x02,0x00, // Y 172 | 0x42,0x62,0x52,0x4A,0x46,0x42,0x00,0x00, // Z 173 | 0x00,0x00,0x7E,0x42,0x42,0x00,0x00,0x00, // [ 174 | 0x00,0x04,0x08,0x10,0x20,0x40,0x00,0x00, // 175 | 0x00,0x00,0x42,0x42,0x7E,0x00,0x00,0x00, // ] 176 | 0x00,0x08,0x04,0x7E,0x04,0x08,0x00,0x00, // ^ 177 | 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00, // _ 178 | 179 | 0x3C,0x42,0x99,0xA5,0xA5,0x81,0x42,0x3C, // ` 180 | 0x00,0x20,0x54,0x54,0x54,0x78,0x00,0x00, // a 181 | 0x00,0x7E,0x48,0x48,0x48,0x30,0x00,0x00, // b 182 | 0x00,0x00,0x38,0x44,0x44,0x44,0x00,0x00, // c 183 | 0x00,0x30,0x48,0x48,0x48,0x7E,0x00,0x00, // d 184 | 0x00,0x38,0x54,0x54,0x54,0x48,0x00,0x00, // e 185 | 0x00,0x00,0x00,0x7C,0x0A,0x02,0x00,0x00, // f 186 | 0x00,0x18,0xA4,0xA4,0xA4,0xA4,0x7C,0x00, // g 187 | 0x00,0x7E,0x08,0x08,0x08,0x70,0x00,0x00, // h 188 | 0x00,0x00,0x00,0x48,0x7A,0x40,0x00,0x00, // i 189 | 0x00,0x00,0x40,0x80,0x80,0x7A,0x00,0x00, // j 190 | 0x00,0x7E,0x18,0x24,0x40,0x00,0x00,0x00, // k 191 | 0x00,0x00,0x00,0x3E,0x40,0x40,0x00,0x00, // l 192 | 0x00,0x7C,0x04,0x78,0x04,0x78,0x00,0x00, // m 193 | 0x00,0x7C,0x04,0x04,0x04,0x78,0x00,0x00, // n 194 | 0x00,0x38,0x44,0x44,0x44,0x38,0x00,0x00, // o 195 | 196 | 0x00,0xFC,0x24,0x24,0x24,0x18,0x00,0x00, // p 197 | 0x00,0x18,0x24,0x24,0x24,0xFC,0x80,0x00, // q 198 | 0x00,0x00,0x78,0x04,0x04,0x04,0x00,0x00, // r 199 | 0x00,0x48,0x54,0x54,0x54,0x20,0x00,0x00, // s 200 | 0x00,0x00,0x04,0x3E,0x44,0x40,0x00,0x00, // t 201 | 0x00,0x3C,0x40,0x40,0x40,0x3C,0x00,0x00, // u 202 | 0x00,0x0C,0x30,0x40,0x30,0x0C,0x00,0x00, // v 203 | 0x00,0x3C,0x40,0x38,0x40,0x3C,0x00,0x00, // w 204 | 0x00,0x44,0x28,0x10,0x28,0x44,0x00,0x00, // x 205 | 0x00,0x1C,0xA0,0xA0,0xA0,0x7C,0x00,0x00, // y 206 | 0x00,0x44,0x64,0x54,0x4C,0x44,0x00,0x00, // z 207 | 0x00,0x08,0x08,0x76,0x42,0x42,0x00,0x00, // { 208 | 0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x00, // | 209 | 0x00,0x42,0x42,0x76,0x08,0x08,0x00,0x00, // } 210 | 0x00,0x00,0x04,0x02,0x04,0x02,0x00,0x00 // ~ 211 | }; 212 | 213 | #endif 214 | -------------------------------------------------------------------------------- /linux_i2c.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | static int file_i2c = 0; 12 | 13 | uint8_t _i2c_init(int i2c, int dev_addr) 14 | { 15 | if (file_i2c == 0) 16 | { 17 | char filename[32]; 18 | sprintf(filename, "/dev/i2c-%d", i2c); // I2C bus number passed 19 | file_i2c = open(filename, O_RDWR); 20 | if (file_i2c < 0) 21 | { 22 | file_i2c = 0; 23 | return 1; 24 | } 25 | if (ioctl(file_i2c, I2C_SLAVE, dev_addr) < 0) // set slave address 26 | { 27 | close(file_i2c); 28 | file_i2c = 0; 29 | return 1; 30 | } 31 | return 0; 32 | } 33 | 34 | // assume done init already 35 | return 0; 36 | } 37 | 38 | uint8_t _i2c_close() 39 | { 40 | if (file_i2c != 0) 41 | { 42 | close(file_i2c); 43 | file_i2c = 0; 44 | return 0; 45 | } 46 | 47 | return 1; 48 | } 49 | 50 | uint8_t _i2c_write(uint8_t* ptr, int16_t len) 51 | { 52 | if (file_i2c == 0 || ptr == 0 || len <= 0) 53 | return 1; 54 | 55 | write(file_i2c, ptr, len); 56 | 57 | return 0; 58 | } 59 | 60 | uint8_t _i2c_read(uint8_t *ptr, int16_t len) 61 | { 62 | if (file_i2c == 0 || ptr == 0 || len <= 0) 63 | return 1; 64 | 65 | read(file_i2c, ptr, len); 66 | 67 | return 0; 68 | } 69 | -------------------------------------------------------------------------------- /linux_i2c.h: -------------------------------------------------------------------------------- 1 | #ifndef __LINUX_I2C_H__ 2 | #define __LINUX_I2C_H__ 3 | 4 | uint8_t _i2c_init(int i2c, int dev_addr); 5 | uint8_t _i2c_close(); 6 | uint8_t _i2c_write(uint8_t* ptr, int16_t len); 7 | uint8_t _i2c_read(uint8_t *ptr, int16_t len); 8 | #endif 9 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "ssd1306.h" 11 | 12 | void print_help() 13 | { 14 | printf("help message\n\n"); 15 | printf("-I\t\tinit oled (128x32 or 128x64 or 64x48)\n"); 16 | printf("-c\t\tclear (line number or all)\n"); 17 | printf("-d\t\t0/display off 1/display on\n"); 18 | printf("-f\t\t0/small font 5x7 1/normal font 8x8 (default normal font)\n"); 19 | printf("-h\t\thelp message\n"); 20 | printf("-i\t\t0/normal oled 1/invert oled\n"); 21 | printf("-l\t\tput your line to display\n"); 22 | printf("-m\t\tput your strings to oled\n"); 23 | printf("-n\t\tI2C device node address (0,1,2..., default 0)\n"); 24 | printf("-r\t\t0/normal 180/rotate\n"); 25 | printf("-x\t\tx position\n"); 26 | printf("-y\t\ty position\n"); 27 | } 28 | 29 | int main(int argc, char **argv) 30 | { 31 | uint8_t i2c_node_address = 0; 32 | int x = -1; 33 | int y = -1; 34 | char line[25] = {0}; 35 | char msg[200] = {0}; 36 | char oled_type[10] = {0}; 37 | int clear_line = -1; 38 | int clear_all = -1; 39 | int orientation = -1; 40 | int inverted = -1; 41 | int display = -1; 42 | int font = 0; 43 | 44 | int cmd_opt = 0; 45 | 46 | while(cmd_opt != -1) 47 | { 48 | cmd_opt = getopt(argc, argv, "I:c::d:f:hi:l:m:n:r:x:y:"); 49 | 50 | /* Lets parse */ 51 | switch (cmd_opt) { 52 | case 'I': 53 | snprintf(oled_type, sizeof (oled_type) - 1, "%s", optarg); 54 | break; 55 | case 'c': 56 | if (optarg) 57 | { 58 | clear_line = atoi(optarg); 59 | } 60 | else 61 | { 62 | clear_all = 1; 63 | } 64 | break; 65 | case 'd': 66 | display = atoi(optarg); 67 | break; 68 | case 'f': 69 | font = atoi(optarg); 70 | break; 71 | case 'h': 72 | print_help(); 73 | return 0; 74 | case 'i': 75 | inverted = atoi(optarg); 76 | break; 77 | case 'l': 78 | strncpy(line, optarg, sizeof(line)); 79 | break; 80 | case 'm': 81 | strncpy(msg, optarg, sizeof(msg)); 82 | break; 83 | case 'n': 84 | i2c_node_address = (uint8_t)atoi(optarg); 85 | break; 86 | case 'r': 87 | orientation = atoi(optarg); 88 | if (orientation != 0 && orientation != 180) 89 | { 90 | printf("orientation value must be 0 or 180\n"); 91 | return 1; 92 | } 93 | break; 94 | case 'x': 95 | x = atoi(optarg); 96 | break; 97 | case 'y': 98 | y = atoi(optarg); 99 | break; 100 | case -1: 101 | // just ignore 102 | break; 103 | /* Error handle: Mainly missing arg or illegal option */ 104 | case '?': 105 | if (optopt == 'I') 106 | { 107 | printf("prams -%c missing oled type (128x64/128x32/64x48)\n", optopt); 108 | return 1; 109 | } 110 | else if (optopt == 'd' || optopt == 'f' || optopt == 'i') 111 | { 112 | printf("prams -%c missing 0 or 1 fields\n", optopt); 113 | return 1; 114 | } 115 | else if (optopt == 'l' || optopt == 'm') 116 | { 117 | printf("prams -%c missing string\n", optopt); 118 | return 1; 119 | } 120 | else if (optopt == 'n') 121 | { 122 | printf("prams -%c missing 0,1,2... I2C device node number\n", optopt); 123 | return 1; 124 | } 125 | else if (optopt == 'r') 126 | { 127 | printf("prams -%c missing 0 or 180 fields\n", optopt); 128 | return 1; 129 | } 130 | else if (optopt == 'x' || optopt == 'y') 131 | { 132 | printf("prams -%c missing coordinate values\n", optopt); 133 | return 1; 134 | } 135 | break; 136 | default: 137 | print_help(); 138 | return 1; 139 | } 140 | } 141 | 142 | uint8_t rc = 0; 143 | 144 | // open the I2C device node 145 | rc = ssd1306_init(i2c_node_address); 146 | 147 | if (rc != 0) 148 | { 149 | printf("no oled attached to /dev/i2c-%d\n", i2c_node_address); 150 | return 1; 151 | } 152 | 153 | // init oled module 154 | if (oled_type[0] != 0) 155 | { 156 | if (strcmp(oled_type, "128x64") == 0) 157 | rc += ssd1306_oled_default_config(64, 128); 158 | else if (strcmp(oled_type, "128x32") == 0) 159 | rc += ssd1306_oled_default_config(32, 128); 160 | else if (strcmp(oled_type, "64x48") == 0) 161 | rc += ssd1306_oled_default_config(48, 64); 162 | } 163 | else if (ssd1306_oled_load_resolution() != 0) 164 | { 165 | printf("please do init oled module with correction resolution first!\n"); 166 | return 1; 167 | } 168 | 169 | // clear display 170 | if (clear_all > -1) 171 | { 172 | rc += ssd1306_oled_clear_screen(); 173 | } 174 | else if (clear_line > -1) 175 | { 176 | rc += ssd1306_oled_clear_line(clear_line); 177 | } 178 | 179 | // set rotate orientation 180 | if (orientation > -1) 181 | { 182 | rc += ssd1306_oled_set_rotate(orientation); 183 | } 184 | 185 | // set oled inverted 186 | if (inverted > -1) 187 | { 188 | rc += ssd1306_oled_display_flip(inverted); 189 | } 190 | 191 | // set display on off 192 | if (display > -1) 193 | { 194 | rc += ssd1306_oled_onoff(display); 195 | } 196 | 197 | // set cursor XY 198 | if (x > -1 && y > -1) 199 | { 200 | rc += ssd1306_oled_set_XY(x, y); 201 | } 202 | else if (x > -1) 203 | { 204 | rc += ssd1306_oled_set_X(x); 205 | } 206 | else if (y > -1) 207 | { 208 | rc += ssd1306_oled_set_Y(y); 209 | } 210 | 211 | // print text 212 | if (msg[0] != 0) 213 | { 214 | rc += ssd1306_oled_write_string(font, msg); 215 | } 216 | else if (line[0] != 0) 217 | { 218 | rc += ssd1306_oled_write_line(font, line); 219 | } 220 | 221 | // close the I2C device node 222 | ssd1306_end(); 223 | 224 | return rc; 225 | } 226 | -------------------------------------------------------------------------------- /ssd1306.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "linux_i2c.h" 13 | #include "ssd1306.h" 14 | #include "font.h" 15 | 16 | const char init_oled_type_file[] = "/tmp/.ssd1306_oled_type"; 17 | 18 | static uint8_t data_buf[1024]; 19 | static uint8_t max_lines = 0; 20 | static uint8_t max_columns = 0; 21 | static uint8_t global_x = 0; 22 | static uint8_t global_y = 0; 23 | 24 | uint8_t ssd1306_init(uint8_t i2c_dev) 25 | { 26 | uint8_t rc; 27 | rc = _i2c_init(i2c_dev, SSD1306_I2C_ADDR); 28 | if (rc > 0) 29 | return rc; 30 | 31 | // test i2c connection 32 | uint8_t cmd = SSD1306_COMM_CONTROL_BYTE; 33 | uint8_t result = 0; 34 | _i2c_write(&cmd, 1); 35 | _i2c_read(&result, 1); 36 | if (result == 0) 37 | return 1; 38 | 39 | return 0; 40 | } 41 | 42 | uint8_t ssd1306_end() 43 | { 44 | return _i2c_close(); 45 | } 46 | 47 | uint8_t ssd1306_oled_onoff(uint8_t onoff) 48 | { 49 | data_buf[0] = SSD1306_COMM_CONTROL_BYTE; 50 | if (onoff == 0) 51 | data_buf[1] = SSD1306_COMM_DISPLAY_OFF; 52 | else 53 | data_buf[1] = SSD1306_COMM_DISPLAY_ON; 54 | 55 | return _i2c_write(data_buf, 2); 56 | } 57 | 58 | uint8_t ssd1306_oled_horizontal_flip(uint8_t flip) 59 | { 60 | data_buf[0] = SSD1306_COMM_CONTROL_BYTE; 61 | if (flip == 0) 62 | data_buf[1] = SSD1306_COMM_HORIZ_NORM; 63 | else 64 | data_buf[1] = SSD1306_COMM_HORIZ_FLIP; 65 | 66 | return _i2c_write(data_buf, 2); 67 | } 68 | 69 | uint8_t ssd1306_oled_display_flip(uint8_t flip) 70 | { 71 | data_buf[0] = SSD1306_COMM_CONTROL_BYTE; 72 | if (flip == 0) 73 | data_buf[1] = SSD1306_COMM_DISP_NORM; 74 | else 75 | data_buf[1] = SSD1306_COMM_DISP_INVERSE; 76 | 77 | return _i2c_write(data_buf, 2); 78 | } 79 | 80 | // 128x32 please use value 32 81 | // 128x64 please use value 64 82 | uint8_t ssd1306_oled_multiplex(uint8_t row) 83 | { 84 | data_buf[0] = SSD1306_COMM_CONTROL_BYTE; 85 | data_buf[1] = SSD1306_COMM_MULTIPLEX; 86 | data_buf[2] = row - 1; 87 | 88 | return _i2c_write(data_buf, 3); 89 | } 90 | 91 | // offset range 0x00~0x3f 92 | uint8_t ssd1306_oled_vert_shift(uint8_t offset) 93 | { 94 | data_buf[0] = SSD1306_COMM_CONTROL_BYTE; 95 | data_buf[1] = SSD1306_COMM_VERT_OFFSET; 96 | data_buf[2] = offset; 97 | 98 | return _i2c_write(data_buf, 3); 99 | } 100 | 101 | // default value for clk is 0x80 102 | uint8_t ssd1306_oled_set_clock(uint8_t clk) 103 | { 104 | data_buf[0] = SSD1306_COMM_CONTROL_BYTE; 105 | data_buf[1] = SSD1306_COMM_CLK_SET; 106 | data_buf[2] = clk; 107 | 108 | return _i2c_write(data_buf, 3); 109 | } 110 | 111 | // default value for precharge is 0xf1 112 | uint8_t ssd1306_oled_set_precharge(uint8_t precharge) 113 | { 114 | data_buf[0] = SSD1306_COMM_CONTROL_BYTE; 115 | data_buf[1] = SSD1306_COMM_PRECHARGE; 116 | data_buf[2] = precharge; 117 | 118 | return _i2c_write(data_buf, 3); 119 | } 120 | 121 | // default value for deselect is 0x40 122 | uint8_t ssd1306_oled_set_deselect(uint8_t voltage) 123 | { 124 | data_buf[0] = SSD1306_COMM_CONTROL_BYTE; 125 | data_buf[1] = SSD1306_COMM_DESELECT_LV; 126 | data_buf[2] = voltage; 127 | 128 | return _i2c_write(data_buf, 3); 129 | } 130 | 131 | // default value for com pin is 0x02 132 | uint8_t ssd1306_oled_set_com_pin(uint8_t value) 133 | { 134 | data_buf[0] = SSD1306_COMM_CONTROL_BYTE; 135 | data_buf[1] = SSD1306_COMM_COM_PIN; 136 | data_buf[2] = value; 137 | 138 | return _i2c_write(data_buf, 3); 139 | } 140 | 141 | // default value use SSD1306_PAGE_MODE 142 | uint8_t ssd1306_oled_set_mem_mode(uint8_t mode) 143 | { 144 | data_buf[0] = SSD1306_COMM_CONTROL_BYTE; 145 | data_buf[1] = SSD1306_COMM_MEMORY_MODE; 146 | data_buf[2] = mode; 147 | 148 | return _i2c_write(data_buf, 3); 149 | } 150 | 151 | uint8_t ssd1306_oled_set_col(uint8_t start, uint8_t end) 152 | { 153 | data_buf[0] = SSD1306_COMM_CONTROL_BYTE; 154 | data_buf[1] = SSD1306_COMM_SET_COL_ADDR; 155 | data_buf[2] = start; 156 | data_buf[3] = end; 157 | 158 | return _i2c_write(data_buf, 4); 159 | } 160 | 161 | uint8_t ssd1306_oled_set_page(uint8_t start, uint8_t end) 162 | { 163 | data_buf[0] = SSD1306_COMM_CONTROL_BYTE; 164 | data_buf[1] = SSD1306_COMM_SET_PAGE_ADDR; 165 | data_buf[2] = start; 166 | data_buf[3] = end; 167 | 168 | return _i2c_write(data_buf, 4); 169 | } 170 | 171 | // default contrast value is 0x7f 172 | uint8_t ssd1306_oled_set_constrast(uint8_t value) 173 | { 174 | data_buf[0] = SSD1306_COMM_CONTROL_BYTE; 175 | data_buf[1] = SSD1306_COMM_CONTRAST; 176 | data_buf[2] = value; 177 | 178 | return _i2c_write(data_buf, 3); 179 | } 180 | 181 | uint8_t ssd1306_oled_scroll_onoff(uint8_t onoff) 182 | { 183 | data_buf[0] = SSD1306_COMM_CONTROL_BYTE; 184 | if (onoff == 0) 185 | data_buf[1] = SSD1306_COMM_DISABLE_SCROLL; 186 | else 187 | data_buf[1] = SSD1306_COMM_ENABLE_SCROLL; 188 | 189 | return _i2c_write(data_buf, 2); 190 | } 191 | 192 | uint8_t ssd1306_oled_set_X(uint8_t x) 193 | { 194 | if (x >= max_columns) 195 | return 1; 196 | 197 | global_x = x; 198 | 199 | data_buf[0] = SSD1306_COMM_CONTROL_BYTE; 200 | data_buf[1] = SSD1306_COMM_LOW_COLUMN | (x & 0x0f); 201 | data_buf[2] = SSD1306_COMM_HIGH_COLUMN | ((x >> 4) & 0x0f); 202 | 203 | return _i2c_write(data_buf, 3); 204 | } 205 | 206 | uint8_t ssd1306_oled_set_Y(uint8_t y) 207 | { 208 | if (y >= (max_lines / 8)) 209 | return 1; 210 | 211 | global_y = y; 212 | 213 | data_buf[0] = SSD1306_COMM_CONTROL_BYTE; 214 | data_buf[1] = SSD1306_COMM_PAGE_NUMBER | (y & 0x0f); 215 | 216 | return _i2c_write(data_buf, 2); 217 | } 218 | 219 | uint8_t ssd1306_oled_set_XY(uint8_t x, uint8_t y) 220 | { 221 | if (x >= max_columns || y >= (max_lines / 8)) 222 | return 1; 223 | 224 | global_x = x; 225 | global_y = y; 226 | 227 | data_buf[0] = SSD1306_COMM_CONTROL_BYTE; 228 | data_buf[1] = SSD1306_COMM_PAGE_NUMBER | (y & 0x0f); 229 | 230 | data_buf[2] = SSD1306_COMM_LOW_COLUMN | (x & 0x0f); 231 | 232 | data_buf[3] = SSD1306_COMM_HIGH_COLUMN | ((x >> 4) & 0x0f); 233 | 234 | return _i2c_write(data_buf, 4); 235 | } 236 | 237 | uint8_t ssd1306_oled_set_rotate(uint8_t degree) 238 | { 239 | // only degree 0 and 180 240 | if (degree == 0) 241 | { 242 | data_buf[0] = SSD1306_COMM_CONTROL_BYTE; 243 | data_buf[1] = SSD1306_COMM_HORIZ_FLIP; 244 | data_buf[2] = SSD1306_COMM_SCAN_REVS; 245 | 246 | return _i2c_write(data_buf, 3); 247 | } 248 | else if (degree == 180) 249 | { 250 | data_buf[0] = SSD1306_COMM_CONTROL_BYTE; 251 | data_buf[1] = SSD1306_COMM_HORIZ_NORM; 252 | data_buf[2] = SSD1306_COMM_SCAN_NORM; 253 | 254 | return _i2c_write(data_buf, 3); 255 | } 256 | else 257 | return 1; 258 | } 259 | 260 | uint8_t ssd1306_oled_default_config(uint8_t oled_lines, uint8_t oled_columns) 261 | { 262 | if (oled_lines != SSD1306_128_64_LINES && oled_lines != SSD1306_128_32_LINES && SSD1306_64_48_LINES) 263 | oled_lines = SSD1306_128_64_LINES; 264 | 265 | if (oled_columns != SSD1306_128_64_COLUMNS && oled_lines != SSD1306_128_32_COLUMNS && SSD1306_64_48_COLUMNS) 266 | oled_columns = SSD1306_128_64_COLUMNS; 267 | 268 | max_lines = oled_lines; 269 | max_columns = oled_columns; 270 | global_x = 0; 271 | global_y = 0; 272 | 273 | if (ssd1306_oled_save_resolution(max_columns, max_lines) != 0) 274 | return 1; 275 | 276 | uint16_t i = 0; 277 | data_buf[i++] = SSD1306_COMM_CONTROL_BYTE; //command control byte 278 | data_buf[i++] = SSD1306_COMM_DISPLAY_OFF; //display off 279 | data_buf[i++] = SSD1306_COMM_DISP_NORM; //Set Normal Display (default) 280 | data_buf[i++] = SSD1306_COMM_CLK_SET; //SETDISPLAYCLOCKDIV 281 | data_buf[i++] = 0x80; // the suggested ratio 0x80 282 | data_buf[i++] = SSD1306_COMM_MULTIPLEX; //SSD1306_SETMULTIPLEX 283 | data_buf[i++] = oled_lines - 1; // height is 32 or 64 (always -1) 284 | data_buf[i++] = SSD1306_COMM_VERT_OFFSET; //SETDISPLAYOFFSET 285 | data_buf[i++] = 0; //no offset 286 | data_buf[i++] = SSD1306_COMM_START_LINE; //SETSTARTLINE 287 | data_buf[i++] = SSD1306_COMM_CHARGE_PUMP; //CHARGEPUMP 288 | data_buf[i++] = 0x14; //turn on charge pump 289 | data_buf[i++] = SSD1306_COMM_MEMORY_MODE; //MEMORYMODE 290 | data_buf[i++] = SSD1306_PAGE_MODE; // page mode 291 | data_buf[i++] = SSD1306_COMM_HORIZ_NORM; //SEGREMAP Mirror screen horizontally (A0) 292 | data_buf[i++] = SSD1306_COMM_SCAN_NORM; //COMSCANDEC Rotate screen vertically (C0) 293 | data_buf[i++] = SSD1306_COMM_COM_PIN; //HARDWARE PIN 294 | if (oled_lines == 32) 295 | data_buf[i++] = 0x02; // for 32 lines 296 | else 297 | data_buf[i++] = 0x12; // for 64 lines or 48 lines 298 | data_buf[i++] = SSD1306_COMM_CONTRAST; //SETCONTRAST 299 | data_buf[i++] = 0x7f; // default contract value 300 | data_buf[i++] = SSD1306_COMM_PRECHARGE; //SETPRECHARGE 301 | data_buf[i++] = 0xf1; // default precharge value 302 | data_buf[i++] = SSD1306_COMM_DESELECT_LV; //SETVCOMDETECT 303 | data_buf[i++] = 0x40; // default deselect value 304 | data_buf[i++] = SSD1306_COMM_RESUME_RAM; //DISPLAYALLON_RESUME 305 | data_buf[i++] = SSD1306_COMM_DISP_NORM; //NORMALDISPLAY 306 | data_buf[i++] = SSD1306_COMM_DISPLAY_ON; //DISPLAY ON 307 | data_buf[i++] = SSD1306_COMM_DISABLE_SCROLL;//Stop scroll 308 | 309 | return _i2c_write(data_buf, i); 310 | } 311 | 312 | uint8_t ssd1306_oled_write_line(uint8_t size, char* ptr) 313 | { 314 | uint16_t i = 0; 315 | uint16_t index = 0; 316 | uint8_t* font_table = 0; 317 | uint8_t font_table_width = 0; 318 | 319 | if (ptr == 0) 320 | return 1; 321 | 322 | if (size == SSD1306_FONT_SMALL) // 5x7 323 | { 324 | font_table = (uint8_t*)font5x7; 325 | font_table_width = 5; 326 | } 327 | else if (size == SSD1306_FONT_NORMAL) // 8x8 328 | { 329 | font_table = (uint8_t*)font8x8; 330 | font_table_width = 8; 331 | } 332 | else 333 | return 1; 334 | 335 | data_buf[i++] = SSD1306_DATA_CONTROL_BYTE; 336 | 337 | // font table range in ascii table is from 0x20(space) to 0x7e(~) 338 | while (ptr[index] != 0 && i <= 1024) 339 | { 340 | if ((ptr[index] < ' ') || (ptr[index] > '~')) 341 | return 1; 342 | 343 | uint8_t* font_ptr = &font_table[(ptr[index] - 0x20) * font_table_width]; 344 | uint8_t j = 0; 345 | for (j = 0; j < font_table_width; j++) 346 | { 347 | data_buf[i++] = font_ptr[j]; 348 | if (i > 1024) 349 | return 1; 350 | } 351 | // insert 1 col space for small font size) 352 | if (size == SSD1306_FONT_SMALL) 353 | data_buf[i++] = 0x00; 354 | index++; 355 | } 356 | 357 | return _i2c_write(data_buf, i); 358 | } 359 | 360 | uint8_t ssd1306_oled_write_string(uint8_t size, char* ptr) 361 | { 362 | uint8_t rc = 0; 363 | 364 | if (ptr == 0) 365 | return 1; 366 | 367 | char* line = 0; 368 | char* cr = 0; 369 | char buf[20]; 370 | 371 | line = ptr; 372 | do { 373 | memset(buf, 0, 20); 374 | cr = strstr(line, "\\n"); 375 | if (cr != NULL) 376 | { 377 | strncpy(buf, line, cr - line); 378 | } 379 | else 380 | { 381 | strcpy(buf, line); 382 | } 383 | 384 | // set cursor position 385 | ssd1306_oled_set_XY(global_x, global_y); 386 | rc += ssd1306_oled_write_line(size, buf); 387 | 388 | if (cr != NULL) 389 | { 390 | line = &cr[2]; 391 | global_x = 0; 392 | global_y++; 393 | if (global_y >= (max_lines / 8)) 394 | global_y = 0; 395 | } 396 | else 397 | line = NULL; 398 | 399 | }while (line != NULL); 400 | 401 | return rc; 402 | } 403 | 404 | uint8_t ssd1306_oled_clear_line(uint8_t row) 405 | { 406 | uint8_t i; 407 | if (row >= (max_lines / 8)) 408 | return 1; 409 | 410 | ssd1306_oled_set_XY(0, row); 411 | data_buf[0] = SSD1306_DATA_CONTROL_BYTE; 412 | for (i = 0; i < max_columns; i++) 413 | data_buf[i+1] = 0x00; 414 | 415 | return _i2c_write(data_buf, 1 + max_columns); 416 | } 417 | 418 | uint8_t ssd1306_oled_clear_screen() 419 | { 420 | uint8_t rc = 0; 421 | uint8_t i; 422 | 423 | for (i = 0; i < (max_lines / 8); i++) 424 | { 425 | rc += ssd1306_oled_clear_line(i); 426 | } 427 | 428 | return rc; 429 | } 430 | 431 | uint8_t ssd1306_oled_save_resolution(uint8_t column, uint8_t row) 432 | { 433 | FILE* fp; 434 | 435 | fp = fopen(init_oled_type_file, "w"); 436 | 437 | if (fp == NULL) 438 | { 439 | // file create failed 440 | return 1; 441 | } 442 | 443 | fprintf(fp, "%hhux%hhu", column, row); 444 | fclose(fp); 445 | 446 | return 0; 447 | } 448 | 449 | uint8_t ssd1306_oled_load_resolution() 450 | { 451 | FILE* fp; 452 | 453 | fp = fopen(init_oled_type_file, "r"); 454 | 455 | if (fp == NULL) 456 | { 457 | // file not exists 458 | return 1; 459 | } 460 | 461 | // file exists 462 | fscanf(fp, "%hhux%hhu", &max_columns, &max_lines); 463 | fclose(fp); 464 | 465 | return 0; 466 | } 467 | -------------------------------------------------------------------------------- /ssd1306.h: -------------------------------------------------------------------------------- 1 | #ifndef __SSD1306_H__ 2 | #define __SSD1306_H__ 3 | 4 | #define SSD1306_I2C_ADDR 0x3c 5 | 6 | #define SSD1306_COMM_CONTROL_BYTE 0x00 7 | #define SSD1306_DATA_CONTROL_BYTE 0x40 8 | 9 | #define SSD1306_COMM_DISPLAY_OFF 0xae 10 | #define SSD1306_COMM_DISPLAY_ON 0xaf 11 | #define SSD1306_COMM_HORIZ_NORM 0xa0 12 | #define SSD1306_COMM_HORIZ_FLIP 0xa1 13 | #define SSD1306_COMM_RESUME_RAM 0xa4 14 | #define SSD1306_COMM_IGNORE_RAM 0xa5 15 | #define SSD1306_COMM_DISP_NORM 0xa6 16 | #define SSD1306_COMM_DISP_INVERSE 0xa7 17 | #define SSD1306_COMM_MULTIPLEX 0xa8 18 | #define SSD1306_COMM_VERT_OFFSET 0xd3 19 | #define SSD1306_COMM_CLK_SET 0xd5 20 | #define SSD1306_COMM_PRECHARGE 0xd9 21 | #define SSD1306_COMM_COM_PIN 0xda 22 | #define SSD1306_COMM_DESELECT_LV 0xdb 23 | #define SSD1306_COMM_CONTRAST 0x81 24 | #define SSD1306_COMM_DISABLE_SCROLL 0x2e 25 | #define SSD1306_COMM_ENABLE_SCROLL 0x2f 26 | #define SSD1306_COMM_PAGE_NUMBER 0xb0 27 | #define SSD1306_COMM_LOW_COLUMN 0x00 28 | #define SSD1306_COMM_HIGH_COLUMN 0x10 29 | 30 | #define SSD1306_COMM_START_LINE 0x40 31 | 32 | #define SSD1306_COMM_CHARGE_PUMP 0x8d 33 | 34 | #define SSD1306_COMM_SCAN_NORM 0xc0 35 | #define SSD1306_COMM_SCAN_REVS 0xc8 36 | 37 | #define SSD1306_COMM_MEMORY_MODE 0x20 38 | #define SSD1306_COMM_SET_COL_ADDR 0x21 39 | #define SSD1306_COMM_SET_PAGE_ADDR 0x22 40 | 41 | #define SSD1306_HORI_MODE 0x00 42 | #define SSD1306_VERT_MODE 0x01 43 | #define SSD1306_PAGE_MODE 0x02 44 | 45 | #define SSD1306_FONT_SMALL 0x00 46 | #define SSD1306_FONT_NORMAL 0x01 47 | 48 | #define SSD1306_128_64_LINES 64 49 | #define SSD1306_128_32_LINES 32 50 | #define SSD1306_64_48_LINES 48 51 | 52 | #define SSD1306_128_64_COLUMNS 128 53 | #define SSD1306_128_32_COLUMNS 128 54 | #define SSD1306_64_48_COLUMNS 64 55 | 56 | 57 | uint8_t ssd1306_init(uint8_t i2c_dev); 58 | uint8_t ssd1306_end(); 59 | uint8_t ssd1306_oled_onoff(uint8_t onoff); 60 | uint8_t ssd1306_oled_horizontal_flip(uint8_t flip); 61 | uint8_t ssd1306_oled_display_flip(uint8_t flip); 62 | uint8_t ssd1306_oled_multiplex(uint8_t row); 63 | uint8_t ssd1306_oled_vert_shift(uint8_t offset); 64 | uint8_t ssd1306_oled_set_clock(uint8_t clk); 65 | uint8_t ssd1306_oled_set_precharge(uint8_t precharge); 66 | uint8_t ssd1306_oled_set_deselect(uint8_t voltage); 67 | uint8_t ssd1306_oled_set_com_pin(uint8_t value); 68 | uint8_t ssd1306_oled_set_mem_mode(uint8_t mode); 69 | uint8_t ssd1306_oled_set_col(uint8_t start, uint8_t end); 70 | uint8_t ssd1306_oled_set_page(uint8_t start, uint8_t end); 71 | uint8_t ssd1306_oled_set_constrast(uint8_t value); 72 | uint8_t ssd1306_oled_scroll_onoff(uint8_t onoff); 73 | uint8_t ssd1306_oled_set_X(uint8_t x); 74 | uint8_t ssd1306_oled_set_Y(uint8_t y); 75 | uint8_t ssd1306_oled_set_XY(uint8_t x, uint8_t y); 76 | uint8_t ssd1306_oled_set_rotate(uint8_t degree); 77 | uint8_t ssd1306_oled_default_config(uint8_t oled_lines, uint8_t oled_columns); 78 | uint8_t ssd1306_oled_write_line(uint8_t size, char* ptr); 79 | uint8_t ssd1306_oled_write_string(uint8_t size, char* ptr); 80 | uint8_t ssd1306_oled_clear_line(uint8_t row); 81 | uint8_t ssd1306_oled_clear_screen(); 82 | uint8_t ssd1306_oled_save_resolution(uint8_t column, uint8_t row); 83 | uint8_t ssd1306_oled_load_resolution(); 84 | 85 | #endif 86 | --------------------------------------------------------------------------------