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"
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();
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__
void ssd1306_platform_i2cInit(int8_t busId, uint8_t addr, int8_t arg)
Initializes i2c interface for platform being used.
int8_t s_ssd1306_dc
Definition: ssd1306_spi.c:34
void ssd1306_platform_spiInit(int8_t busId, int8_t cesPin, int8_t dcPin)
Initializes spi interface for platform being used.
void(* send)(uint8_t data)
uint32_t s_ssd1306_spi_clock
Definition: ssd1306_spi.c:35
void(* close)(void)
deinitializes internal resources, allocated for interface.
ssd1306_interface_t ssd1306_intf
#define SSD1306_SA
void(* send_buffer)(const uint8_t *buffer, uint16_t size)
Sends bytes to SSD1306 device.
int8_t s_ssd1306_cs
Definition: ssd1306_spi.c:33