SSD1306 OLED display driver 1.7.8 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, 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 #if defined(__linux__) && !defined(ARDUINO)
26
27 #include "ssd1306_hal/io.h"
28 #include "intf/ssd1306_interface.h"
29 #include "intf/i2c/ssd1306_i2c.h"
30 #include "intf/spi/ssd1306_spi_conf.h"
31 #include "intf/spi/ssd1306_spi.h"
32
33 #ifndef __KERNEL__
34
35 #include <sys/stat.h>
36 #include <sys/types.h>
37 #include <errno.h>
38 #include <fcntl.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <unistd.h>
42 #include <sys/ioctl.h>
43 #include <linux/i2c-dev.h>
44 #include <linux/spi/spidev.h>
45
46 #define MAX_GPIO_COUNT 256
47
48 #ifdef IN
49 #undef IN
50 #endif
51 #define IN 0
52
53 #ifdef OUT
54 #undef OUT
55 #endif
56 #define OUT 1
57
58 int gpio_export(int pin)
59 {
60 char buffer[4];
61 ssize_t bytes_written;
62 int fd;
63 char path[64];
64
65 snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d", pin);
66
67 if (access(path, F_OK) == 0)
68 {
69 return 0;
70 }
71
72 fd = open("/sys/class/gpio/export", O_WRONLY);
73 if (-1 == fd)
74 {
75 fprintf(stderr, "Failed to allocate gpio pin resources[%d]: %s!\n", pin, strerror (errno));
76 return(-1);
77 }
78
79 bytes_written = snprintf(buffer, sizeof(buffer), "%d", pin);
80 if (write(fd, buffer, bytes_written) < 0)
81 {
82 fprintf(stderr, "Failed to allocate gpio pin resources[%d]: %s!\n", pin, strerror (errno));
83 close(fd);
84 return -1;
85 }
86 close(fd);
87 return(0);
88 }
89
90 int gpio_unexport(int pin)
91 {
92 char buffer[4];
93 ssize_t bytes_written;
94 int fd;
95
96 fd = open("/sys/class/gpio/unexport", O_WRONLY);
97 if (-1 == fd)
98 {
99 fprintf(stderr, "Failed to free gpio pin resources!\n");
100 return(-1);
101 }
102
103 bytes_written = snprintf(buffer, sizeof(buffer), "%d", pin);
104 if (write(fd, buffer, bytes_written) < 0)
105 {
106 fprintf(stderr, "Failed to free gpio pin resources!\n");
107 }
108 close(fd);
109 return(0);
110 }
111
112 int gpio_direction(int pin, int dir)
113 {
114 static const char s_directions_str[] = "in\0out";
115
116 char path[64];
117 int fd;
118
119 snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/direction", pin);
120 fd = open(path, O_WRONLY);
121 if (-1 == fd)
122 {
123 fprintf(stderr, "Failed to set gpio pin direction1[%d]: %s!\n", pin, strerror(errno));
124 return(-1);
125 }
126
127 if (-1 == write(fd, &s_directions_str[IN == dir ? 0 : 3], IN == dir ? 2 : 3))
128 {
129 fprintf(stderr, "Failed to set gpio pin direction2[%d]: %s!\n", pin, strerror(errno));
130 return(-1);
131 }
132
133 close(fd);
134 return(0);
135 }
136
137 int gpio_read(int pin)
138 {
139 char path[32];
140 char value_str[3];
141 int fd;
142
143 snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/value", pin);
144 fd = open(path, O_RDONLY);
145 if (-1 == fd)
146 {
147 fprintf(stderr, "Failed to read gpio pin value!\n");
148 return(-1);
149 }
150
151 if (-1 == read(fd, value_str, 3))
152 {
153 fprintf(stderr, "Failed to read gpio pin value!\n");
154 return(-1);
155 }
156
157 close(fd);
158
159 return(atoi(value_str));
160 }
161
162 int gpio_write(int pin, int value)
163 {
164 static const char s_values_str[] = "01";
165
166 char path[64];
167 int fd;
168
169 snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/value", pin);
170 fd = open(path, O_WRONLY);
171 if (-1 == fd)
172 {
173 fprintf(stderr, "Failed to set gpio pin value[%d]: %s!\n", pin, strerror(errno));
174 return(-1);
175 }
176
177 if (1 != write(fd, &s_values_str[LOW == value ? 0 : 1], 1))
178 {
179 fprintf(stderr, "Failed to set gpio pin value[%d]: %s!\n", pin, strerror (errno));
180 return(-1);
181 }
182
183 close(fd);
184 return(0);
185 }
186
187 #if !defined(SDL_EMULATION)
188
189 static uint8_t s_exported_pin[MAX_GPIO_COUNT] = {0};
190 static uint8_t s_pin_mode[MAX_GPIO_COUNT] = {0};
191
192 void pinMode(int pin, int mode)
193 {
194 if (!s_exported_pin[pin])
195 {
196 if ( gpio_export(pin)<0 )
197 {
198 return;
199 }
200 s_exported_pin[pin] = 1;
201 }
202 if (mode == OUTPUT)
203 {
204 gpio_direction(pin, OUT);
205 s_pin_mode[pin] = 1;
206 }
207 if (mode == INPUT)
208 {
209 gpio_direction(pin, IN);
210 s_pin_mode[pin] = 0;
211 }
212 }
213
214 void digitalWrite(int pin, int level)
215 {
216 if (!s_exported_pin[pin])
217 {
218 if ( gpio_export(pin)<0 )
219 {
220 return;
221 }
222 s_exported_pin[pin] = 1;
223 }
224 if (!s_pin_mode[pin])
225 {
226 pinMode(pin, OUTPUT);
227 }
228 gpio_write( pin, level );
229 }
230
231 #endif // SDL_EMULATION
232
234 // LINUX I2C IMPLEMENTATION
236 #if defined(CONFIG_PLATFORM_I2C_AVAILABLE) && defined(CONFIG_PLATFORM_I2C_ENABLE)
237
238
239
240 #if !defined(SDL_EMULATION)
241
242
243 static uint8_t s_sa = SSD1306_SA;
244 static int s_fd = -1;
245 static uint8_t s_buffer[128];
246 static uint8_t s_dataSize = 0;
247
248 static void platform_i2c_start(void)
249 {
250 s_dataSize = 0;
251 }
252
253 static void platform_i2c_stop(void)
254 {
255 if (write(s_fd, s_buffer, s_dataSize) != s_dataSize)
256 {
257 fprintf(stderr, "Failed to write to the i2c bus: %s.\n", strerror(errno));
258 }
259 s_dataSize = 0;
260 }
261
262 static void platform_i2c_send(uint8_t data)
263 {
264 s_buffer[s_dataSize] = data;
265 s_dataSize++;
266 if (s_dataSize == sizeof(s_buffer))
267 {
268 /* Send function puts all data to internal buffer. *
269 * Restart transmission if internal buffer is full. */
270 ssd1306_intf.stop();
271 ssd1306_intf.start();
272 ssd1306_intf.send(0x40);
273 }
274 }
275
276 static void platform_i2c_send_buffer(const uint8_t *buffer, uint16_t size)
277 {
278 while (size--)
279 {
280 platform_i2c_send(*buffer);
281 buffer++;
282 }
283 }
284
285 static void platform_i2c_close()
286 {
287 if (s_fd >= 0)
288 {
289 close(s_fd);
290 s_fd = -1;
291 }
292 }
293
294 static void empty_function()
295 {
296 }
297
298 static void empty_function_single_arg(uint8_t arg)
299 {
300 }
301
302 static void empty_function_two_args(const uint8_t *arg1, uint16_t arg2)
303 {
304 }
305
306 void ssd1306_platform_i2cInit(int8_t busId, uint8_t sa, int8_t arg)
307 {
308 char filename[20];
309 if (busId < 0)
310 {
311 busId = 1;
312 }
313 snprintf(filename, 19, "/dev/i2c-%d", busId);
314 ssd1306_intf.start = empty_function;
315 ssd1306_intf.stop = empty_function;
316 ssd1306_intf.close = empty_function;
317 ssd1306_intf.send = empty_function_single_arg;
318 ssd1306_intf.send_buffer = empty_function_two_args;
319 if ((s_fd = open(filename, O_RDWR)) < 0)
320 {
321 fprintf(stderr, "Failed to open the i2c bus\n");
322 return;
323 }
324 if (sa)
325 {
326 s_sa = sa;
327 }
328 if (ioctl(s_fd, I2C_SLAVE, s_sa) < 0)
329 {
330 fprintf(stderr, "Failed to acquire bus access and/or talk to slave.\n");
331 return;
332 }
333 ssd1306_intf.start = platform_i2c_start;
334 ssd1306_intf.stop = platform_i2c_stop;
335 ssd1306_intf.send = platform_i2c_send;
336 ssd1306_intf.send_buffer = platform_i2c_send_buffer;
337 ssd1306_intf.close = platform_i2c_close;
338 }
339
340 #else /* SDL_EMULATION */
341
342 #include "sdl_core.h"
343
344 static void platform_i2c_send_buffer(const uint8_t *buffer, uint16_t size)
345 {
346 while (size--)
347 {
348 sdl_send_byte(*buffer);
349 buffer++;
350 };
351 }
352
353 void ssd1306_platform_i2cInit(int8_t busId, uint8_t sa, int8_t arg)
354 {
355 sdl_core_init();
356 ssd1306_intf.spi = 0;
357 ssd1306_intf.start = sdl_send_init;
358 ssd1306_intf.stop = sdl_send_stop;
359 ssd1306_intf.send = sdl_send_byte;
360 ssd1306_intf.send_buffer = platform_i2c_send_buffer;
361 ssd1306_intf.close = sdl_core_close;
362 }
363
364 #endif /* SDL_EMULATION */
365
366 #endif // CONFIG_PLATFORM_I2C_AVAILABLE
367
368
370 // LINUX SPI IMPLEMENTATION
372 #if defined(CONFIG_PLATFORM_SPI_AVAILABLE) && defined(CONFIG_PLATFORM_SPI_ENABLE)
373
374 #if !defined(SDL_EMULATION)
375
376 static int s_spi_fd = -1;
377 extern uint32_t s_ssd1306_spi_clock;
378
379 static void platform_spi_start(void)
380 {
381 }
382
383 static void platform_spi_stop(void)
384 {
385 }
386
387 static void platform_spi_send(uint8_t data)
388 {
389 /* TODO: Yeah, sending single bytes is too slow, but *
390 * need to figure out how to detect data/command bytes *
391 * to send bytes as one block */
392 uint8_t buf[1];
393 struct spi_ioc_transfer mesg;
394 buf[0] = data;
395 memset(&mesg, 0, sizeof mesg);
396 mesg.tx_buf = (unsigned long)&buf[0];
397 mesg.rx_buf = 0;
398 mesg.len = 1;
399 mesg.delay_usecs = 0;
400 mesg.speed_hz = 0;
401 mesg.bits_per_word = 8;
402 mesg.cs_change = 0;
403 if (ioctl(s_spi_fd, SPI_IOC_MESSAGE(1), &mesg) < 1)
404 {
405 fprintf(stderr, "SPI failed to send SPI message: %s\n", strerror (errno)) ;
406 }
407 }
408
409 static void platform_spi_close(void)
410 {
411 if (s_spi_fd >= 0)
412 {
413 close(s_spi_fd);
414 s_spi_fd = -1;
415 }
416 }
417
418 static void platform_spi_send_buffer(const uint8_t *data, uint16_t len)
419 {
420 while (len--)
421 {
422 platform_spi_send(*data);
423 data++;
424 }
425 }
426
427 static void empty_function_spi(void)
428 {
429 }
430
431 static void empty_function_arg_spi(uint8_t byte)
432 {
433 }
434
435 static void empty_function_args_spi(const uint8_t *buffer, uint16_t bytes)
436 {
437 }
438
439 void ssd1306_platform_spiInit(int8_t busId,
440 int8_t ces,
441 int8_t dcPin)
442 {
443 char filename[20];
444 if (busId < 0)
445 {
446 busId = 0;
447 }
448 if (ces < 0)
449 {
450 ces = 0;
451 }
452 s_ssd1306_cs = -1; // SPI interface does't need separate ces pin
453 s_ssd1306_dc = dcPin;
454 ssd1306_intf.spi = 1;
455 ssd1306_intf.start = empty_function_spi;
456 ssd1306_intf.stop = empty_function_spi;
457 ssd1306_intf.send = empty_function_arg_spi;
458 ssd1306_intf.send_buffer = empty_function_args_spi;
459 ssd1306_intf.close = empty_function;
460
461 snprintf(filename, 19, "/dev/spidev%d.%d", busId, ces);
462 if ((s_spi_fd = open(filename, O_RDWR)) < 0)
463 {
464 printf("Failed to initialize SPI: %s!\n", strerror(errno));
465 return;
466 }
467 unsigned int speed = s_ssd1306_spi_clock;
468 if (ioctl(s_spi_fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed) < 0)
469 {
470 printf("Failed to set speed on SPI line: %s!\n", strerror(errno));
471 }
472 uint8_t mode = SPI_MODE_0;
473 if (ioctl (s_spi_fd, SPI_IOC_WR_MODE, &mode) < 0)
474 {
475 printf("Failed to set SPI mode: %s!\n", strerror(errno));
476 }
477 uint8_t spi_bpw = 8;
478 if (ioctl (s_spi_fd, SPI_IOC_WR_BITS_PER_WORD, &spi_bpw) < 0)
479 {
480 printf("Failed to set SPI BPW: %s!\n", strerror(errno));
481 }
482
483 ssd1306_intf.spi = 1;
484 ssd1306_intf.start = platform_spi_start;
485 ssd1306_intf.stop = platform_spi_stop;
486 ssd1306_intf.send = platform_spi_send;
487 ssd1306_intf.send_buffer = platform_spi_send_buffer;
488 ssd1306_intf.close = platform_spi_close;
489 }
490
491 #else /* SDL_EMULATION */
492
493 #include "sdl_core.h"
494
495 static void sdl_send_bytes(const uint8_t *buffer, uint16_t size)
496 {
497 while (size--)
498 {
499 sdl_send_byte(*buffer);
500 buffer++;
501 };
502 }
503
504 void ssd1306_platform_spiInit(int8_t busId, int8_t ces, int8_t dcPin)
505 {
506 sdl_core_init();
507 if (ces >= 0)
508 {
509 s_ssd1306_cs = ces;
510 }
511 if (dcPin >= 0)
512 {
513 s_ssd1306_dc = dcPin;
514 }
515 sdl_set_dc_pin(dcPin);
516 ssd1306_intf.spi = 1;
517 ssd1306_intf.start = sdl_send_init;
518 ssd1306_intf.stop = sdl_send_stop;
519 ssd1306_intf.send = sdl_send_byte;
520 ssd1306_intf.send_buffer = sdl_send_bytes;
521 ssd1306_intf.close = sdl_core_close;
522 }
523
524 #endif /* SDL_EMULATION */
525
526 #endif // CONFIG_PLATFORM_SPI_AVAILABLE
527
528 #endif // !KERNEL
529
530 #endif // __linux__
ssd1306_platform_i2cInit
void ssd1306_platform_i2cInit(int8_t busId, uint8_t addr, int8_t arg)
Initializes i2c interface for platform being used.
s_ssd1306_dc
int8_t s_ssd1306_dc
Definition: ssd1306_spi.c:34
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_i2c.h
ssd1306_spi_conf.h
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:29
SSD1306_SA
#define SSD1306_SA
Definition: ssd1306_i2c_conf.h:47
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