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
int8_t scl
clock pin number
Definition: io.h:82
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
int8_t sda
data pin number
Definition: io.h:81
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