summaryrefslogtreecommitdiff
path: root/include/driver/ssd1306.h
blob: d5d3a58f73b4502c4bf0cc07ca17f083f8db6f67 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
/*
 * Copyright 2021 Birte Kristina Friesel
 *
 * SPDX-License-Identifier: BSD-2-Clause
 *
 * Driver for Solomon Systech SSD1306 OLED controller. Tested with
 * 128x64 and 128x32 Displays.
 */
#ifndef SSD1306_H
#define SSD1306_H

#define SSD1306_SET_CONTRAST 0x81
#define SSD1306_SET_ENTIRE_ON 0xa4
#define SSD1306_SET_NORM_INV 0xa6
#define SSD1306_SET_DISP 0xae
#define SSD1306_SET_MEM_ADDR 0x20
#define SSD1306_SET_COL_ADDR 0x21
#define SSD1306_SET_PAGE_ADDR 0x22
#define SSD1306_SET_DISP_START_LINE 0x40
#define SSD1306_SET_SEG_REMAP 0xa0
#define SSD1306_SET_MUX_RATIO 0xa8
#define SSD1306_SET_COM_OUT_DIR 0xc0
#define SSD1306_SET_DISP_OFFSET 0xd3
#define SSD1306_SET_COM_PIN_CFG 0xda
#define SSD1306_SET_DISP_CLK_DIV 0xd5
#define SSD1306_SET_PRECHARGE 0xd9
#define SSD1306_SET_VCOM_DESEL 0xdb
#define SSD1306_SET_CHARGE_PUMP 0x8d

#include <stdint.h>
#include <stddef.h>

class SSD1306 {
	private:
		const uint8_t width = SSD1306_WIDTH;
		const uint8_t height = SSD1306_HEIGHT;
		SSD1306(const SSD1306 &copy);

		unsigned char const address = 0x3c;

		unsigned char txbuf[130];
		unsigned char rxbuf[2];

		/*
		 * Adjust both SSD1306_SET_SEG_REMAP and SSD1306_SET_COM_OUT_DIR for
		 * 180° rotation.
		 */
		const unsigned char init1[6] = {
			// Turn off power for configuration
			SSD1306_SET_DISP | 0x00,

#ifdef CONFIG_driver_ssd1306_mode_horizontal
			/*
			 * Enable Horizontal Addressing Mode. Assuming image data is {A, B, C,
			 * ..., a, b, c, ...}, each byte corresponds to a 1x8 column, starting
			 * at the top left corner and proceeding to the right and then down:
			 *
			 * A7 B7 C7 ...
			 * .. .. .. ...
			 * A0 B0 C0 ...
			 * a7 b7 c7 ...
			 * .. .. .. ...
			 * a0 b0 c0 ...
			 */
			SSD1306_SET_MEM_ADDR, 0x00,
#endif
#ifdef CONFIG_driver_ssd1306_mode_vertical
			/*
			 * Enable Vertical Addressing Mode. Assuming image data is {A, B, C,
			 * ..., a, b, c, ...}, each byte corresponds to a 1x8 column, starting
			 * at the top left corner and proceeding down and then to the right:
			 *
			 * A7 a7 ...
			 * .. .. ...
			 * A0 a0 ...
			 * B7 b7 ...
			 * .. .. ...
			 * B0 b0 ...
			 * .. .. ...
			 */
			SSD1306_SET_MEM_ADDR, 0x01,
#endif

			// RAM line 0 == display line 0
			SSD1306_SET_DISP_START_LINE | 0x00,

			/*
			 * Horizontal Layout: Column 127 is SEG0.
			 * This depends on the connection between SSD1306 and OLED.
			 * Use 0x00 if your content is horizontally mirrored.
			 */
			SSD1306_SET_SEG_REMAP | 0x01,

			/*
			 * Multiplex ratio is the number of display lines
			 * (i.e., the display height)
			 */
			SSD1306_SET_MUX_RATIO
		};

		// height-1 sent by init()

		const unsigned char init2[4] = {
			/*
			 * Vertical Layout: Scan from COM63 to COM0.
			 * This depends on the connection between SSD1306 and OLED.
			 * Use 0x00 if your content is vertically mirrored.
			 */
			SSD1306_SET_COM_OUT_DIR | 0x08,

			// No vertical display offset
			SSD1306_SET_DISP_OFFSET, 0x00,

			/*
			 * COM PIN layout depends on display height and type. See
			 * datasheet and init().
			 */
			SSD1306_SET_COM_PIN_CFG
		};

		// height == 32? 0x02 : 0x12

		const unsigned char init3[19] = {
			/*
			 * Set clock to recommended values: 370 kHz (bits 7..4),
			 * no divider (bits 3..0). Increase divider for glitchy effects.
			 * The datasheet is unclear on the clock frequency range.
			 */
			SSD1306_SET_DISP_CLK_DIV, 0x80,

			/*
			 * Set line (multiplex) precharge times.
			 * phase 1 (discharge pixels to avoid effects from the previous line): 8 cycles
			 * phase 2 (charge pixels for next line): 8 cycles
			 * decrease phase 1 time for glitchy effects.
			 */
			SSD1306_SET_PRECHARGE, 0x88,

			/*
			 * VCOM deselect level. Unknown.
			 * 0x00: ~0.65 VCC
			 * 0x20: ~0.77 VCC
			 * 0x30: ~0.85 VCC
			 */
			SSD1306_SET_VCOM_DESEL, 0x30,

			// start with medium contrast
			SSD1306_SET_CONTRAST, 0x80,

			// display content == RAM content
			SSD1306_SET_ENTIRE_ON,

			// regular (uninverted) display
			SSD1306_SET_NORM_INV | 0x00,

			// Enable charge pump (provide power to the display)
			SSD1306_SET_CHARGE_PUMP, 0x14,

			// turn on display
			SSD1306_SET_DISP | 0x01,

			// reset column pointer
			SSD1306_SET_COL_ADDR, 0, 127,

			// reset page pointer
			SSD1306_SET_PAGE_ADDR, 0, height/8-1
		};

		void writeCommand(uint8_t command);
		void writeData(unsigned char* data);

	public:
		SSD1306() {}

		void init();
		void setContrast(unsigned char contrast);
		void setInvert(bool invert);
		void showImage(unsigned char* data, uint16_t length);
};

extern SSD1306 ssd1306;

#endif