diff options
Diffstat (limited to 'lib/chibios-contrib/testhal/NUMICRO/NUC123/NUTINY-SDK-NUC123-V2.0/I2C/ssd1306.c')
-rw-r--r-- | lib/chibios-contrib/testhal/NUMICRO/NUC123/NUTINY-SDK-NUC123-V2.0/I2C/ssd1306.c | 193 |
1 files changed, 193 insertions, 0 deletions
diff --git a/lib/chibios-contrib/testhal/NUMICRO/NUC123/NUTINY-SDK-NUC123-V2.0/I2C/ssd1306.c b/lib/chibios-contrib/testhal/NUMICRO/NUC123/NUTINY-SDK-NUC123-V2.0/I2C/ssd1306.c new file mode 100644 index 000000000..f4b37c195 --- /dev/null +++ b/lib/chibios-contrib/testhal/NUMICRO/NUC123/NUTINY-SDK-NUC123-V2.0/I2C/ssd1306.c | |||
@@ -0,0 +1,193 @@ | |||
1 | /* | ||
2 | Copyright (C) 2020 Ein Terakawa | ||
3 | |||
4 | Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | you may not use this file except in compliance with the License. | ||
6 | You may obtain a copy of the License at | ||
7 | |||
8 | http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | |||
10 | Unless required by applicable law or agreed to in writing, software | ||
11 | distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | See the License for the specific language governing permissions and | ||
14 | limitations under the License. | ||
15 | */ | ||
16 | |||
17 | #include "hal.h" | ||
18 | #include "ssd1306.h" | ||
19 | #include "string.h" | ||
20 | |||
21 | /* timeout value must be increased for i2cclk less than its default, 100kHz. */ | ||
22 | #define CMD_TRANSMIT_TIMEOUT TIME_MS2I(10) | ||
23 | #define DATA_TRANSMIT_TIMEOUT TIME_MS2I(100) | ||
24 | |||
25 | #define CTRL_CMD_STREAM 0x00 | ||
26 | #define CTRL_DATA_STREAM 0x40 | ||
27 | #define CTRL_CMD_SINGLE 0x80 | ||
28 | |||
29 | #define I2CD ((ssd1306)->i2cd) | ||
30 | #define ADDR ((ssd1306)->i2caddr) | ||
31 | |||
32 | #define send_cmd(ssd1306, ...) \ | ||
33 | do { \ | ||
34 | uint8_t buf[] = { CTRL_CMD_STREAM, __VA_ARGS__ }; \ | ||
35 | bool _success = _send_cmd(I2CD, ADDR, buf, sizeof(buf)); \ | ||
36 | if (!_success) goto done; \ | ||
37 | } while(0) | ||
38 | |||
39 | #define send_cmd_static(ssd1306, ...) \ | ||
40 | do{ \ | ||
41 | static const uint8_t buf[] = { CTRL_CMD_STREAM, __VA_ARGS__ }; \ | ||
42 | bool _success = _send_cmd(I2CD, ADDR, buf, sizeof(buf)); \ | ||
43 | if (!_success) goto done; \ | ||
44 | } while(0) | ||
45 | |||
46 | #define CMD1(c) c | ||
47 | #define CMD2(c, d) c, d | ||
48 | #define CMD3(c, d, e) c, d, e | ||
49 | |||
50 | static bool _send_cmd(I2CDriver *i2cd, uint8_t addr, const uint8_t *buf, int len) { | ||
51 | |||
52 | msg_t status = i2cMasterTransmitTimeout(i2cd, addr, | ||
53 | buf, len, NULL, 0, CMD_TRANSMIT_TIMEOUT); | ||
54 | |||
55 | if (MSG_OK != status) { | ||
56 | /* i2cflags_t error_code = i2cGetErrors(i2cd); */ | ||
57 | return false; | ||
58 | } | ||
59 | |||
60 | return true; | ||
61 | } | ||
62 | |||
63 | #define send_data(ssd1306, buf, len) \ | ||
64 | do { \ | ||
65 | bool _success = _send_data(I2CD, ADDR, buf, len); \ | ||
66 | if (!_success) goto done; \ | ||
67 | } while(0) | ||
68 | |||
69 | static bool _send_data(I2CDriver *i2cd, uint8_t addr, const uint8_t *buf, int len) { | ||
70 | bool success = false; | ||
71 | |||
72 | msg_t status = i2cMasterTransmitTimeout(i2cd, addr, | ||
73 | buf, len, NULL, 0, DATA_TRANSMIT_TIMEOUT); | ||
74 | |||
75 | if (MSG_OK != status) { | ||
76 | /* i2cflags_t error_code = i2cGetErrors(I2CD); */ | ||
77 | goto done; | ||
78 | } | ||
79 | |||
80 | success = true; | ||
81 | |||
82 | done: | ||
83 | return success; | ||
84 | } | ||
85 | |||
86 | bool ssd1306_init(SSD1306_DRIVER *ssd1306) { | ||
87 | bool success = false; | ||
88 | uint8_t width = ssd1306->width; | ||
89 | uint8_t height = ssd1306->height; | ||
90 | uint8_t num_pages = height / 8; | ||
91 | |||
92 | i2cStart(I2CD, ssd1306->i2ccfg); | ||
93 | |||
94 | send_cmd_static(ssd1306, | ||
95 | CMD1(SetDisplayOff), | ||
96 | CMD1(DeactivateScroll), | ||
97 | CMD1(DisableEntireDisplayOn), | ||
98 | CMD2(SetOscFreqAndClkDiv, 0x80), | ||
99 | CMD2(SetDisplayOffset, 0x00), | ||
100 | CMD1(SetDisplayStartLine | 0x00), | ||
101 | CMD2(SetMemoryAddressMode, 0x00)); /* Horizontal Addressing Mode */ | ||
102 | |||
103 | send_cmd(ssd1306, CMD2(SetMultiplexRatio, height - 1)); | ||
104 | |||
105 | if (ssd1306->rotate180) { | ||
106 | /* rotate 180 degrees == upside down */ | ||
107 | send_cmd_static(ssd1306, | ||
108 | CMD1(SetSegmentRemapReverse), | ||
109 | CMD1(SetComScanOrderReverse)); | ||
110 | } else { | ||
111 | /* no rotation */ | ||
112 | send_cmd_static(ssd1306, | ||
113 | CMD1(SetSegmentRemapNormal), | ||
114 | CMD1(SetComScanOrderNormal)); | ||
115 | } | ||
116 | |||
117 | if (height == 32) { | ||
118 | /* 128x32 module uses SequentialComMode */ | ||
119 | send_cmd_static(ssd1306, CMD2(SetComPins, 0x02)); | ||
120 | } else { | ||
121 | /* 128x64 module uses AlternativeComMode */ | ||
122 | send_cmd_static(ssd1306, CMD2(SetComPins, 0x12)); | ||
123 | } | ||
124 | |||
125 | /* Clear Graphic Display Data RAM */ | ||
126 | send_cmd(ssd1306, | ||
127 | CMD3(SetPageAddress, 0, num_pages - 1), | ||
128 | CMD3(SetColumnAddress, 0, width - 1)); | ||
129 | |||
130 | uint8_t *buf = ssd1306->buf; | ||
131 | size_t len = SSD1306_PREAMBLE_LENGTH + num_pages * width; | ||
132 | memset(buf, 0, len); | ||
133 | buf[0] = CTRL_DATA_STREAM; /* need this byte proceeding the actual data */ | ||
134 | send_data(ssd1306, buf, len); | ||
135 | |||
136 | send_cmd_static(ssd1306, | ||
137 | CMD2(SetPreChargePeriod, 0xC4), | ||
138 | CMD2(SetVcomhLevel, 0x20), | ||
139 | CMD1(SetNormalDisplay), | ||
140 | CMD2(SetContrastControl, 0x3F), | ||
141 | CMD2(ChargePumpSetting, 0x14), | ||
142 | CMD1(SetDisplayOn)); | ||
143 | |||
144 | success = true; | ||
145 | |||
146 | done: | ||
147 | i2cStop(I2CD); | ||
148 | return success; | ||
149 | } | ||
150 | |||
151 | bool ssd1306_data(SSD1306_DRIVER *ssd1306) { | ||
152 | bool success = false; | ||
153 | uint8_t width = ssd1306->width; | ||
154 | uint8_t height = ssd1306->height; | ||
155 | uint8_t num_pages = height / 8; | ||
156 | |||
157 | i2cStart(I2CD, ssd1306->i2ccfg); | ||
158 | |||
159 | /* Transfer to Graphic Display Data RAM */ | ||
160 | send_cmd(ssd1306, | ||
161 | CMD3(SetPageAddress, 0, num_pages - 1), | ||
162 | CMD3(SetColumnAddress, 0, width - 1)); | ||
163 | |||
164 | uint8_t *buf = ssd1306->buf; | ||
165 | size_t len = SSD1306_PREAMBLE_LENGTH + num_pages * width; | ||
166 | send_data(ssd1306, buf, len); | ||
167 | |||
168 | success = true; | ||
169 | |||
170 | done: | ||
171 | i2cStop(I2CD); | ||
172 | return success; | ||
173 | } | ||
174 | |||
175 | bool ssd1306_display_on(SSD1306_DRIVER *ssd1306) { | ||
176 | bool success = false; | ||
177 | i2cStart(I2CD, ssd1306->i2ccfg); | ||
178 | send_cmd_static(ssd1306, CMD1(SetDisplayOn)); | ||
179 | success = true; | ||
180 | done: | ||
181 | i2cStop(I2CD); | ||
182 | return success; | ||
183 | } | ||
184 | |||
185 | bool ssd1306_display_off(SSD1306_DRIVER *ssd1306) { | ||
186 | bool success = false; | ||
187 | i2cStart(I2CD, ssd1306->i2ccfg); | ||
188 | send_cmd_static(ssd1306, CMD1(SetDisplayOff)); | ||
189 | success = true; | ||
190 | done: | ||
191 | i2cStop(I2CD); | ||
192 | return success; | ||
193 | } | ||