GPS Device
Loading...
Searching...
No Matches
SSD1309 Public API

Public functions to interact with the SSD1309 display subsystem. More...

Collaboration diagram for SSD1309 Public API:

Functions

ERR_te ssd1309_init_subsys (void)
 Initializes the SSD1309 subsystem.
ERR_te ssd1309_deinit_subsys (void)
 Deinitializes the SSD1309 subsystem.
ERR_te ssd1309_start_subsys (void)
 Starts the SSD1309 subsystem.
ERR_te ssd1309_stop_subsys (void)
 Stops the SSD1309 subsystem.
ERR_te ssd1309_get_def_cfg (SSD1309_CFG_ts *ssd1309_cfg_o)
 Populates a configuration structure with sensible default values.
ERR_te ssd1309_init_handle (SSD1309_CFG_ts *ssd1309_cfg, SSD1309_HANDLE_ts **ssd1309_handle_o)
 Initializes the SSD1309 display and sends the full configuration sequence over I2C.
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.
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.
ERR_te ssd1309_clear_line (uint8_t line, bool force)
 Clears a single display line in the framebuffer (sets all pixels off).
ERR_te ssd1309_invert_line (uint8_t line, bool force)
 Inverts all pixels in a single display line in the framebuffer.
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 (sets all pixels off).
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.
ERR_te ssd1309_update (bool force)
 Flushes the internal framebuffer to the display over I2C.

Detailed Description

Public functions to interact with the SSD1309 display subsystem.

Function Documentation

◆ ssd1309_init_subsys()

ERR_te ssd1309_init_subsys ( void )

Initializes the SSD1309 subsystem.

Resets the internal state, initializes the logging dependency, and registers the CLI commands.

Must be called before any other SSD1309 API function.

Returns
  • ERR_OK on success
  • ERR_MODULE_ALREADY_INITIALIZED if the subsystem is already initialized
  • Propagated error from cmd_register on failure
See also
ssd1309_init_subsys

Definition at line 488 of file ssd1309.c.

488 {
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}
static struct internal_state_s internal_state
Singleton instance of the SysTick driver internal state.
ERR_te cmd_register(CMD_CLIENT_INFO_ts *cmd_client_info)
Registers a client with the command subsystem.
Definition cmd.c:51
ERR_te
Standard return type used by all public API functions.
Definition err.h:35
@ ERR_OK
Definition err.h:36
@ ERR_MODULE_ALREADY_INITIALIZED
Definition err.h:54
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_INFO
Definition log.h:64
@ MODULES_SSD1309
Definition modules.h:44
static CMD_CLIENT_INFO_ts ssd1309_cmd_client_info
Registration descriptor passed to the command subsystem.
Definition ssd1309.c:475
Internal state of the SysTick driver.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ssd1309_deinit_subsys()

ERR_te ssd1309_deinit_subsys ( void )

Deinitializes the SSD1309 subsystem.

Resets the internal state to zero and deregisters the CLI commands. The subsystem must be stopped before calling this function.

Returns
  • ERR_OK on success
  • ERR_DEINITIALIZATION_FAILURE if the subsystem is not initialized or still running
  • Propagated error from cmd_deregister on failure
See also
ssd1309_deinit_subsys

Definition at line 523 of file ssd1309.c.

523 {
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}
ERR_te cmd_deregister(CMD_CLIENT_INFO_ts const *cmd_client_info)
Deregisters a client from the command subsystem.
Definition cmd.c:66
@ ERR_DEINITIALIZATION_FAILURE
Definition err.h:44
Here is the call graph for this function:

◆ ssd1309_start_subsys()

ERR_te ssd1309_start_subsys ( void )

Starts the SSD1309 subsystem.

Returns
  • ERR_OK on success
  • ERR_UNKNOWN if the subsystem is not initialized or already started
See also
ssd1309_start_subsys

Definition at line 551 of file ssd1309.c.

551 {
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}
@ ERR_UNKNOWN
Definition err.h:37
Here is the caller graph for this function:

◆ ssd1309_stop_subsys()

ERR_te ssd1309_stop_subsys ( void )

Stops the SSD1309 subsystem.

Returns
  • ERR_OK on success
  • ERR_UNKNOWN if the subsystem is not initialized or already stopped
See also
ssd1309_stop_subsys

Definition at line 575 of file ssd1309.c.

575 {
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}

◆ ssd1309_get_def_cfg()

ERR_te ssd1309_get_def_cfg ( SSD1309_CFG_ts * ssd1309_cfg_o)

Populates a configuration structure with sensible default values.

The default configuration uses:

  • Horizontal addressing mode (HAM), full 128×64 column and page range
  • Contrast level 10, both horizontal and vertical flip enabled
  • Multiplex ratio 64, no display offset, clock divide ratio 1
  • Clock speed level 15, phase 1 and phase 2 precharge of 2 DCLKs
  • VCOMH deselect level: medium (0.78 × Vcc)

