SSD1306 OLED display driver 1.8.2 This library is developed to control SSD1306/SSD1331/SSD1351/IL9163/PCD8554 RGB i2c/spi LED displays

platform.c
1 /*
2 MIT License
3
4 Copyright (c) 2018-2019, Alexey Dynda
5
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to deal
8 in the Software without restriction, including without limitation the rights
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 copies of the Software, and to permit persons to whom the Software is
11 furnished to do so, subject to the following conditions:
12
13 The above copyright notice and this permission notice shall be included in all
14 copies or substantial portions of the Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 SOFTWARE.
23 */
24
25 #include "ssd1306_hal/io.h"
26
27 #if defined(SSD1306_ESP_PLATFORM)
28
29 #include "intf/ssd1306_interface.h"
30 #include "intf/spi/ssd1306_spi.h"
31 #include "freertos/FreeRTOS.h"
32 #include "freertos/task.h"
33 #include "driver/gpio.h"
34
35 #if 1
36
37 #if defined(CONFIG_PLATFORM_SPI_AVAILABLE) && defined(CONFIG_PLATFORM_SPI_ENABLE)
38 static void platform_spi_send_cache();
39 #endif
40
41 // TODO: To complete support. Any help is welcome
42 int digitalRead(int pin) // digitalRead()
43 {
44 return gpio_get_level(pin);
45 }
46
47 void digitalWrite(int pin, int level) // digitalWrite()
48 {
49 #if defined(CONFIG_PLATFORM_SPI_AVAILABLE) && defined(CONFIG_PLATFORM_SPI_ENABLE)
50 if (s_ssd1306_dc == pin)
51 {
52 platform_spi_send_cache();
53 }
54 #endif
55 gpio_set_level(pin, level);
56 }
57
58 void pinMode(int pin, int mode)
59 {
60 if (mode == INPUT)
61 gpio_set_direction(pin, GPIO_MODE_INPUT);
62 else if (mode == OUTPUT)
63 gpio_set_direction(pin, GPIO_MODE_OUTPUT);
64 }
65
66 uint32_t millis(void)
67 {
68 return xTaskGetTickCount() * portTICK_PERIOD_MS;
69 }
70
71 void delay(uint32_t ms) // delay()
72 {
73 vTaskDelay(ms / portTICK_PERIOD_MS);
74 }
75
76 #endif
77
79 // !!! PLATFORM I2C IMPLEMENTATION OPTIONAL !!!
80 #if defined(CONFIG_PLATFORM_I2C_AVAILABLE) && defined(CONFIG_PLATFORM_I2C_ENABLE)
81
82 #include <stdio.h>
83 #include "driver/i2c.h"
84
85 static uint8_t s_i2c_addr = 0x3C;
86 static int8_t s_bus_id;
87
88 static i2c_cmd_handle_t s_cmd_handle;
89
90 static void platform_i2c_start(void)
91 {
92 // ... Open i2c channel for your device with specific s_i2c_addr
93 s_cmd_handle = i2c_cmd_link_create();
94 i2c_master_start(s_cmd_handle);
95 i2c_master_write_byte(s_cmd_handle, ( s_i2c_addr << 1 ) | I2C_MASTER_WRITE, 0x1);
96 }
97
98 static void platform_i2c_stop(void)
99 {
100 // ... Complete i2c communication
101 i2c_master_stop(s_cmd_handle);
102 /*esp_err_t ret =*/ i2c_master_cmd_begin(s_bus_id, s_cmd_handle, 1000 / portTICK_RATE_MS);
103 i2c_cmd_link_delete(s_cmd_handle);
104 }
105
106 static void platform_i2c_send(uint8_t data)
107 {
108 // ... Send byte to i2c communication channel
109 i2c_master_write_byte(s_cmd_handle, data, 0x1);
110 }
111
112 static void platform_i2c_close(void)
113 {
114 // ... free all i2c resources here
115 i2c_driver_delete(s_bus_id);
116 }
117
118 static void platform_i2c_send_buffer(const uint8_t *data, uint16_t len)
119 {
120 // ... Send len bytes to i2c communication channel here
121 while (len--)
122 {
123 platform_i2c_send(*data);
124 data++;
125 }
126 // i2c_master_write(cmd, data_wr, size, ACK_CHECK_EN);
127 }
128
129 void ssd1306_platform_i2cInit(int8_t busId, uint8_t addr, ssd1306_platform_i2cConfig_t * cfg)
130 {
131 if (addr) s_i2c_addr = addr;
132 ssd1306_intf.spi = 0;
133 ssd1306_intf.start = &platform_i2c_start;
134 ssd1306_intf.stop = &platform_i2c_stop;
135 ssd1306_intf.send = &platform_i2c_send;
136 ssd1306_intf.close = &platform_i2c_close;
137 ssd1306_intf.send_buffer = &platform_i2c_send_buffer;
138 // init your interface here
139 if ( busId < 0) busId = I2C_NUM_1;
140 s_bus_id = busId;
141 i2c_config_t conf;
142 conf.mode = I2C_MODE_MASTER;
143 conf.sda_io_num = cfg->sda >= 0 ? cfg->sda : 21;
144 conf.sda_pullup_en = GPIO_PULLUP_ENABLE;
145 conf.scl_io_num = cfg->scl >= 0 ? cfg->scl : 22;
146 conf.scl_pullup_en = GPIO_PULLUP_ENABLE;
147 conf.master.clk_speed = 400000; //I2C_EXAMPLE_MASTER_FREQ_HZ;
148 i2c_param_config(s_bus_id, &conf);
149 i2c_driver_install(s_bus_id, conf.mode, 0, 0, 0);
150 // I2C_EXAMPLE_MASTER_RX_BUF_DISABLE,
151 // I2C_EXAMPLE_MASTER_TX_BUF_DISABLE, 0);
152 }
153 #endif
154
156 // !!! PLATFORM SPI IMPLEMENTATION OPTIONAL !!!
157 #if defined(CONFIG_PLATFORM_SPI_AVAILABLE) && defined(CONFIG_PLATFORM_SPI_ENABLE)
158
159 #include "intf/spi/ssd1306_spi.h"
160 #include "driver/spi_master.h"
161
162 // Store spi handle globally for all spi callbacks
163 static spi_device_handle_t s_spi;
164 static int8_t s_spi_bus_id;
165 // s_first_spi_session is used for delayed spi initialization.
166 // Some oled displays have slow max SPI speed, so display init function can change
167 // spi frequency s_ssd1306_spi_clock. Register device, only when frequency is known.
168 static uint8_t s_first_spi_session = 0;
169 static uint8_t s_spi_cache[1024];
170 static int s_spi_cached_count = 0;
171
172 static void platform_spi_send_cache()
173 {
174 /* TODO: Yeah, sending single bytes is too slow, but *
175 * need to figure out how to detect data/command bytes *
176 * to send bytes as one block */
177 uint8_t *data = s_spi_cache;
178 while (s_spi_cached_count)
179 {
180 size_t sz = s_spi_cached_count > 32 ? 32: s_spi_cached_count;
181 spi_transaction_t t;
182 memset(&t, 0, sizeof(t));
183 t.length=8*sz; // 8 bits
184 t.tx_buffer=data;
185 // ... Send byte to spi communication channel
186 // We do not care here about DC line state, because
187 // ssd1306 library already set DC pin via ssd1306_spiDataMode() before call to send().
188 spi_device_transmit(s_spi, &t);
189 data+=sz;
190 s_spi_cached_count-=sz;
191 }
192 s_spi_cached_count = 0;
193 }
194
195 static void platform_spi_start(void)
196 {
197 // ... Open spi channel for your device with specific s_ssd1306_cs, s_ssd1306_dc
198 if (s_first_spi_session)
199 {
200 spi_device_interface_config_t devcfg=
201 {
202 .clock_speed_hz = s_ssd1306_spi_clock,
203 .mode=0,
204 .spics_io_num=s_ssd1306_cs,
205 .queue_size=7, // max 7 transactions at a time
206 };
207 spi_bus_add_device(s_spi_bus_id ? VSPI_HOST : HSPI_HOST, &devcfg, &s_spi);
208 s_first_spi_session = 0;
209 }
210 s_spi_cached_count = 0;
211 }
212
213 static void platform_spi_stop(void)
214 {
215 // ... Complete spi communication
216 // no complete actions required for this implementation
217 platform_spi_send_cache();
218 }
219
220 static void platform_spi_send(uint8_t data)
221 {
222 s_spi_cache[s_spi_cached_count] = data;
223 s_spi_cached_count++;
224 if ( s_spi_cached_count >= sizeof( s_spi_cache ) )
225 {
226 platform_spi_send_cache();
227 }
228 }
229
230 static void platform_spi_close(void)
231 {
232 // ... free all spi resources here
233 if (!s_first_spi_session)
234 {
235 spi_bus_remove_device( s_spi );
236 }
237 spi_bus_free( s_spi_bus_id ? VSPI_HOST : HSPI_HOST );
238 }
239
240 static void platform_spi_send_buffer(const uint8_t *data, uint16_t len)
241 {
242 while (len--)
243 {
244 platform_i2c_send(*data);
245 data++;
246 }
247 }
248
249 void ssd1306_platform_spiInit(int8_t busId,
250 int8_t cesPin,
251 int8_t dcPin)
252 {
253 // Use VSPI by default
254 if (busId < 0) busId = 1;
255 s_spi_bus_id = busId;
256
257 // If cesPin is not provided, select by default
258 if (cesPin < 0)
259 {
260 cesPin = s_spi_bus_id ? 5 : 15;
261 }
262 s_ssd1306_cs = cesPin;
263 if (dcPin>=0) s_ssd1306_dc = dcPin;
264
265 if (cesPin >=0) pinMode(cesPin, OUTPUT);
266 if (dcPin >= 0) pinMode(dcPin, OUTPUT);
267
268 ssd1306_intf.spi = 1;
269 ssd1306_intf.start = &platform_spi_start;
270 ssd1306_intf.stop = &platform_spi_stop;
271 ssd1306_intf.send = &platform_spi_send;
272 ssd1306_intf.close = &platform_spi_close;
273 ssd1306_intf.send_buffer = &platform_spi_send_buffer;
274
275 // init your interface here
276 spi_bus_config_t buscfg=
277 {
278 .miso_io_num= s_spi_bus_id ? 19 : 12,
279 .mosi_io_num= s_spi_bus_id ? 23 : 13,
280 .sclk_io_num= s_spi_bus_id ? 18 : 14,
281 .quadwp_io_num=-1,
282 .quadhd_io_num=-1,
283 .max_transfer_sz=32
284 };
285 spi_bus_initialize(s_spi_bus_id ? VSPI_HOST : HSPI_HOST, &buscfg, 0); // 0 -no dma
286 s_first_spi_session = 1;
287 }
288 #endif
289
290 #endif // SSD1306_ESP_PLATFORM
ssd1306_platform_i2cConfig_t::scl
int8_t scl
clock pin number
Definition: io.h:82
s_ssd1306_dc
int8_t s_ssd1306_dc
Definition: ssd1306_spi.c:34
ssd1306_platform_i2cConfig_t
Definition: io.h:80
ssd1306_platform_spiInit
void ssd1306_platform_spiInit(int8_t busId, int8_t cesPin, int8_t dcPin)
Initializes spi interface for platform being used.
ssd1306_interface_t::send
void(* send)(uint8_t data)
Definition: ssd1306_interface.h:70
ssd1306_interface_t::stop
void(* stop)(void)
Definition: ssd1306_interface.h:65
s_ssd1306_spi_clock
uint32_t s_ssd1306_spi_clock
Definition: ssd1306_spi.c:35
io.h
ssd1306_platform_i2cInit
void ssd1306_platform_i2cInit(int8_t busId, uint8_t addr, ssd1306_platform_i2cConfig_t *cfg)
Initializes i2c interface for platform being used.
ssd1306_spi.h
ssd1306_interface_t::start
void(* start)(void)
Definition: ssd1306_interface.h:61
ssd1306_interface_t::close
void(* close)(void)
deinitializes internal resources, allocated for interface.
Definition: ssd1306_interface.h:88
ssd1306_intf
ssd1306_interface_t ssd1306_intf
Definition: ssd1306_interface.c:31
ssd1306_platform_i2cConfig_t::sda
int8_t sda
data pin number
Definition: io.h:81
ssd1306_interface.h
ssd1306_interface_t::spi
uint8_t spi
Definition: ssd1306_interface.h:57
ssd1306_interface_t::send_buffer
void(* send_buffer)(const uint8_t *buffer, uint16_t size)
Sends bytes to SSD1306 device.
Definition: ssd1306_interface.h:80
s_ssd1306_cs
int8_t s_ssd1306_cs
Definition: ssd1306_spi.c:33