GPS Device
Loading...
Searching...
No Matches
ssd1309.c
Go to the documentation of this file.
1
11
12#include <stdbool.h>
13
14#include "ssd1309.h"
15#include "common.h"
16#include "err.h"
17#include "modules.h"
18#include "stm32f401re.h"
19#include "stm32f401re_gpio.h"
20#include "stm32f401re_i2c.h"
21#include "log.h"
22#include "cmd.h"
23#include "init.h"
24
26#define SSD1309_ADDR_W 0x3C
28#define SSD1309_ADDR_R 0x3D
30#define SSD1309_PAGE_NUM 8
32#define SSD1309_BITS_IN_PAGE 8
34#define SSD1309_COL_NUM 128
36#define SSD1309_MAX_LINES 8
37
47
48const uint8_t fonts8x8[95][8] = {
49
50/* 0x20 ' ' */
51{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
52
53/* 0x21 '!' */
54{0x00,0x00,0x00,0x5F,0x00,0x00,0x00,0x00},
55
56/* 0x22 '"' */
57{0x00,0x07,0x00,0x07,0x00,0x00,0x00,0x00},
58
59/* 0x23 '#' */
60{0x14,0x7F,0x14,0x7F,0x14,0x00,0x00,0x00},
61
62/* 0x24 '$' */
63{0x24,0x2A,0x7F,0x2A,0x12,0x00,0x00,0x00},
64
65/* 0x25 '%' */
66{0x23,0x13,0x08,0x64,0x62,0x00,0x00,0x00},
67
68/* 0x26 '&' */
69{0x36,0x49,0x55,0x22,0x50,0x00,0x00,0x00},
70
71/* 0x27 ''' */
72{0x00,0x05,0x03,0x00,0x00,0x00,0x00,0x00},
73
74/* 0x28 '(' */
75{0x00,0x1C,0x22,0x41,0x00,0x00,0x00,0x00},
76
77/* 0x29 ')' */
78{0x00,0x41,0x22,0x1C,0x00,0x00,0x00,0x00},
79
80/* 0x2A '*' */
81{0x14,0x08,0x3E,0x08,0x14,0x00,0x00,0x00},
82
83/* 0x2B '+' */
84{0x08,0x08,0x3E,0x08,0x08,0x00,0x00,0x00},
85
86/* 0x2C ',' */
87{0x00,0x50,0x30,0x00,0x00,0x00,0x00,0x00},
88
89/* 0x2D '-' */
90{0x08,0x08,0x08,0x08,0x08,0x00,0x00,0x00},
91
92/* 0x2E '.' */
93{0x00,0x60,0x60,0x00,0x00,0x00,0x00,0x00},
94
95/* 0x2F '/' */
96{0x20,0x10,0x08,0x04,0x02,0x00,0x00,0x00},
97
98/* 0x30 '0' */
99{0x3E,0x51,0x49,0x45,0x3E,0x00,0x00,0x00},
100
101/* 0x31 '1' */
102{0x00,0x42,0x7F,0x40,0x00,0x00,0x00,0x00},
103
104/* 0x32 '2' */
105{0x62,0x51,0x49,0x49,0x46,0x00,0x00,0x00},
106
107/* 0x33 '3' */
108{0x22,0x41,0x49,0x49,0x36,0x00,0x00,0x00},
109
110/* 0x34 '4' */
111{0x18,0x14,0x12,0x7F,0x10,0x00,0x00,0x00},
112
113/* 0x35 '5' */
114{0x2F,0x49,0x49,0x49,0x31,0x00,0x00,0x00},
115
116/* 0x36 '6' */
117{0x3E,0x49,0x49,0x49,0x32,0x00,0x00,0x00},
118
119/* 0x37 '7' */
120{0x01,0x71,0x09,0x05,0x03,0x00,0x00,0x00},
121
122/* 0x38 '8' */
123{0x36,0x49,0x49,0x49,0x36,0x00,0x00,0x00},
124
125/* 0x39 '9' */
126{0x26,0x49,0x49,0x49,0x3E,0x00,0x00,0x00},
127
128/* 0x3A ':' */
129{0x00,0x36,0x36,0x00,0x00,0x00,0x00,0x00},
130
131/* 0x3B ';' */
132{0x00,0x56,0x36,0x00,0x00,0x00,0x00,0x00},
133
134/* 0x3C '<' */
135{0x08,0x14,0x22,0x41,0x00,0x00,0x00,0x00},
136
137/* 0x3D '=' */
138{0x14,0x14,0x14,0x14,0x14,0x00,0x00,0x00},
139
140/* 0x3E '>' */
141{0x41,0x22,0x14,0x08,0x00,0x00,0x00,0x00},
142
143/* 0x3F '?' */
144{0x02,0x01,0x51,0x09,0x06,0x00,0x00,0x00},
145
146/* 0x40 '@' */
147{0x32,0x49,0x79,0x41,0x3E,0x00,0x00,0x00},
148
149/* 0x41 'A' */
150{0x00,0x7E,0x09,0x09,0x09,0x09,0x7E,0x00},
151
152/* 0x42 'B' */
153{0x00,0x7F,0x49,0x49,0x49,0x49,0x36,0x00},
154
155/* 0x43 'C' */
156{0x00,0x3E,0x41,0x41,0x41,0x41,0x22,0x00},
157
158/* 0x44 'D' */
159{0x00,0x7F,0x41,0x41,0x41,0x22,0x1C,0x00},
160
161/* 0x45 'E' */
162{0x00,0x7F,0x49,0x49,0x49,0x49,0x41,0x00},
163
164/* 0x46 'F' */
165{0x00,0x7F,0x09,0x09,0x09,0x09,0x01,0x00},
166
167/* 0x47 'G' */
168{0x00,0x3E,0x41,0x41,0x49,0x49,0x7A,0x00},
169
170/* 0x48 'H' */
171{0x00,0x7F,0x08,0x08,0x08,0x08,0x7F,0x00},
172
173/* 0x49 'I' */
174{0x00,0x41,0x41,0x7F,0x41,0x41,0x00,0x00},
175
176/* 0x4A 'J' */
177{0x00,0x20,0x40,0x41,0x3F,0x01,0x00,0x00},
178
179/* 0x4B 'K' */
180{0x00,0x7F,0x08,0x14,0x22,0x41,0x00,0x00},
181
182/* 0x4C 'L' */
183{0x00,0x7F,0x40,0x40,0x40,0x40,0x40,0x00},
184
185/* 0x4D 'M' */
186{0x00,0x7F,0x02,0x0C,0x02,0x7F,0x00,0x00},
187
188/* 0x4E 'N' */
189{0x00,0x7F,0x04,0x08,0x10,0x7F,0x00,0x00},
190
191/* 0x4F 'O' */
192{0x00,0x3E,0x41,0x41,0x41,0x41,0x3E,0x00},
193
194/* 0x50 'P' */
195{0x00,0x7F,0x09,0x09,0x09,0x09,0x06,0x00},
196
197/* 0x51 'Q' */
198{0x00,0x3E,0x41,0x51,0x21,0x5E,0x00,0x00},
199
200/* 0x52 'R' */
201{0x00,0x7F,0x09,0x19,0x29,0x46,0x00,0x00},
202
203/* 0x53 'S' */
204{0x00,0x26,0x49,0x49,0x49,0x49,0x32,0x00},
205
206/* 0x54 'T' */
207{0x00,0x01,0x01,0x7F,0x01,0x01,0x00,0x00},
208
209/* 0x55 'U' */
210{0x00,0x3F,0x40,0x40,0x40,0x40,0x3F,0x00},
211
212/* 0x56 'V' */
213{0x00,0x1F,0x20,0x40,0x20,0x1F,0x00,0x00},
214
215/* 0x57 'W' */
216{0x00,0x7F,0x20,0x18,0x20,0x7F,0x00,0x00},
217
218/* 0x58 'X' */
219{0x00,0x63,0x14,0x08,0x14,0x63,0x00,0x00},
220
221/* 0x59 'Y' */
222{0x00,0x03,0x04,0x78,0x04,0x03,0x00,0x00},
223
224/* 0x5A 'Z' */
225{0x00,0x61,0x51,0x49,0x45,0x43,0x00,0x00},
226
227/* 0x5B '[' */
228{0x00,0x7F,0x41,0x41,0x00,0x00,0x00,0x00},
229
230/* 0x5C '\' */
231{0x02,0x04,0x08,0x10,0x20,0x00,0x00,0x00},
232
233/* 0x5D ']' */
234{0x00,0x41,0x41,0x7F,0x00,0x00,0x00,0x00},
235
236/* 0x5E '^' */
237{0x04,0x02,0x01,0x02,0x04,0x00,0x00,0x00},
238
239/* 0x5F '_' */
240{0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00},
241
242/* 0x60 '`' */
243{0x00,0x01,0x02,0x04,0x00,0x00,0x00,0x00},
244
245/* 0x61 'a' */
246{0x00,0x20,0x54,0x54,0x54,0x54,0x78,0x00},
247
248/* 0x62 'b' */
249{0x00,0x7F,0x48,0x48,0x48,0x48,0x30,0x00},
250
251/* 0x63 'c' */
252{0x00,0x38,0x44,0x44,0x44,0x44,0x28,0x00},
253
254/* 0x64 'd' */
255{0x00,0x30,0x48,0x48,0x48,0x48,0x7F,0x00},
256
257/* 0x65 'e' */
258{0x00,0x38,0x54,0x54,0x54,0x54,0x18,0x00},
259
260/* 0x66 'f' */
261{0x00,0x08,0x7E,0x09,0x01,0x02,0x00,0x00},
262
263/* 0x67 'g' */
264{0x00,0x0C,0x52,0x52,0x52,0x52,0x3E,0x00},
265
266/* 0x68 'h' */
267{0x00,0x7F,0x08,0x08,0x08,0x08,0x70,0x00},
268
269/* 0x69 'i' */
270{0x00,0x00,0x48,0x7A,0x40,0x00,0x00,0x00},
271
272/* 0x6A 'j' */
273{0x00,0x20,0x40,0x48,0x3A,0x00,0x00,0x00},
274
275/* 0x6B 'k' */
276{0x00,0x7F,0x10,0x28,0x44,0x00,0x00,0x00},
277
278/* 0x6C 'l' */
279{0x00,0x41,0x7F,0x40,0x00,0x00,0x00,0x00},
280
281/* 0x6D 'm' */
282{0x00,0x7C,0x04,0x18,0x04,0x78,0x00,0x00},
283
284/* 0x6E 'n' */
285{0x00,0x7C,0x08,0x04,0x04,0x78,0x00,0x00},
286
287/* 0x6F 'o' */
288{0x00,0x38,0x44,0x44,0x44,0x44,0x38,0x00},
289
290/* 0x70 'p' */
291{0x00,0x7E,0x12,0x12,0x12,0x12,0x0C,0x00},
292
293/* 0x71 'q' */
294{0x00,0x0C,0x12,0x12,0x12,0x12,0x7E,0x00},
295
296/* 0x72 'r' */
297{0x00,0x7C,0x08,0x04,0x04,0x08,0x00,0x00},
298
299/* 0x73 's' */
300{0x00,0x48,0x54,0x54,0x54,0x54,0x20,0x00},
301
302/* 0x74 't' */
303{0x00,0x04,0x3F,0x44,0x40,0x20,0x00,0x00},
304
305/* 0x75 'u' */
306{0x00,0x3C,0x40,0x40,0x40,0x20,0x7C,0x00},
307
308/* 0x76 'v' */
309{0x00,0x1C,0x20,0x40,0x20,0x1C,0x00,0x00},
310
311/* 0x77 'w' */
312{0x00,0x3C,0x40,0x30,0x40,0x3C,0x00,0x00},
313
314/* 0x78 'x' */
315{0x00,0x44,0x28,0x10,0x28,0x44,0x00,0x00},
316
317/* 0x79 'y' */
318{0x00,0x0C,0x50,0x50,0x50,0x50,0x3C,0x00},
319
320/* 0x7A 'z' */
321{0x00,0x44,0x64,0x54,0x4C,0x44,0x00,0x00},
322
323/* 0x7B '{' */
324{0x00,0x08,0x36,0x41,0x00,0x00,0x00,0x00},
325
326/* 0x7C '|' */
327{0x00,0x00,0x7F,0x00,0x00,0x00,0x00,0x00},
328
329/* 0x7D '}' */
330{0x00,0x41,0x36,0x08,0x00,0x00,0x00,0x00},
331
332/* 0x7E '~' */
333{0x10,0x08,0x08,0x10,0x08,0x08,0x00,0x00}
334
335};
336
374
382struct internal_state_s {
385
392
395
398
400 bool initialized;
401
403 bool started;
404};
407
408/* ---- Forward declarations for command handlers ---- */
409static ERR_te ssd1309_cmd_start_handler(uint32_t argc, char **argv);
410static ERR_te ssd1309_cmd_stop_handler(uint32_t argc, char **argv);
411static ERR_te ssd1309_cmd_fillrect_handler(uint32_t argc, char **argv);
412static ERR_te ssd1309_cmd_clearrect_handler(uint32_t argc, char **argv);
413static ERR_te ssd1309_cmd_invertrect_handler(uint32_t argc, char **argv);
414static ERR_te ssd1309_cmd_drawtext_handler(uint32_t argc, char **argv);
415static ERR_te ssd1309_cmd_clearline_handler(uint32_t argc, char **argv);
416static ERR_te ssd1309_cmd_invertline_handler(uint32_t argc, char **argv);
417
426 {
427 .name = "start",
428 .help = "Starts the module, usage: ssd1309 start",
430 },
431 {
432 .name = "stop",
433 .help = "Stops the module, usage: ssd1309 stop",
434 .handler = ssd1309_cmd_stop_handler
435 },
436 {
437 .name = "fillrect",
438 .help = "Fills a rectangle, usage: ssd1309 fillrect <x1,y1,x2,y2>",
440 },
441 {
442 .name = "clearrect",
443 .help = "Clears a rectangle, usage: ssd1309 clearrect <x1,y1,x2,y2>",
445 },
446 {
447 .name = "invertrect",
448 .help = "Inverts the pixels of a rectangle, usage: ssd1309 invertrect <x1,y1,x2,y2>",
450 },
451 {
452 .name = "drawtext",
453 .help = "Draws text in a line, usage: ssd1309 drawtext <text> <line>",
455 },
456 {
457 .name = "clearline",
458 .help = "Clears a line, usage: ssd1309 clearline <line>",
460 },
461 {
462 .name = "invertline",
463 .help = "Inverts a line, usage: ssd1309 invertline <line>",
465 }
466};
467
476 .cmds_ptr = ssd1309_cmds,
477 .num_cmds = sizeof(ssd1309_cmds) / sizeof(ssd1309_cmds[0]),
478 .name = "ssd1309",
479 .log_level_ptr = &internal_state.log_level
480};
481
486
489 ERR_te err;
490
491 if(internal_state.initialized) {
493 }
494
495 internal_state = (struct internal_state_s){ 0 };
496 internal_state.log_level = LOG_LEVEL_INFO;
498 internal_state.initialized = true;
499 internal_state.started = false;
500
501 init_log();
502
504 if(err != ERR_OK) {
505 LOG_ERROR(
506 internal_state.subsys,
507 internal_state.log_level,
508 "ssd1309_init_subsys: cmd_register error"
509 );
510
511 return err;
512 }
513 LOG_INFO(
514 internal_state.subsys,
515 internal_state.log_level,
516 "ssd1309_init_subsys: subsys initialized"
517 );
518
519 return ERR_OK;
520}
521
524 if(internal_state.initialized && !internal_state.started) {
525 internal_state = (struct internal_state_s){ 0 };
526
528 if(err != ERR_OK) {
529 return err;
530 }
531 }
532 else {
533 LOG_ERROR(
534 internal_state.subsys,
535 internal_state.log_level,
536 "ssd1309_deinit_subsys: subsys is not initialized or stopped"
537 );
538
540 }
541
542 LOG_INFO(
543 internal_state.subsys,
544 internal_state.log_level,
545 "ssd1309_deinit_subsys: subsystem deinitialized"
546 );
547 return ERR_OK;
548}
549
552 if(internal_state.initialized && !internal_state.started) {
553 internal_state.started = true;
554
555 LOG_INFO(
556 internal_state.subsys,
557 internal_state.log_level,
558 "ssd1309_start_subsys: subsys started"
559 );
560 }
561 else {
562 LOG_ERROR(
563 internal_state.subsys,
564 internal_state.log_level,
565 "ssd1309_start_subsys: subsys not initialized or already started"
566 );
567
568 return ERR_UNKNOWN;
569 }
570
571 return ERR_OK;
572}
573
576 if(internal_state.initialized && internal_state.started) {
577 internal_state.started = false;
578
579 LOG_INFO(
580 internal_state.subsys,
581 internal_state.log_level,
582 "ssd1309_stop_subsys: subsys stopped"
583 );
584 }
585 else {
586 LOG_ERROR(
587 internal_state.subsys,
588 internal_state.log_level,
589 "ssd1309_stop_subsys: subsys not initialized or already already stopped"
590 );
591
592 return ERR_UNKNOWN;
593 }
594
595 return ERR_OK;
596}
597
600 ssd1309_cfg_o->mem_addr_mode = SSD1309_MEM_ADDR_MODE_HAM;
601 ssd1309_cfg_o->col_addr_start_ham_vam = SSD1309_COL_ADDR_START_HAM_VAM_0;
602 ssd1309_cfg_o->col_addr_end_ham_vam = SSD1309_COL_ADDR_END_HAM_VAM_127;
603 ssd1309_cfg_o->page_addr_start_ham_vam = SSD1309_PAGE_ADDR_START_HAM_VAM_0;
604 ssd1309_cfg_o->page_addr_end_ham_vam = SSD1309_PAGE_ADDR_END_HAM_VAM_7;
605 ssd1309_cfg_o->start_line = SSD1309_START_LINE_0;
606 ssd1309_cfg_o->contrast = SSD1309_CONTRAST_10;
607 ssd1309_cfg_o->horizontal_flip = SSD1309_HORIZONTAL_FLIP_TRUE;
608 ssd1309_cfg_o->inverse_mode = SSD1309_INVERSE_MODE_FALSE;
609 ssd1309_cfg_o->multiplex_ratio = SSD1309_MULTIPLEX_RATIO_64;
610 ssd1309_cfg_o->vertical_flip = SSD1309_VERTICAL_FLIP_TRUE;
611 ssd1309_cfg_o->offset = SSD1309_OFFSET_0;
612 ssd1309_cfg_o->clk_div_ratio = SSD1309_CLK_DIV_RATIO_1;
613 ssd1309_cfg_o->clk_speed_lvl = SSD1309_CLK_SPEED_LVL_LVL_15;
614 ssd1309_cfg_o->phase1_precharge_dclk = SSD1309_PHASE1_PRECHARGE_DCLK_2;
615 ssd1309_cfg_o->phase2_precharge_dclk = SSD1309_PHASE2_PRECHARGE_DCLK_2;
616 ssd1309_cfg_o->vcomh_deselect_lvl = SSD1309_VCOMH_DESELECT_LVL_MED;
617
618 return ERR_OK;
619}
620
623 if(internal_state.ssd1309_handle.initialized == true) {
624 LOG_ERROR(
625 internal_state.subsys,
626 internal_state.log_level,
627 "ssd1309_init_handle: handle already initialized"
628 );
629
631 }
632
633 if(ssd1309_cfg->i2c_instance == (void*)0) {
634 LOG_ERROR(
635 internal_state.subsys,
636 internal_state.log_level,
637 "ssd1309_init_handle: No I2C peripheral given"
638 );
639
641 }
642 else if(ssd1309_cfg->scl_gpio_port == (void*)0 || ssd1309_cfg->sda_gpio_port == (void*)0) {
643 LOG_ERROR(
644 internal_state.subsys,
645 internal_state.log_level,
646 "ssd1309_init_handle: No GPIO peripheral given"
647 );
648
650 }
651
652 internal_state.ssd1309_handle.i2c_instance = ssd1309_cfg->i2c_instance;
653 internal_state.ssd1309_handle.scl_gpio_port = ssd1309_cfg->scl_gpio_port;
654 internal_state.ssd1309_handle.scl_gpio_pin = ssd1309_cfg->scl_gpio_pin;
655 internal_state.ssd1309_handle.sda_gpio_port = ssd1309_cfg->sda_gpio_port;
656 internal_state.ssd1309_handle.sda_gpio_pin = ssd1309_cfg->sda_gpio_pin;
657 internal_state.ssd1309_handle.gpio_alternate_function = ssd1309_cfg->gpio_alternate_function;
658 internal_state.ssd1309_handle.low_col_start_addr_pam = ssd1309_cfg->low_col_start_addr_pam;
659 internal_state.ssd1309_handle.high_col_start_addr_pam = ssd1309_cfg->high_col_start_addr_pam;
660 internal_state.ssd1309_handle.mem_addr_mode = ssd1309_cfg->mem_addr_mode;
661 internal_state.ssd1309_handle.col_addr_start_ham_vam = ssd1309_cfg->col_addr_start_ham_vam;
662 internal_state.ssd1309_handle.col_addr_end_ham_vam = ssd1309_cfg->col_addr_end_ham_vam;
663 internal_state.ssd1309_handle.page_addr_start_ham_vam = ssd1309_cfg->page_addr_start_ham_vam;
664 internal_state.ssd1309_handle.page_addr_end_ham_vam = ssd1309_cfg->page_addr_end_ham_vam;
665 internal_state.ssd1309_handle.start_line = ssd1309_cfg->start_line;
666 internal_state.ssd1309_handle.contrast = ssd1309_cfg->contrast;
667 internal_state.ssd1309_handle.horizontal_flip = ssd1309_cfg->horizontal_flip;
668 internal_state.ssd1309_handle.inverse_mode = ssd1309_cfg->inverse_mode;
669 internal_state.ssd1309_handle.multiplex_ratio = ssd1309_cfg->multiplex_ratio;
670 internal_state.ssd1309_handle.page_start_addr_pam = ssd1309_cfg->page_start_addr_pam;
671 internal_state.ssd1309_handle.vertical_flip = ssd1309_cfg->vertical_flip;
672 internal_state.ssd1309_handle.offset = ssd1309_cfg->offset;
673 internal_state.ssd1309_handle.clk_div_ratio = ssd1309_cfg->clk_div_ratio;
674 internal_state.ssd1309_handle.clk_speed_lvl =ssd1309_cfg->clk_speed_lvl;
675 internal_state.ssd1309_handle.phase1_precharge_dclk = ssd1309_cfg->phase1_precharge_dclk;
676 internal_state.ssd1309_handle.phase2_precharge_dclk = ssd1309_cfg->phase2_precharge_dclk;
677 internal_state.ssd1309_handle.vcomh_deselect_lvl = ssd1309_cfg->vcomh_deselect_lvl;
678
679 GPIO_CFG_ts ssd1309_scl = { 0 };
680 GPIO_CFG_ts ssd1309_sda = { 0 };
681
682 ssd1309_scl.port = ssd1309_cfg->scl_gpio_port;
683 ssd1309_scl.pin = ssd1309_cfg->scl_gpio_pin;
685 ssd1309_scl.alternate_function = ssd1309_cfg->gpio_alternate_function;
687
688 ssd1309_sda.port = ssd1309_cfg->sda_gpio_port;
689 ssd1309_sda.pin = ssd1309_cfg->sda_gpio_pin;
691 ssd1309_sda.alternate_function = ssd1309_cfg->gpio_alternate_function;
693
694 gpio_init(&ssd1309_scl);
695 gpio_init(&ssd1309_sda);
696
697 I2C_CFG_ts ssd1309_i2c = { 0 };
699 ssd1309_i2c.instance = internal_state.ssd1309_handle.i2c_instance;
700 ssd1309_i2c.speed = I2C_SPEED_400kHz;
701
702 i2c_init(&ssd1309_i2c);
703
704 i2c_master_set_comm(internal_state.ssd1309_handle.i2c_instance, ENABLE);
705
706 uint8_t cmd_buf[64];
707 uint8_t idx = 0;
708
709 // Control byte: commands
710 cmd_buf[idx++] = 0x00;
711
712 // SSD1309 OFF
713 cmd_buf[idx++] = 0xAE;
714
715 // Memory addressing mode
716 cmd_buf[idx++] = 0x20;
717 cmd_buf[idx++] = ssd1309_cfg->mem_addr_mode;
718
719 // Addressing mode dependent setup
720 if (ssd1309_cfg->mem_addr_mode == SSD1309_MEM_ADDR_MODE_HAM ||
721 ssd1309_cfg->mem_addr_mode == SSD1309_MEM_ADDR_MODE_VAM) {
722
723 // Column start/end
724 cmd_buf[idx++] = 0x21;
725 cmd_buf[idx++] = ssd1309_cfg->col_addr_start_ham_vam;
726 cmd_buf[idx++] = ssd1309_cfg->col_addr_end_ham_vam;
727
728 // Page start/end
729 cmd_buf[idx++] = 0x22;
730 cmd_buf[idx++] = ssd1309_cfg->page_addr_start_ham_vam;
731 cmd_buf[idx++] = ssd1309_cfg->page_addr_end_ham_vam;
732 }
733 else {
734 // Page start (PAM)
735 cmd_buf[idx++] = 0xB0 | ssd1309_cfg->page_start_addr_pam;
736
737 // Column start (PAM)
738 cmd_buf[idx++] = ssd1309_cfg->low_col_start_addr_pam;
739 cmd_buf[idx++] = 0x10 | ssd1309_cfg->high_col_start_addr_pam;
740 }
741
742 // SSD1309 start line
743 cmd_buf[idx++] = 0x40 | ssd1309_cfg->start_line;
744
745 // Contrast
746 cmd_buf[idx++] = 0x81;
747 cmd_buf[idx++] = ssd1309_cfg->contrast;
748
749 // Horizontal flip
750 cmd_buf[idx++] = 0xA0 | ssd1309_cfg->horizontal_flip;
751
752 // Inverse mode
753 cmd_buf[idx++] = 0xA6 | ssd1309_cfg->inverse_mode;
754
755 // Multiplex ratio
756 cmd_buf[idx++] = 0xA8;
757 cmd_buf[idx++] = ssd1309_cfg->multiplex_ratio;
758
759 // Vertical flip
760 cmd_buf[idx++] = 0xC0 | ssd1309_cfg->vertical_flip;
761
762 // SSD1309 offset
763 cmd_buf[idx++] = 0xD3;
764 cmd_buf[idx++] = ssd1309_cfg->offset;
765
766 // Clock divide + oscillator frequency
767 cmd_buf[idx++] = 0xD5;
768 cmd_buf[idx++] =
769 (ssd1309_cfg->clk_div_ratio & 0x0F) |
770 (ssd1309_cfg->clk_speed_lvl << 4);
771
772 // Pre-charge period
773 cmd_buf[idx++] = 0xD9;
774 cmd_buf[idx++] =
775 (ssd1309_cfg->phase1_precharge_dclk & 0x0F) |
776 (ssd1309_cfg->phase2_precharge_dclk << 4);
777
778 // VCOMH deselect level
779 cmd_buf[idx++] = 0xDB;
780 cmd_buf[idx++] = ssd1309_cfg->vcomh_deselect_lvl;
781
782 // Turn on SSD1309
783 cmd_buf[idx++] = 0xAF;
784
785 // Output follows RAM content
786 cmd_buf[idx++] = 0xA4;
787
788 i2c_master_send(internal_state.ssd1309_handle.i2c_instance, SSD1309_ADDR_W, cmd_buf, idx);
789
790 i2c_master_set_comm(internal_state.ssd1309_handle.i2c_instance, DISABLE);
791
792 internal_state.ssd1309_handle.initialized = true;
793
794 *ssd1309_handle_o = &internal_state.ssd1309_handle;
795
796 LOG_INFO(
797 internal_state.subsys,
798 internal_state.log_level,
799 "ssd1309_init_handle: ssd1309 handle initialized"
800 );
801
802 return ERR_OK;
803}
804
806ERR_te ssd1309_draw_text(char const *text, uint8_t text_len, uint8_t line, bool force) {
807 if((!internal_state.ssd1309_handle.initialized || !internal_state.started) && !force) {
808 LOG_ERROR(
809 internal_state.subsys,
810 internal_state.log_level,
811 "ssd1309_draw_text: handle not initialized or subsystem not started"
812 );
813
815 }
816
817 if (line > SSD1309_PAGE_NUM || line == 0) {
818 return ERR_INVALID_ARGUMENT; // invalid line
819 }
820
821 line--;
822
823 uint8_t x = 0; // start at left-most column
824 for (uint8_t i = 0; i < text_len; i++) {
825 // check if character fits horizontally
826 if (x + 8 > SSD1309_WIDTH && line < SSD1309_PAGE_NUM) {
827 line++; // stop drawing if we run out of columns
828 x = 0;
829 }
830
831 // draw 8x8 character
832 for (uint8_t col = 0; col < 8; col++) {
833 internal_state.fb[line][x + col] = fonts8x8[text[i] - 32][col];
834 }
835
836 x += 8; // move to next character position
837 }
838
839 return ERR_OK;
840}
841
843ERR_te ssd1309_draw_rect(uint8_t x_src, uint8_t y_src, uint8_t x_dest, uint8_t y_dest, bool force) {
844 if((!internal_state.ssd1309_handle.initialized || !internal_state.started) && !force) {
845 LOG_ERROR(
846 internal_state.subsys,
847 internal_state.log_level,
848 "ssd1309_draw_rect: handle not initialized or subsystem not started"
849 );
850
852 }
853
854 if(x_src > x_dest || y_src > y_dest || x_src < 1 || x_dest > SSD1309_WIDTH ||
855 y_src < 1 || y_dest > SSD1309_HEIGHT) {
856 // Invalid arguments
858 }
859
860 // Convert to 0-based coordinates
861 uint8_t xs = x_src - 1;
862 uint8_t ys = y_src - 1;
863 uint8_t xd = x_dest - 1;
864 uint8_t yd = y_dest - 1;
865
866 uint8_t page_src = ys / SSD1309_BITS_IN_PAGE;
867 uint8_t bit_src = ys % SSD1309_BITS_IN_PAGE;
868
869 uint8_t page_dest = yd / SSD1309_BITS_IN_PAGE;
870 uint8_t bit_dest = yd % SSD1309_BITS_IN_PAGE;
871
872 for (uint8_t p = page_src; p <= page_dest; p++) {
873 for (uint8_t x = xs; x <= xd; x++) {
874
875 if (p == page_src && p == page_dest) {
876 /* Single page */
877 uint8_t mask = (uint8_t)((0xFFu << bit_src) & ((1u << (bit_dest + 1)) - 1));
878 internal_state.fb[p][x] |= mask;
879 }
880 else if (p == page_src) {
881 /* First page */
882 uint8_t mask = (uint8_t)(0xFFu << bit_src);
883 internal_state.fb[p][x] |= mask;
884 }
885 else if (p == page_dest) {
886 /* Last page */
887 uint8_t mask = (uint8_t)((1u << (bit_dest + 1)) - 1);
888 internal_state.fb[p][x] |= mask;
889 }
890 else {
891 /* Full pages in between */
892 internal_state.fb[p][x] = 0xFF;
893 }
894 }
895 }
896
897 return ERR_OK;
898}
899
901ERR_te ssd1309_clear_line(uint8_t line, bool force) {
902 if((!internal_state.ssd1309_handle.initialized || !internal_state.started) && !force) {
903 LOG_ERROR(
904 internal_state.subsys,
905 internal_state.log_level,
906 "ssd1309_clear_line: handle not initialized or subsystem not started"
907 );
908
910 }
911
912 if (line > SSD1309_PAGE_NUM || line == 0) {
913 return ERR_INVALID_ARGUMENT; // invalid line
914 }
915
916 line--;
917
918 ssd1309_clear_rect(1, line * SSD1309_BITS_IN_PAGE + 1, 128, line * SSD1309_BITS_IN_PAGE + 8, force);
919
920 return ERR_OK;
921}
922
924ERR_te ssd1309_invert_line(uint8_t line, bool force) {
925 if((!internal_state.ssd1309_handle.initialized || !internal_state.started) && !force) {
926 LOG_ERROR(
927 internal_state.subsys,
928 internal_state.log_level,
929 "ssd1309_invert_line: handle not initialized or subsystem not started"
930 );
931
933 }
934
935 if (line > SSD1309_PAGE_NUM || line == 0) {
936 return ERR_INVALID_ARGUMENT; // invalid line
937 }
938
939 line--;
940
941 ssd1309_invert_rect(1, line * SSD1309_BITS_IN_PAGE + 1, 128, line * SSD1309_BITS_IN_PAGE + 8, force);
942
943 return ERR_OK;
944}
945
947ERR_te ssd1309_clear_rect(uint8_t x_src, uint8_t y_src, uint8_t x_dest, uint8_t y_dest, bool force) {
948 if((!internal_state.ssd1309_handle.initialized || !internal_state.started) && !force) {
949 LOG_ERROR(
950 internal_state.subsys,
951 internal_state.log_level,
952 "ssd1309_clear_rect: handle not initialized or subsystem not started"
953 );
954
956 }
957
958 if(x_src > x_dest || y_src > y_dest || x_src < 1 || x_dest > SSD1309_WIDTH ||
959 y_src < 1 || y_dest > SSD1309_HEIGHT) {
960 // Invalid arguments
962 }
963
964 // Convert to 0-based coordinates
965 uint8_t xs = x_src - 1;
966 uint8_t ys = y_src - 1;
967 uint8_t xd = x_dest - 1;
968 uint8_t yd = y_dest - 1;
969
970 uint8_t page_src = ys / SSD1309_BITS_IN_PAGE;
971 uint8_t bit_src = ys % SSD1309_BITS_IN_PAGE;
972
973 uint8_t page_dest = yd / SSD1309_BITS_IN_PAGE;
974 uint8_t bit_dest = yd % SSD1309_BITS_IN_PAGE;
975
976 for (uint8_t p = page_src; p <= page_dest; p++) {
977 for (uint8_t x = xs; x <= xd; x++) {
978
979 if (p == page_src && p == page_dest) {
980 /* Single page */
981 uint8_t mask = (uint8_t)((0xFFu << bit_src) & ((1u << (bit_dest + 1)) - 1));
982 internal_state.fb[p][x] &= ~mask;
983 }
984 else if (p == page_src) {
985 /* First page */
986 uint8_t mask = (uint8_t)(0xFFu << bit_src);
987 internal_state.fb[p][x] &= ~mask;
988 }
989 else if (p == page_dest) {
990 /* Last page */
991 uint8_t mask = (uint8_t)((1u << (bit_dest + 1)) - 1);
992 internal_state.fb[p][x] &= ~mask;
993 }
994 else {
995 /* Full pages in between */
996 internal_state.fb[p][x] = 0x00;
997 }
998 }
999 }
1000
1001 return ERR_OK;
1002}
1003
1005ERR_te ssd1309_invert_rect(uint8_t x_src, uint8_t y_src, uint8_t x_dest, uint8_t y_dest, bool force) {
1006 if((!internal_state.ssd1309_handle.initialized || !internal_state.started) && !force) {
1007 LOG_ERROR(
1008 internal_state.subsys,
1009 internal_state.log_level,
1010 "ssd1309_invert_rect: handle not initialized or subsystem not started"
1011 );
1012
1014 }
1015
1016 if(x_src > x_dest || y_src > y_dest || x_src < 1 || x_dest > SSD1309_WIDTH ||
1017 y_src < 1 || y_dest > SSD1309_HEIGHT) {
1018 // Invalid arguments
1019 return ERR_INVALID_ARGUMENT;
1020 }
1021
1022// Convert to 0-based coordinates
1023 uint8_t xs = x_src - 1;
1024 uint8_t ys = y_src - 1;
1025 uint8_t xd = x_dest - 1;
1026 uint8_t yd = y_dest - 1;
1027
1028 uint8_t page_src = ys / SSD1309_BITS_IN_PAGE;
1029 uint8_t bit_src = ys % SSD1309_BITS_IN_PAGE;
1030
1031 uint8_t page_dest = yd / SSD1309_BITS_IN_PAGE;
1032 uint8_t bit_dest = yd % SSD1309_BITS_IN_PAGE;
1033
1034
1035 for (uint8_t p = page_src; p <= page_dest; p++) {
1036 for (uint8_t x = xs; x <= xd; x++) {
1037
1038 if (p == page_src && p == page_dest) {
1039 /* Single page */
1040 uint8_t mask = (uint8_t)((0xFFu << bit_src) & ((1u << (bit_dest + 1)) - 1));
1041 internal_state.fb[p][x] ^= mask;
1042 }
1043 else if (p == page_src) {
1044 /* First page */
1045 uint8_t mask = (uint8_t)(0xFFu << bit_src);
1046 internal_state.fb[p][x] ^= mask;
1047 }
1048 else if (p == page_dest) {
1049 /* Last page */
1050 uint8_t mask = (uint8_t)((1u << (bit_dest + 1)) - 1);
1051 internal_state.fb[p][x] ^= mask;
1052 }
1053 else {
1054 /* Full pages in between */
1055 internal_state.fb[p][x] ^= 0xFF;
1056 }
1057 }
1058 }
1059
1060 return ERR_OK;
1061}
1062
1065 if((!internal_state.ssd1309_handle.initialized || !internal_state.started) && !force) {
1066 LOG_ERROR(
1067 internal_state.subsys,
1068 internal_state.log_level,
1069 "ssd1309_update: handle not initialized or subsystem not started"
1070 );
1071
1073 }
1074
1075 i2c_master_set_comm(internal_state.ssd1309_handle.i2c_instance, ENABLE);
1076
1077 uint8_t cmd = 0x40 ;
1078 i2c_master_send(internal_state.ssd1309_handle.i2c_instance,
1079 SSD1309_ADDR_W, &cmd, 1);
1080
1081 /* Framebuffer */
1082 i2c_master_send_continue(internal_state.ssd1309_handle.i2c_instance,
1083 (uint8_t *)internal_state.fb,
1085
1086 i2c_master_set_comm(internal_state.ssd1309_handle.i2c_instance, DISABLE);
1087
1088 return ERR_OK;
1089}
1090
1092
1097
1111static ERR_te ssd1309_cmd_start_handler(uint32_t argc, char **argv) {
1112 if(argc != 2) {
1113 LOG_ERROR(
1114 internal_state.subsys,
1115 internal_state.log_level,
1116 "ssd1309_cmd_start_handler: invalid arguments"
1117 );
1118
1119 return ERR_INVALID_ARGUMENT;
1120 }
1121
1122 internal_state.started = true;
1123
1124 return ERR_OK;
1125}
1126
1140static ERR_te ssd1309_cmd_stop_handler(uint32_t argc, char **argv) {
1141 if(argc != 2) {
1142 LOG_ERROR(
1143 internal_state.subsys,
1144 internal_state.log_level,
1145 "ssd1309_cmd_stop_handler: invalid arguments"
1146 );
1147
1148 return ERR_INVALID_ARGUMENT;
1149 }
1150
1151 internal_state.started = false;
1152
1153 return ERR_OK;
1154}
1155
1172static ERR_te ssd1309_cmd_fillrect_handler(uint32_t argc, char **argv) {
1173 ERR_te err;
1174
1175 if(argc != 6) {
1176 LOG_ERROR(
1177 internal_state.subsys,
1178 internal_state.log_level,
1179 "ssd1309_cmd_fillrect_handler: invalid arguments"
1180 );
1181
1182 return ERR_INVALID_ARGUMENT;
1183 }
1184
1185 int x1 = str_to_int(argv[2]);
1186 int y1 = str_to_int(argv[3]);
1187 int x2 = str_to_int(argv[4]);
1188 int y2 = str_to_int(argv[5]);
1189
1190 if(
1191 (x1 < 1 || x1 > SSD1309_WIDTH) ||
1192 (y1 < 1 || y1 > SSD1309_HEIGHT) ||
1193 (x2 < 1 || x2 > SSD1309_WIDTH) ||
1194 (y2 < 1 || y2 > SSD1309_HEIGHT)
1195 ) {
1196 LOG_ERROR(
1197 internal_state.subsys,
1198 internal_state.log_level,
1199 "ssd1309_cmd_fillrect_handler: invalid arguments"
1200 );
1201
1202 return ERR_INVALID_ARGUMENT;
1203 }
1204
1205 err = ssd1309_draw_rect(x1, y1, x2, y2, true);
1206 if(err != ERR_OK) {
1207 LOG_ERROR(
1208 internal_state.subsys,
1209 internal_state.log_level,
1210 "ssd1309_cmd_fillrect_handler: invalid arguments"
1211 );
1212
1213 return ERR_INVALID_ARGUMENT;
1214 }
1215
1216 ssd1309_update(true);
1217
1218 return ERR_OK;
1219}
1220
1234static ERR_te ssd1309_cmd_clearrect_handler(uint32_t argc, char **argv) {
1235 ERR_te err;
1236
1237 if(argc != 6) {
1238 LOG_ERROR(
1239 internal_state.subsys,
1240 internal_state.log_level,
1241 "ssd1309_cmd_clearrect_handler: invalid arguments"
1242 );
1243
1244 return ERR_INVALID_ARGUMENT;
1245 }
1246
1247 int x1 = str_to_int(argv[2]);
1248 int y1 = str_to_int(argv[3]);
1249 int x2 = str_to_int(argv[4]);
1250 int y2 = str_to_int(argv[5]);
1251
1252 if(
1253 (x1 < 1 || x1 > SSD1309_WIDTH) ||
1254 (y1 < 1 || y1 > SSD1309_HEIGHT) ||
1255 (x2 < 1 || x2 > SSD1309_WIDTH) ||
1256 (y2 < 1 || y2 > SSD1309_HEIGHT)
1257 ) {
1258 LOG_ERROR(
1259 internal_state.subsys,
1260 internal_state.log_level,
1261 "ssd1309_cmd_clearrect_handler: invalid arguments"
1262 );
1263
1264 return ERR_INVALID_ARGUMENT;
1265 }
1266
1267 err = ssd1309_clear_rect(x1, y1, x2, y2, true);
1268 if(err != ERR_OK) {
1269 LOG_ERROR(
1270 internal_state.subsys,
1271 internal_state.log_level,
1272 "ssd1309_cmd_clearrect_handler: invalid arguments"
1273 );
1274
1275 return ERR_INVALID_ARGUMENT;
1276 }
1277
1278 ssd1309_update(true);
1279
1280 return ERR_OK;
1281}
1282
1296static ERR_te ssd1309_cmd_invertrect_handler(uint32_t argc, char **argv) {
1297 ERR_te err;
1298
1299 if(argc != 6) {
1300 LOG_ERROR(
1301 internal_state.subsys,
1302 internal_state.log_level,
1303 "ssd1309_cmd_invertrect_handler: invalid arguments"
1304 );
1305
1306 return ERR_INVALID_ARGUMENT;
1307 }
1308
1309 int x1 = str_to_int(argv[2]);
1310 int y1 = str_to_int(argv[3]);
1311 int x2 = str_to_int(argv[4]);
1312 int y2 = str_to_int(argv[5]);
1313
1314 if(
1315 (x1 < 1 || x1 > SSD1309_WIDTH) ||
1316 (y1 < 1 || y1 > SSD1309_HEIGHT) ||
1317 (x2 < 1 || x2 > SSD1309_WIDTH) ||
1318 (y2 < 1 || y2 > SSD1309_HEIGHT)
1319 ) {
1320 LOG_ERROR(
1321 internal_state.subsys,
1322 internal_state.log_level,
1323 "ssd1309_cmd_invertrect_handler: invalid arguments"
1324 );
1325
1326 return ERR_INVALID_ARGUMENT;
1327 }
1328
1329 err = ssd1309_invert_rect(x1, y1, x2, y2, true);
1330 if(err != ERR_OK) {
1331 LOG_ERROR(
1332 internal_state.subsys,
1333 internal_state.log_level,
1334 "ssd1309_cmd_invertrect_handler: invalid arguments"
1335 );
1336
1337 return ERR_INVALID_ARGUMENT;
1338 }
1339
1340 ssd1309_update(true);
1341
1342 return ERR_OK;
1343}
1344
1359static ERR_te ssd1309_cmd_drawtext_handler(uint32_t argc, char **argv) {
1360 ERR_te err;
1361
1362 if(argc != 4) {
1363 LOG_ERROR(
1364 internal_state.subsys,
1365 internal_state.log_level,
1366 "ssd1309_cmd_drawtext_handler: invalid arguments"
1367 );
1368
1369 return ERR_INVALID_ARGUMENT;
1370 }
1371
1372 uint8_t line = str_to_int(argv[3]);
1373 if(line > SSD1309_MAX_LINES) {
1374 LOG_ERROR(
1375 internal_state.subsys,
1376 internal_state.log_level,
1377 "ssd1309_cmd_drawtext_handler: invalid arguments"
1378 );
1379
1380 return ERR_INVALID_ARGUMENT;
1381 }
1382
1383 err = ssd1309_draw_text(argv[2], get_str_len(argv[2]), line, true);
1384 if(err != ERR_OK) {
1385 return err;
1386 }
1387
1388 ssd1309_update(true);
1389
1390 return ERR_OK;
1391}
1392
1407static ERR_te ssd1309_cmd_clearline_handler(uint32_t argc, char **argv) {
1408 ERR_te err;
1409
1410 if(argc != 3) {
1411 LOG_ERROR(
1412 internal_state.subsys,
1413 internal_state.log_level,
1414 "ssd1309_cmd_clearline_handler: invalid arguments"
1415 );
1416
1417 return ERR_INVALID_ARGUMENT;
1418 }
1419
1420 uint8_t line = str_to_int(argv[2]);
1421 if(line > SSD1309_MAX_LINES) {
1422 LOG_ERROR(
1423 internal_state.subsys,
1424 internal_state.log_level,
1425 "ssd1309_cmd_clearline_handler: invalid arguments"
1426 );
1427
1428 return ERR_INVALID_ARGUMENT;
1429 }
1430
1431 err = ssd1309_clear_line(line, true);
1432 if(err != ERR_OK) {
1433 return err;
1434 }
1435
1436 ssd1309_update(true);
1437
1438 return ERR_OK;
1439}
1440
1455static ERR_te ssd1309_cmd_invertline_handler(uint32_t argc, char **argv) {
1456 ERR_te err;
1457
1458 if(argc != 3) {
1459 LOG_ERROR(
1460 internal_state.subsys,
1461 internal_state.log_level,
1462 "ssd1309_cmd_invertline_handler: invalid arguments"
1463 );
1464
1465 return ERR_INVALID_ARGUMENT;
1466 }
1467
1468 uint8_t line = str_to_int(argv[2]);
1469 if(line > SSD1309_MAX_LINES) {
1470 LOG_ERROR(
1471 internal_state.subsys,
1472 internal_state.log_level,
1473 "ssd1309_cmd_invertline_handler: invalid arguments"
1474 );
1475
1476 return ERR_INVALID_ARGUMENT;
1477 }
1478
1479 err = ssd1309_invert_line(line, true);
1480 if(err != ERR_OK) {
1481 return err;
1482 }
1483
1484 ssd1309_update(true);
1485
1486 return ERR_OK;
1487}
1488
static struct internal_state_s internal_state
Singleton instance of the SysTick driver internal state.
Command subsystem public API.
Common utility module public API.
System-wide error code definitions.
ERR_te cmd_deregister(CMD_CLIENT_INFO_ts const *cmd_client_info)
Deregisters a client from the command subsystem.
Definition cmd.c:66
ERR_te cmd_register(CMD_CLIENT_INFO_ts *cmd_client_info)
Registers a client with the command subsystem.
Definition cmd.c:51
int str_to_int(const char *str)
Converts a decimal string to an integer.
Definition common.c:69
uint32_t get_str_len(char const *str)
Returns the length of a string, excluding the null terminator.
Definition common.c:22
@ ENABLE
Definition common.h:100
@ DISABLE
Definition common.h:97
ERR_te
Standard return type used by all public API functions.
Definition err.h:35
@ ERR_DEINITIALIZATION_FAILURE
Definition err.h:44
@ ERR_UNKNOWN
Definition err.h:37
@ ERR_OK
Definition err.h:36
@ ERR_MODULE_ALREADY_INITIALIZED
Definition err.h:54
@ ERR_INITIALIZATION_FAILURE
Definition err.h:43
@ ERR_INVALID_ARGUMENT
Definition err.h:38
ERR_te init_log(void)
Initializes the logging subsystem.
Definition init.c:25
#define LOG_ERROR(subsys, lvl, fmt,...)
Definition log.h:258
#define LOG_INFO(subsys, lvl, fmt,...)
Definition log.h:255
LOG_LEVEL_te
Log severity levels, in ascending order of severity.
Definition log.h:63
@ LOG_LEVEL_INFO
Definition log.h:64
MODULES_te
Identifies a subsystem for use in logging and CLI output.
Definition modules.h:42
@ MODULES_SSD1309
Definition modules.h:44
static ERR_te ssd1309_cmd_clearline_handler(uint32_t argc, char **argv)
CLI handler for the "clearline" command. Clears a line and updates the display.
Definition ssd1309.c:1407
static ERR_te ssd1309_cmd_fillrect_handler(uint32_t argc, char **argv)
CLI handler for the "fillrect" command. Fills a rectangle and updates the display.
Definition ssd1309.c:1172
static ERR_te ssd1309_cmd_start_handler(uint32_t argc, char **argv)
CLI handler for the "start" command. Starts the SSD1309 subsystem at runtime.
Definition ssd1309.c:1111
static ERR_te ssd1309_cmd_invertline_handler(uint32_t argc, char **argv)
CLI handler for the "invertline" command. Inverts a line and updates the display.
Definition ssd1309.c:1455
static ERR_te ssd1309_cmd_drawtext_handler(uint32_t argc, char **argv)
CLI handler for the "drawtext" command. Draws text on a line and updates the display.
Definition ssd1309.c:1359
static ERR_te ssd1309_cmd_invertrect_handler(uint32_t argc, char **argv)
CLI handler for the "invertrect" command. Inverts a rectangle and updates the display.
Definition ssd1309.c:1296
static ERR_te ssd1309_cmd_stop_handler(uint32_t argc, char **argv)
CLI handler for the "stop" command. Stops the SSD1309 subsystem at runtime.
Definition ssd1309.c:1140
static ERR_te ssd1309_cmd_clearrect_handler(uint32_t argc, char **argv)
CLI handler for the "clearrect" command. Clears a rectangle and updates the display.
Definition ssd1309.c:1234
#define SSD1309_HEIGHT
Definition ssd1309.h:62
#define SSD1309_WIDTH
Definition ssd1309.h:61
ERR_te ssd1309_update(bool force)
Flushes the internal framebuffer to the display over I2C.
Definition ssd1309.c:1064
ERR_te ssd1309_deinit_subsys(void)
Deinitializes the SSD1309 subsystem.
Definition ssd1309.c:523
ERR_te ssd1309_init_handle(SSD1309_CFG_ts *ssd1309_cfg, SSD1309_HANDLE_ts **ssd1309_handle_o)
Initializes the SSD1309 display handle and sends the configuration sequence.
Definition ssd1309.c:622
ERR_te ssd1309_draw_rect(uint8_t x_src, uint8_t y_src, uint8_t x_dest, uint8_t y_dest, bool force)
Draws a filled rectangle into the framebuffer.
Definition ssd1309.c:843
ERR_te ssd1309_invert_line(uint8_t line, bool force)
Inverts all pixels in a single display line in the framebuffer.
Definition ssd1309.c:924
ERR_te ssd1309_init_subsys(void)
Initializes the SSD1309 subsystem.
Definition ssd1309.c:488
ERR_te ssd1309_start_subsys(void)
Starts the SSD1309 subsystem.
Definition ssd1309.c:551
ERR_te ssd1309_clear_rect(uint8_t x_src, uint8_t y_src, uint8_t x_dest, uint8_t y_dest, bool force)
Clears a rectangular region in the framebuffer.
Definition ssd1309.c:947
ERR_te ssd1309_draw_text(char const *text, uint8_t text_len, uint8_t line, bool force)
Draws a text string into the framebuffer at the specified line.
Definition ssd1309.c:806
ERR_te ssd1309_get_def_cfg(SSD1309_CFG_ts *ssd1309_cfg_o)
Populates a configuration structure with sensible default values.
Definition ssd1309.c:599
ERR_te ssd1309_invert_rect(uint8_t x_src, uint8_t y_src, uint8_t x_dest, uint8_t y_dest, bool force)
Inverts all pixels in a rectangular region of the framebuffer.
Definition ssd1309.c:1005
ERR_te ssd1309_stop_subsys(void)
Stops the SSD1309 subsystem.
Definition ssd1309.c:575
ERR_te ssd1309_clear_line(uint8_t line, bool force)
Clears a single display line in the framebuffer.
Definition ssd1309.c:901
SSD1309_VERTICAL_FLIP_te
Flip the image vertically.
Definition ssd1309.h:855
SSD1309_CLK_SPEED_LVL_te
The clock speed of the SSD1309.
Definition ssd1309.h:958
SSD1309_PHASE2_PRECHARGE_DCLK_te
Phase 2 (charge) length of the segment (pixel) output wave form.
Definition ssd1309.h:1003
SSD1309_COL_ADDR_START_HAM_VAM_te
Column start address for RAM scanning of the SSD1309. Only relevant for HAM and VAM.
Definition ssd1309.h:132
SSD1309_PAGE_START_ADDR_PAM_te
Page address start for RAM scanning of the SSD1309. Only relevant for PAM.
Definition ssd1309.h:840
SSD1309_MEM_ADDR_MODE_te
Memory addressing mode:
Definition ssd1309.h:122
struct ssd1309_handle_s SSD1309_HANDLE_ts
Opaque handle representing an SSD1309 display instance.
Definition ssd1309.h:1136
SSD1309_VCOMH_DESELECT_LVL_te
The deselect level of a LED row in the SSD1309. LOW -> 0.64 * Vcc MED -> 0.78 * Vcc HIGH -> 0....
Definition ssd1309.h:1027
SSD1309_COL_ADDR_END_HAM_VAM_te
Column end address for RAM scanning of the SSD1309. Only relevant for HAM and VAM.
Definition ssd1309.h:267
SSD1309_CONTRAST_te
Current control (brightness) of the LEDs in the SSD1309.
Definition ssd1309.h:503
SSD1309_INVERSE_MODE_te
Causes the values stored in RAM to have the opposite effect. (1 to turn off pixel,...
Definition ssd1309.h:775
SSD1309_CLK_DIV_RATIO_te
The divide ratio of the SSD1309 clock.
Definition ssd1309.h:935
SSD1309_PAGE_ADDR_END_HAM_VAM_te
Page address end for RAM scanning of the SSD1309. Only relevant for HAM and VAM.
Definition ssd1309.h:417
SSD1309_PAGE_ADDR_START_HAM_VAM_te
Page address start for RAM scanning of the SSD1309. Only relevant for HAM and VAM.
Definition ssd1309.h:402
SSD1309_MULTIPLEX_RATIO_te
Number of SSD1309 LED lines activated.
Definition ssd1309.h:784
SSD1309_HORIZONTAL_FLIP_te
Flip the image horizontally.
Definition ssd1309.h:766
SSD1309_HIGH_COL_START_ADDR_PAM_te
Higher column start address (upper 4 bit part of 8 bit address) for RAM scanning of the SSD1309....
Definition ssd1309.h:105
SSD1309_START_LINE_te
Which row in RAM to appear at the top of the screen.
Definition ssd1309.h:432
SSD1309_OFFSET_te
selects which RAM row is internally linked to COM0.
Definition ssd1309.h:864
SSD1309_PHASE1_PRECHARGE_DCLK_te
Phase 1 (discharge) length of the segment (pixel) output wave form.
Definition ssd1309.h:981
SSD1309_LOW_COL_START_ADDR_PAM_te
Lower column start address (lower 4 bit part of 8 bit address) for RAM scanning of the SSD1309....
Definition ssd1309.h:81
void gpio_init(GPIO_CFG_ts *gpio_cfg)
Initializes a GPIO pin according to the given configuration.
GPIO_PIN_te
GPIO pin number within a port (0–15).
GPIO_ALTERNATE_FUNCTION_te
GPIO alternate function mapping (AF0–AF15).
@ GPIO_OUTPUT_TYPE_OPENDRAIN
@ GPIO_MODE_ALTERNATE_FUNCTION
void i2c_init(I2C_CFG_ts *i2c_cfg)
Initializes the I2C peripheral with the given configuration.
void i2c_master_send_continue(I2C_REGDEF_ts *i2c_instance, uint8_t *tx_buffer, uint32_t len)
Continues a transmission started by i2c_master_send without a new START or address phase.
void i2c_master_set_comm(I2C_REGDEF_ts *i2c_instance, EN_STATUS_te en_status)
Enables or disables the I2C peripheral and controls bus ownership.
void i2c_master_send(I2C_REGDEF_ts *i2c_instance, uint8_t slave_addr, uint8_t *tx_buffer, uint32_t len)
Blocking I2C master transmit. Sends a start condition, address, and data.
@ I2C_CLOCK_STRETCH_ON
@ I2C_SPEED_400kHz
Common initialization public API.
Log subsystem public API.
System module identifier definitions.
#define SSD1309_MAX_LINES
Maximum number of text lines on the display (one per page).
Definition ssd1309.c:36
const uint8_t fonts8x8[95][8]
8×8 pixel font table for printable ASCII characters (0x20–0x7E).
Definition ssd1309.c:48
#define SSD1309_COL_NUM
Number of columns in the display.
Definition ssd1309.c:34
#define SSD1309_ADDR_W
I2C write address for the SSD1309 (7-bit address 0x3C, write mode).
Definition ssd1309.c:26
static CMD_CLIENT_INFO_ts ssd1309_cmd_client_info
Registration descriptor passed to the command subsystem.
Definition ssd1309.c:475
static CMD_INFO_ts ssd1309_cmds[]
Table of CLI commands registered by the SSD1309 subsystem.
Definition ssd1309.c:425
#define SSD1309_PAGE_NUM
Number of pages in the SSD1309 display (8 pages × 8 rows = 64 rows).
Definition ssd1309.c:30
#define SSD1309_BITS_IN_PAGE
Number of pixel rows per page.
Definition ssd1309.c:32
SSD1309 OLED display driver public API.
STM32F401RE MCU-specific peripheral register definitions and bit position enumerations.
STM32F401RE GPIO driver public API.
STM32F401RE I2C driver public API.
Describes a subsystem client registering with the command module.
Definition cmd.h:92
Describes a single command exposed by a client.
Definition cmd.h:72
Configuration structure for initializing a GPIO pin.
GPIO_REGDEF_ts * port
GPIO_ALTERNATE_FUNCTION_te alternate_function
GPIO_OUTPUT_TYPE_te output_type
GPIO_PIN_te pin
GPIO_MODE_te mode
GPIO peripheral register map.
Definition stm32f401re.h:95
Configuration structure for initializing an I2C peripheral.
I2C_REGDEF_ts * instance
I2C_CLOCK_STRECH_te clock_strech
I2C_SPEED_te speed
I2C peripheral register map.
Full configuration structure for initializing an SSD1309 display handle.
Definition ssd1309.h:1046
GPIO_PIN_te scl_gpio_pin
Definition ssd1309.h:1054
SSD1309_PHASE2_PRECHARGE_DCLK_te phase2_precharge_dclk
Definition ssd1309.h:1120
SSD1309_PAGE_START_ADDR_PAM_te page_start_addr_pam
Definition ssd1309.h:1102
SSD1309_PAGE_ADDR_END_HAM_VAM_te page_addr_end_ham_vam
Definition ssd1309.h:1084
SSD1309_HIGH_COL_START_ADDR_PAM_te high_col_start_addr_pam
Definition ssd1309.h:1069
SSD1309_MEM_ADDR_MODE_te mem_addr_mode
Definition ssd1309.h:1072
SSD1309_MULTIPLEX_RATIO_te multiplex_ratio
Definition ssd1309.h:1099
SSD1309_LOW_COL_START_ADDR_PAM_te low_col_start_addr_pam
Definition ssd1309.h:1066
SSD1309_PAGE_ADDR_START_HAM_VAM_te page_addr_start_ham_vam
Definition ssd1309.h:1081
SSD1309_VCOMH_DESELECT_LVL_te vcomh_deselect_lvl
Definition ssd1309.h:1123
SSD1309_CLK_SPEED_LVL_te clk_speed_lvl
Definition ssd1309.h:1114
SSD1309_START_LINE_te start_line
Definition ssd1309.h:1087
GPIO_ALTERNATE_FUNCTION_te gpio_alternate_function
Definition ssd1309.h:1063
I2C_REGDEF_ts * i2c_instance
Definition ssd1309.h:1048
GPIO_REGDEF_ts * scl_gpio_port
Definition ssd1309.h:1051
SSD1309_HORIZONTAL_FLIP_te horizontal_flip
Definition ssd1309.h:1093
SSD1309_CONTRAST_te contrast
Definition ssd1309.h:1090
GPIO_REGDEF_ts * sda_gpio_port
Definition ssd1309.h:1057
GPIO_PIN_te sda_gpio_pin
Definition ssd1309.h:1060
SSD1309_OFFSET_te offset
Definition ssd1309.h:1108
SSD1309_PHASE1_PRECHARGE_DCLK_te phase1_precharge_dclk
Definition ssd1309.h:1117
SSD1309_COL_ADDR_START_HAM_VAM_te col_addr_start_ham_vam
Definition ssd1309.h:1075
SSD1309_CLK_DIV_RATIO_te clk_div_ratio
Definition ssd1309.h:1111
SSD1309_VERTICAL_FLIP_te vertical_flip
Definition ssd1309.h:1105
SSD1309_COL_ADDR_END_HAM_VAM_te col_addr_end_ham_vam
Definition ssd1309.h:1078
SSD1309_INVERSE_MODE_te inverse_mode
Definition ssd1309.h:1096
Internal state of the SysTick driver.
MODULES_te subsys
Definition button.c:95
SSD1309_HANDLE_ts ssd1309_handle
Definition ssd1309.c:384
uint8_t fb[SSD1309_PAGE_NUM][SSD1309_COL_NUM]
Definition ssd1309.c:391
LOG_LEVEL_te log_level
Definition button.c:92
Internal structure representing the SSD1309 hardware instance.
Definition ssd1309.c:345
GPIO_PIN_te scl_gpio_pin
Definition ssd1309.c:348
GPIO_PIN_te sda_gpio_pin
Definition ssd1309.c:350
GPIO_REGDEF_ts * scl_gpio_port
Definition ssd1309.c:347
GPIO_ALTERNATE_FUNCTION_te gpio_alternate_function
Definition ssd1309.c:351
I2C_REGDEF_ts * i2c_instance
Definition ssd1309.c:346
GPIO_REGDEF_ts * sda_gpio_port
Definition ssd1309.c:349