The I2C instance and GPIO fields are not set and must be filled in by the caller before passing to ssd1309_init_handle.

Parameters
[out]ssd1309_cfg_oPointer to the configuration structure to populate.
Returns
  • ERR_OK always
See also
ssd1309_get_def_cfg

Definition at line 599 of file ssd1309.c.

599 {
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}
SSD1309_PHASE2_PRECHARGE_DCLK_te phase2_precharge_dclk
Definition ssd1309.h:1120
SSD1309_PAGE_ADDR_END_HAM_VAM_te page_addr_end_ham_vam
Definition ssd1309.h:1084
SSD1309_MEM_ADDR_MODE_te mem_addr_mode
Definition ssd1309.h:1072
SSD1309_MULTIPLEX_RATIO_te multiplex_ratio
Definition ssd1309.h:1099
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
SSD1309_HORIZONTAL_FLIP_te horizontal_flip
Definition ssd1309.h:1093
SSD1309_CONTRAST_te contrast
Definition ssd1309.h:1090
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
Here is the caller graph for this function:

◆ ssd1309_init_handle()

ERR_te ssd1309_init_handle ( SSD1309_CFG_ts * ssd1309_cfg,
SSD1309_HANDLE_ts ** ssd1309_handle_o )

Initializes the SSD1309 display and sends the full configuration sequence over I2C.

Configures the SCL and SDA GPIO pins in open-drain alternate function mode, initializes the I2C peripheral at 400 kHz, and transmits the complete SSD1309 initialization command sequence derived from ssd1309_cfg.

The display is turned off during configuration and turned on at the end.

Note
Only one handle instance is supported. Calling this function a second time without deinitialization returns an error.
Parameters
[in]ssd1309_cfgPointer to the display configuration structure.
[out]ssd1309_handle_oPointer to a handle pointer that will be set to the initialized display instance.
Returns
  • ERR_OK on success
  • ERR_INITIALIZATION_FAILURE if a handle is already initialized, or if the I2C or GPIO pointers in ssd1309_cfg are NULL

Initializes the SSD1309 display and sends the full configuration sequence over I2C.

See also
ssd1309_init_handle

Definition at line 622 of file ssd1309.c.

622 {
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}
@ ENABLE
Definition common.h:100
@ DISABLE
Definition common.h:97
@ ERR_INITIALIZATION_FAILURE
Definition err.h:43
void gpio_init(GPIO_CFG_ts *gpio_cfg)
Initializes a GPIO pin according to the given configuration.
@ 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_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
#define SSD1309_ADDR_W
I2C write address for the SSD1309 (7-bit address 0x3C, write mode).
Definition ssd1309.c:26
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
Configuration structure for initializing an I2C peripheral.
I2C_REGDEF_ts * instance
I2C_CLOCK_STRECH_te clock_strech
I2C_SPEED_te speed
GPIO_PIN_te scl_gpio_pin
Definition ssd1309.h:1054
SSD1309_PAGE_START_ADDR_PAM_te page_start_addr_pam
Definition ssd1309.h:1102
SSD1309_HIGH_COL_START_ADDR_PAM_te high_col_start_addr_pam
Definition ssd1309.h:1069
SSD1309_LOW_COL_START_ADDR_PAM_te low_col_start_addr_pam
Definition ssd1309.h:1066
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
GPIO_REGDEF_ts * sda_gpio_port
Definition ssd1309.h:1057
GPIO_PIN_te sda_gpio_pin
Definition ssd1309.h:1060
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ssd1309_draw_text()

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.

Renders characters from the built-in 8×8 font table into the framebuffer. Each character occupies 8 columns; characters wrap to the next line if they exceed the display width. The framebuffer is not flushed to the display; call ssd1309_update to make the changes visible.

Supports printable ASCII characters (0x20–0x7E).

Parameters
[in]textPointer to the text string to render.
[in]text_lenNumber of characters to render from text.
[in]lineDisplay line (1–8, top to bottom) where text begins.
[in]forceIf true, bypasses the initialized/started guard.
Returns
  • ERR_OK on success
  • ERR_INITIALIZATION_FAILURE if not initialized/started and force is false
  • ERR_INVALID_ARGUMENT if line is out of range
See also
ssd1309_draw_text

Definition at line 806 of file ssd1309.c.

806 {
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}
@ ERR_INVALID_ARGUMENT
Definition err.h:38
#define SSD1309_WIDTH
Definition ssd1309.h:61
const uint8_t fonts8x8[95][8]
8×8 pixel font table for printable ASCII characters (0x20–0x7E).
Definition ssd1309.c:48
#define SSD1309_PAGE_NUM
Number of pages in the SSD1309 display (8 pages × 8 rows = 64 rows).
Definition ssd1309.c:30
Here is the caller graph for this function:

◆ ssd1309_draw_rect()

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.

Sets all pixels within the rectangle defined by (x_src, y_src) to (x_dest, y_dest) in the framebuffer. Coordinates are 1-based. The framebuffer is not flushed; call ssd1309_update to display the result.

