Firmware SDK
 All Data Structures Functions Variables Typedefs Enumerations Enumerator Groups Pages
bc_ssd1306.c
1 #include <bc_ssd1306.h>
2 #include <math.h>
3 
4 #define _BC_SSD1306_SETCONTRAST 0x81
5 #define _BC_SSD1306_DISPLAYALLON_RESUME 0xA4
6 #define _BC_SSD1306_DISPLAYALLON 0xA5
7 #define _BC_SSD1306_NORMALDISPLAY 0xA6
8 #define _BC_SSD1306_INVERTDISPLAY 0xA7
9 #define _BC_SSD1306_DISPLAYOFF 0xAE
10 #define _BC_SSD1306_DISPLAYON 0xAF
11 #define _BC_SSD1306_SETDISPLAYOFFSET 0xD3
12 #define _BC_SSD1306_SETCOMPINS 0xDA
13 #define _BC_SSD1306_SETVCOMDETECT 0xDB
14 #define _BC_SSD1306_SETDISPLAYCLOCKDIV 0xD5
15 #define _BC_SSD1306_SETPRECHARGE 0xD9
16 #define _BC_SSD1306_SETMULTIPLEX 0xA8
17 #define _BC_SSD1306_SETLOWCOLUMN 0x00
18 #define _BC_SSD1306_SETHIGHCOLUMN 0x10
19 #define _BC_SSD1306_SETSTARTLINE 0x40
20 #define _BC_SSD1306_MEMORYMODE 0x20
21 #define _BC_SSD1306_COLUMNADDR 0x21
22 #define _BC_SSD1306_PAGEADDR 0x22
23 #define _BC_SSD1306_COMSCANINC 0xC0
24 #define _BC_SSD1306_COMSCANDEC 0xC8
25 #define _BC_SSD1306_SEGREMAP 0xA0
26 #define _BC_SSD1306_CHARGEPUMP 0x8D
27 #define _BC_SSD1306_EXTERNALVCC 0x1
28 #define _BC_SSD1306_SWITCHCAPVCC 0x2
29 
30 static bool _bc_ssd1306_command(bc_ssd1306_t *self, uint8_t command);
31 static bool _bc_ssd1306_send_data(bc_ssd1306_t *self, uint8_t *buffer, size_t length);
32 static bool _bc_ssd1306_init(bc_ssd1306_t *self);
33 
34 bool bc_ssd1306_init(bc_ssd1306_t *self, bc_i2c_channel_t i2c_channel, uint8_t i2c_address, const bc_ssd1306_framebuffer_t *framebuffer)
35 {
36  memset(self, 0xff, sizeof(*self));
37 
38  self->_i2c_channel = i2c_channel;
39 
40  self->_i2c_address = i2c_address;
41 
42  self->_framebuffer = framebuffer;
43 
44  bc_i2c_init(self->_i2c_channel, BC_I2C_SPEED_400_KHZ);
45 
46  self->_initialized = _bc_ssd1306_init(self);
47 
48  return self->_initialized;
49 }
50 
52 {
53  bc_gfx_caps_t caps = { .width = self->_framebuffer->width, .height = self->_framebuffer->height };
54 
55  return caps;
56 }
57 
59 {
60  if (!self->_initialized)
61  {
62  self->_initialized = _bc_ssd1306_init(self);
63  }
64 
65  return self->_initialized;
66 }
67 
69 {
70  memset(self->_framebuffer->buffer, 0x00, self->_framebuffer->length);
71 }
72 
73 void bc_ssd1306_draw_pixel(bc_ssd1306_t *self, int x, int y, uint32_t color)
74 {
75  // Skip mode byte + addr byte
76  uint32_t byteIndex = 0;
77  // Skip lines
78  byteIndex += x;
79  // Select column byte
80  byteIndex += (y / 8) * self->_framebuffer->width;
81 
82  uint8_t bitMask = 1 << (y % 8);
83 
84  if (color == 0)
85  {
86  self->_framebuffer->buffer[byteIndex] &= ~bitMask;
87  }
88  else
89  {
90  self->_framebuffer->buffer[byteIndex] |= bitMask;
91  }
92 }
93 
94 uint32_t bc_ssd1306_get_pixel(bc_ssd1306_t *self, int x, int y)
95 {
96  (void) self;
97  (void) x;
98  (void) y;
99 
100  return 0;
101 }
102 
104 {
105  if (!self->_initialized)
106  {
107  self->_initialized = _bc_ssd1306_init(self);
108  }
109 
110  if (!self->_initialized)
111  {
112  return false;
113  }
114 
115  if (_bc_ssd1306_command(self, _BC_SSD1306_COLUMNADDR) &&
116  _bc_ssd1306_command(self, 0) && // Column start address. (0 = reset)
117  _bc_ssd1306_command(self, self->_framebuffer->width - 1) && // Column end address.
118  _bc_ssd1306_command(self, _BC_SSD1306_PAGEADDR) &&
119  _bc_ssd1306_command(self, 0) && // Page start address. (0 = reset)
120  _bc_ssd1306_command(self, self->_framebuffer->pages - 1)) // Page end address.
121  {
122  for (size_t i = 0; i < self->_framebuffer->length; i += 8)
123  {
124  if (!_bc_ssd1306_send_data(self, self->_framebuffer->buffer + i, 8))
125  {
126  return false;
127  }
128  }
129 
130  return true;
131  }
132 
133  return false;
134 }
135 
137 {
138  static const bc_gfx_driver_t driver =
139  {
140  .is_ready = (bool (*)(void *)) bc_ssd1306_is_ready,
141  .clear = (void (*)(void *)) bc_ssd1306_clear,
142  .draw_pixel = (void (*)(void *, int, int, uint32_t)) bc_ssd1306_draw_pixel,
143  .get_pixel = (uint32_t (*)(void *, int, int)) bc_ssd1306_get_pixel,
144  .update = (bool (*)(void *)) bc_ssd1306_update,
145  .get_caps = (bc_gfx_caps_t (*)(void *)) bc_ssd1306_get_caps
146  };
147 
148  return &driver;
149 }
150 
151 static bool _bc_ssd1306_command(bc_ssd1306_t *self, uint8_t command)
152 {
153  return bc_i2c_memory_write_8b(self->_i2c_channel, self->_i2c_address, 0x00, command);
154 }
155 
156 static bool _bc_ssd1306_send_data(bc_ssd1306_t *self, uint8_t *buffer, size_t length)
157 {
158  bc_i2c_memory_transfer_t transfer;
159 
160  transfer.device_address = self->_i2c_address;
161  transfer.memory_address = 0x40;
162  transfer.buffer = buffer;
163  transfer.length = length;
164 
165  return bc_i2c_memory_write(self->_i2c_channel, &transfer);
166 }
167 
168 static bool _bc_ssd1306_init(bc_ssd1306_t *self)
169 {
170  return _bc_ssd1306_command(self, _BC_SSD1306_DISPLAYOFF) &&
171  _bc_ssd1306_command(self, _BC_SSD1306_SETDISPLAYCLOCKDIV) &&
172  _bc_ssd1306_command(self, 0x80) && // the suggested ratio
173  _bc_ssd1306_command(self, _BC_SSD1306_SETMULTIPLEX) &&
174  _bc_ssd1306_command(self, self->_framebuffer->height - 1) &&
175  _bc_ssd1306_command(self, _BC_SSD1306_SETDISPLAYOFFSET) &&
176  _bc_ssd1306_command(self, 0x0) && // no offset
177  _bc_ssd1306_command(self, _BC_SSD1306_SETSTARTLINE | 0x0) && // line #0
178  _bc_ssd1306_command(self, _BC_SSD1306_CHARGEPUMP) &&
179  _bc_ssd1306_command(self, 0x14) &&
180  _bc_ssd1306_command(self, _BC_SSD1306_MEMORYMODE) &&
181  _bc_ssd1306_command(self, 0x00) && // Horizontal addressing mode
182  _bc_ssd1306_command(self, _BC_SSD1306_SEGREMAP | 0x1) &&
183  _bc_ssd1306_command(self, _BC_SSD1306_COMSCANDEC) &&
184  _bc_ssd1306_command(self, _BC_SSD1306_SETCOMPINS) &&
185  _bc_ssd1306_command(self, self->_framebuffer->height == 64 ? 0x12 : 0x02) &&
186  _bc_ssd1306_command(self, _BC_SSD1306_SETCONTRAST) &&
187  _bc_ssd1306_command(self, 0x8f) &&
188  _bc_ssd1306_command(self, _BC_SSD1306_SETPRECHARGE) &&
189  _bc_ssd1306_command(self, 0xF1) &&
190  _bc_ssd1306_command(self, _BC_SSD1306_SETVCOMDETECT) &&
191  _bc_ssd1306_command(self, 0x40) &&
192  _bc_ssd1306_command(self, _BC_SSD1306_DISPLAYALLON_RESUME) &&
193  _bc_ssd1306_command(self, _BC_SSD1306_NORMALDISPLAY) &&
194  _bc_ssd1306_command(self, _BC_SSD1306_DISPLAYON); // Turn on the display.
195 }
void * buffer
Pointer to buffer which is being written or read.
Definition: bc_i2c.h:66
I2C communication speed is 400 kHz.
Definition: bc_i2c.h:36
bool bc_ssd1306_update(bc_ssd1306_t *self)
Lcd update, send data.
Definition: bc_ssd1306.c:103
uint32_t bc_ssd1306_get_pixel(bc_ssd1306_t *self, int x, int y)
Lcd get pixel.
Definition: bc_ssd1306.c:94
void bc_ssd1306_clear(bc_ssd1306_t *self)
Clear.
Definition: bc_ssd1306.c:68
Display size.
Definition: bc_gfx.h:13
Instance.
Definition: bc_ssd1306.h:37
Display driver interface.
Definition: bc_gfx.h:22
void bc_i2c_init(bc_i2c_channel_t channel, bc_i2c_speed_t speed)
Initialize I2C channel.
Definition: bc_i2c.c:54
const bc_gfx_driver_t * bc_ssd1306_get_driver(void)
Get Lcd driver.
Definition: bc_ssd1306.c:136
bool bc_ssd1306_init(bc_ssd1306_t *self, bc_i2c_channel_t i2c_channel, uint8_t i2c_address, const bc_ssd1306_framebuffer_t *framebuffer)
Initialize lcd driver.
Definition: bc_ssd1306.c:34
uint32_t memory_address
8-bit I2C memory address (it can be extended to 16-bit format if OR-ed with BC_I2C_MEMORY_ADDRESS_16_...
Definition: bc_i2c.h:63
uint8_t device_address
7-bit I2C device address
Definition: bc_i2c.h:60
I2C memory transfer parameters.
Definition: bc_i2c.h:57
bc_i2c_channel_t
I2C channels.
Definition: bc_i2c.h:15
bc_gfx_caps_t bc_ssd1306_get_caps(bc_ssd1306_t *self)
Get capabilities.
Definition: bc_ssd1306.c:51
size_t length
Length of buffer which is being written or read.
Definition: bc_i2c.h:69
bool bc_i2c_memory_write(bc_i2c_channel_t channel, const bc_i2c_memory_transfer_t *transfer)
Memory write to I2C channel.
Definition: bc_i2c.c:327
void bc_ssd1306_draw_pixel(bc_ssd1306_t *self, int x, int y, uint32_t color)
Lcd draw pixel.
Definition: bc_ssd1306.c:73
bool bc_ssd1306_is_ready(bc_ssd1306_t *self)
Check if lcd is ready for commands.
Definition: bc_ssd1306.c:58
bool bc_i2c_memory_write_8b(bc_i2c_channel_t channel, uint8_t device_address, uint32_t memory_address, uint8_t data)
Memory write 1 byte to I2C channel.
Definition: bc_i2c.c:402