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, 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(__MINGW32__)
26 
27 #include "ssd1306_hal/io.h"
28 
29 #include "intf/ssd1306_interface.h"
30 #include "intf/i2c/ssd1306_i2c.h"
31 #include "intf/ssd1306_interface.h"
33 #include "intf/spi/ssd1306_spi.h"
34 
35 #include <stdio.h>
36 #include <unistd.h>
37 
38 #if !defined(SDL_EMULATION)
39 
40 #include <errno.h>
41 #include <fcntl.h>
42 #include <sys/ioctl.h>
43 #include <linux/i2c-dev.h>
44 #include <stdlib.h>
45 #include <linux/spi/spidev.h>
46 
47 #endif
48 
50 // MINGW I2C IMPLEMENTATION
52 #if defined(CONFIG_PLATFORM_I2C_AVAILABLE) && defined(CONFIG_PLATFORM_I2C_ENABLE)
53 
54 #if !defined(SDL_EMULATION)
55 
56 static uint8_t s_sa = SSD1306_SA;
57 static int s_fd = -1;
58 static uint8_t s_buffer[128];
59 static uint8_t s_dataSize = 0;
60 
61 static void platform_i2c_start(void)
62 {
63  s_dataSize = 0;
64 }
65 
66 static void platform_i2c_stop(void)
67 {
68  if (write(s_fd, s_buffer, s_dataSize) != s_dataSize)
69  {
70  fprintf(stderr, "Failed to write to the i2c bus: %s.\n", strerror(errno));
71  }
72  s_dataSize = 0;
73 }
74 
75 static void platform_i2c_send(uint8_t data)
76 {
77  s_buffer[s_dataSize] = data;
78  s_dataSize++;
79  if (s_dataSize == sizeof(s_buffer))
80  {
81  /* Send function puts all data to internal buffer. *
82  * Restart transmission if internal buffer is full. */
85  ssd1306_intf.send(0x40);
86  }
87 }
88 
89 static void platform_i2c_send_buffer(const uint8_t *buffer, uint16_t size)
90 {
91  while (size--)
92  {
93  platform_i2c_send(*buffer);
94  buffer++;
95  }
96 }
97 
98 static void platform_i2c_close()
99 {
100  if (s_fd >= 0)
101  {
102  close(s_fd);
103  s_fd = -1;
104  }
105 }
106 
107 static void empty_function()
108 {
109 }
110 
111 static void empty_function_single_arg(uint8_t arg)
112 {
113 }
114 
115 static void empty_function_two_args(const uint8_t *arg1, uint16_t arg2)
116 {
117 }
118 
119 void ssd1306_platform_i2cInit(int8_t busId, uint8_t sa, ssd1306_platform_i2cConfig_t * cfg)
120 {
121  char filename[20];
122  if (busId < 0)
123  {
124  busId = 1;
125  }
126  snprintf(filename, 19, "/dev/i2c-%d", busId);
127  ssd1306_intf.start = empty_function;
128  ssd1306_intf.stop = empty_function;
129  ssd1306_intf.close = empty_function;
130  ssd1306_intf.send = empty_function_single_arg;
131  ssd1306_intf.send_buffer = empty_function_two_args;
132  if ((s_fd = open(filename, O_RDWR)) < 0)
133  {
134  fprintf(stderr, "Failed to open the i2c bus\n");
135  return;
136  }
137  if (sa)
138  {
139  s_sa = sa;
140  }
141  if (ioctl(s_fd, I2C_SLAVE, s_sa) < 0)
142  {
143  fprintf(stderr, "Failed to acquire bus access and/or talk to slave.\n");
144  return;
145  }
146  ssd1306_intf.start = platform_i2c_start;
147  ssd1306_intf.stop = platform_i2c_stop;
148  ssd1306_intf.send = platform_i2c_send;
149  ssd1306_intf.send_buffer = platform_i2c_send_buffer;
150  ssd1306_intf.close = platform_i2c_close;
151 }
152 
153 #else /* SDL_EMULATION */
154 
155 #include "sdl_core.h"
156 
157 static void platform_i2c_send_buffer(const uint8_t *buffer, uint16_t size)
158 {
159  while (size--)
160  {
161  sdl_send_byte(*buffer);
162  buffer++;
163  };
164 }
165 
166 void ssd1306_platform_i2cInit(int8_t busId, uint8_t sa, ssd1306_platform_i2cConfig_t * cfg)
167 {
168  sdl_core_init();
169  ssd1306_intf.spi = 0;
170  ssd1306_intf.start = sdl_send_init;
171  ssd1306_intf.stop = sdl_send_stop;
172  ssd1306_intf.send = sdl_send_byte;
173  ssd1306_intf.send_buffer = platform_i2c_send_buffer;
174  ssd1306_intf.close = sdl_core_close;
175 }
176 
177 #endif /* SDL_EMULATION */
178 
179 #endif // CONFIG_PLATFORM_I2C_AVAILABLE
180 
181 
183 // MINGW SPI IMPLEMENTATION
185 #if defined(CONFIG_PLATFORM_SPI_AVAILABLE) && defined(CONFIG_PLATFORM_SPI_ENABLE)
186 
187 #if !defined(SDL_EMULATION)
188 
189 static int s_spi_fd = -1;
190 extern uint32_t s_ssd1306_spi_clock;
191 
192 static void platform_spi_start(void)
193 {
194 }
195 
196 static void platform_spi_stop(void)
197 {
198 }
199 
200 static void platform_spi_send(uint8_t data)
201 {
202  /* TODO: Yeah, sending single bytes is too slow, but *
203  * need to figure out how to detect data/command bytes *
204  * to send bytes as one block */
205  uint8_t buf[1];
206  struct spi_ioc_transfer mesg;
207  buf[0] = data;
208  memset(&mesg, 0, sizeof mesg);
209  mesg.tx_buf = (unsigned long)&buf[0];
210  mesg.rx_buf = 0;
211  mesg.len = 1;
212  mesg.delay_usecs = 0;
213  mesg.speed_hz = 0;
214  mesg.bits_per_word = 8;
215  mesg.cs_change = 0;
216  if (ioctl(s_spi_fd, SPI_IOC_MESSAGE(1), &mesg) < 1)
217  {
218  fprintf(stderr, "SPI failed to send SPI message: %s\n", strerror (errno)) ;
219  }
220 }
221 
222 static void platform_spi_close(void)
223 {
224  if (s_spi_fd >= 0)
225  {
226  close(s_spi_fd);
227  s_spi_fd = -1;
228  }
229 }
230 
231 static void platform_spi_send_buffer(const uint8_t *data, uint16_t len)
232 {
233  while (len--)
234  {
235  platform_spi_send(*data);
236  data++;
237  }
238 }
239 
240 static void empty_function_spi(void)
241 {
242 }
243 
244 static void empty_function_arg_spi(uint8_t byte)
245 {
246 }
247 
248 static void empty_function_args_spi(const uint8_t *buffer, uint16_t bytes)
249 {
250 }
251 
252 void ssd1306_platform_spiInit(int8_t busId,
253  int8_t ces,
254  int8_t dcPin)
255 {
256  char filename[20];
257  if (busId < 0)
258  {
259  busId = 0;
260  }
261  if (ces < 0)
262  {
263  ces = 0;
264  }
265  s_ssd1306_cs = -1; // SPI interface does't need separate ces pin
266  s_ssd1306_dc = dcPin;
267  ssd1306_intf.spi = 1;
268  ssd1306_intf.start = empty_function_spi;
269  ssd1306_intf.stop = empty_function_spi;
270  ssd1306_intf.send = empty_function_arg_spi;
271  ssd1306_intf.send_buffer = empty_function_args_spi;
272  ssd1306_intf.close = empty_function;
273 
274  snprintf(filename, 19, "/dev/spidev%d.%d", busId, ces);
275  if ((s_spi_fd = open(filename, O_RDWR)) < 0)
276  {
277  printf("Failed to initialize SPI: %s!\n", strerror(errno));
278  return;
279  }
280  unsigned int speed = s_ssd1306_spi_clock;
281  if (ioctl(s_spi_fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed) < 0)
282  {
283  printf("Failed to set speed on SPI line: %s!\n", strerror(errno));
284  }
285  uint8_t mode = SPI_MODE_0;
286  if (ioctl (s_spi_fd, SPI_IOC_WR_MODE, &mode) < 0)
287  {
288  printf("Failed to set SPI mode: %s!\n", strerror(errno));
289  }
290  uint8_t spi_bpw = 8;
291  if (ioctl (s_spi_fd, SPI_IOC_WR_BITS_PER_WORD, &spi_bpw) < 0)
292  {
293  printf("Failed to set SPI BPW: %s!\n", strerror(errno));
294  }
295 
296  ssd1306_intf.spi = 1;
297  ssd1306_intf.start = platform_spi_start;
298  ssd1306_intf.stop = platform_spi_stop;
299  ssd1306_intf.send = platform_spi_send;
300  ssd1306_intf.send_buffer = platform_spi_send_buffer;
301  ssd1306_intf.close = platform_spi_close;
302 }
303 
304 #else /* SDL_EMULATION */
305 
306 #include "sdl_core.h"
307 
308 static void sdl_send_bytes(const uint8_t *buffer, uint16_t size)
309 {
310  while (size--)
311  {
312  sdl_send_byte(*buffer);
313  buffer++;
314  };
315 }
316 
317 void ssd1306_platform_spiInit(int8_t busId, int8_t ces, int8_t dcPin)
318 {
319  sdl_core_init();
320  if (ces >= 0)
321  {
322  s_ssd1306_cs = ces;
323  }
324  if (dcPin >= 0)
325  {
326  s_ssd1306_dc = dcPin;
327  }
328  sdl_set_dc_pin(dcPin);
329  ssd1306_intf.spi = 1;
330  ssd1306_intf.start = sdl_send_init;
331  ssd1306_intf.stop = sdl_send_stop;
332  ssd1306_intf.send = sdl_send_byte;
333  ssd1306_intf.send_buffer = sdl_send_bytes;
334  ssd1306_intf.close = sdl_core_close;
335 }
336 
337 #endif /* SDL_EMULATION */
338 
339 #endif // CONFIG_PLATFORM_SPI_AVAILABLE
340 
341 #endif // __MINGW32__
342 
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 ssd1306_platform_i2cInit(int8_t busId, uint8_t addr, ssd1306_platform_i2cConfig_t *cfg)
Initializes i2c interface for platform being used.
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