Parameters
[in]x_srcLeft edge of the rectangle (1–128).
[in]y_srcTop edge of the rectangle (1–64).
[in]x_destRight edge of the rectangle (1–128, must be ≥ x_src).
[in]y_destBottom edge of the rectangle (1–64, must be ≥ y_src).
[in]forceIf true, bypasses the initialized/started guard.
Returns
  • ERR_OK on success
  • ERR_INITIALIZATION_FAILURE if not initialized/started and force is false
  • ERR_INVALID_ARGUMENT if coordinates are out of range or x_src > x_dest
See also
ssd1309_draw_rect

Definition at line 843 of file ssd1309.c.

843 {
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}
#define SSD1309_HEIGHT
Definition ssd1309.h:62
#define SSD1309_BITS_IN_PAGE
Number of pixel rows per page.
Definition ssd1309.c:32
Here is the caller graph for this function:

◆ ssd1309_clear_line()

ERR_te ssd1309_clear_line ( uint8_t line,
bool force )

Clears a single display line in the framebuffer (sets all pixels off).

Equivalent to calling ssd1309_clear_rect over the full width of the given line. The framebuffer is not flushed; call ssd1309_update afterwards.

Parameters
[in]lineDisplay line to clear (1–8).
[in]forceIf true, bypasses the initialized/started guard.
Returns
  • ERR_OK on success
  • ERR_INITIALIZATION_FAILURE if not initialized/started and force is false
  • ERR_INVALID_ARGUMENT if line is out of range

Clears a single display line in the framebuffer (sets all pixels off).

See also
ssd1309_clear_line

Definition at line 901 of file ssd1309.c.

901 {
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}
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
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ssd1309_invert_line()

ERR_te ssd1309_invert_line ( uint8_t line,
bool force )

Inverts all pixels in a single display line in the framebuffer.

Equivalent to calling ssd1309_invert_rect over the full width of the given line. Used by the menu module to simulate a selection highlight. The framebuffer is not flushed; call ssd1309_update afterwards.

Parameters
[in]lineDisplay line to invert (1–8).
[in]forceIf true, bypasses the initialized/started guard.
Returns
  • ERR_OK on success
  • ERR_INITIALIZATION_FAILURE if not initialized/started and force is false
  • ERR_INVALID_ARGUMENT if line is out of range
See also
ssd1309_invert_line

Definition at line 924 of file ssd1309.c.

924 {
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}
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
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ssd1309_clear_rect()

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 (sets all pixels off).

Clears all pixels within the rectangle defined by (x_src, y_src) to (x_dest, y_dest). Coordinates are 1-based. The framebuffer is not flushed; call ssd1309_update to display the result.

Parameters
[in]x_srcLeft edge (1–128).
[in]y_srcTop edge (1–64).
[in]x_destRight edge (1–128, must be ≥ x_src).
[in]y_destBottom edge (1–64, must be ≥ y_src).
[in]forceIf true, bypasses the initialized/started guard.
Returns
  • ERR_OK on success
  • ERR_INITIALIZATION_FAILURE if not initialized/started and force is false
  • ERR_INVALID_ARGUMENT if coordinates are out of range or x_src > x_dest

Clears a rectangular region in the framebuffer (sets all pixels off).

See also
ssd1309_clear_rect

Definition at line 947 of file ssd1309.c.

947 {
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}
Here is the caller graph for this function:

◆ ssd1309_invert_rect()

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.

XORs all pixels within the rectangle defined by (x_src, y_src) to (x_dest, y_dest). Coordinates are 1-based. The framebuffer is not flushed; call ssd1309_update to display the result.

Parameters
[in]x_srcLeft edge (1–128).
[in]y_srcTop edge (1–64).
[in]x_destRight edge (1–128, must be ≥ x_src).
[in]y_destBottom edge (1–64, must be ≥ y_src).
[in]forceIf true, bypasses the initialized/started guard.
Returns
  • ERR_OK on success
  • ERR_INITIALIZATION_FAILURE if not initialized/started and force is false
  • ERR_INVALID_ARGUMENT if coordinates are out of range or x_src > x_dest
See also
ssd1309_invert_rect

Definition at line 1005 of file ssd1309.c.

1005 {
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}
Here is the caller graph for this function:

◆ ssd1309_update()

ERR_te ssd1309_update ( bool force)

Flushes the internal framebuffer to the display over I2C.

Transmits the full 128×8-page framebuffer to the SSD1309 over I2C, making all pending framebuffer changes visible on the display.

Parameters
[in]forceIf true, bypasses the initialized/started guard.
Returns
  • ERR_OK on success
  • ERR_INITIALIZATION_FAILURE if not initialized/started and force is false
See also
ssd1309_update

Definition at line 1064 of file ssd1309.c.

1064 {
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}
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.
Here is the call graph for this function:
Here is the caller graph for this function: