{"id":3700,"date":"2025-08-21T07:23:43","date_gmt":"2025-08-21T07:23:43","guid":{"rendered":"https:\/\/blog.embeddedexpert.io\/?p=3700"},"modified":"2025-08-21T07:23:45","modified_gmt":"2025-08-21T07:23:45","slug":"porting-u8g2-graphics-library-to-stm32-part2-ssd1306-oled-display","status":"publish","type":"post","link":"https:\/\/blog.embeddedexpert.io\/?p=3700","title":{"rendered":"Porting U8G2 Graphics Library to STM32 Part2: SSD1306 OLED Display"},"content":{"rendered":"<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"683\" height=\"1024\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/08\/ChatGPT-Image-Aug-21-2025-at-09_39_26-AM-683x1024.png\" alt=\"\" class=\"wp-image-3701\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/08\/ChatGPT-Image-Aug-21-2025-at-09_39_26-AM-683x1024.png 683w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/08\/ChatGPT-Image-Aug-21-2025-at-09_39_26-AM-200x300.png 200w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/08\/ChatGPT-Image-Aug-21-2025-at-09_39_26-AM-768x1152.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/08\/ChatGPT-Image-Aug-21-2025-at-09_39_26-AM-750x1125.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/08\/ChatGPT-Image-Aug-21-2025-at-09_39_26-AM-400x600.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/08\/ChatGPT-Image-Aug-21-2025-at-09_39_26-AM-250x375.png 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/08\/ChatGPT-Image-Aug-21-2025-at-09_39_26-AM.png 1024w\" sizes=\"(max-width: 683px) 100vw, 683px\" \/><\/figure><\/div>\n\n\n<p>In this part, we will use the U8g2 library to interface the popular\u00a0<strong>SSD1306 OLED display<\/strong>\u00a0with STM32. This will demonstrate how to initialize the display and render text and graphics through U8g2.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>In this guide, we shall cover the following:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Adding the U2G8 library to the project.<\/li>\n\n\n\n<li>Developing delay, GPIO and communication callback.<\/li>\n\n\n\n<li>Developing the firmware.<\/li>\n\n\n\n<li>Results.<\/li>\n<\/ul>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">5. Adding U8G2 Library To The Project:<\/h2>\n\n\n\n<p>After downloading the library from the github repository, extract it.<\/p>\n\n\n\n<p>Open the extract is completed, copy csrc folder to the driver folder as follows:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"578\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/08\/2025-08-20_10-50-40-1024x578.jpg\" alt=\"\" class=\"wp-image-3702\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/08\/2025-08-20_10-50-40-1024x578.jpg 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/08\/2025-08-20_10-50-40-300x169.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/08\/2025-08-20_10-50-40-768x433.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/08\/2025-08-20_10-50-40-1536x866.jpg 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/08\/2025-08-20_10-50-40-2048x1155.jpg 2048w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/08\/2025-08-20_10-50-40-1150x649.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/08\/2025-08-20_10-50-40-750x422.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/08\/2025-08-20_10-50-40-400x225.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/08\/2025-08-20_10-50-40-250x141.jpg 250w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>Next, right click on the project and click on properties:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"724\" height=\"1024\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/08\/2025-08-21_09-50-03-724x1024.jpg\" alt=\"\" class=\"wp-image-3703\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/08\/2025-08-21_09-50-03-724x1024.jpg 724w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/08\/2025-08-21_09-50-03-212x300.jpg 212w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/08\/2025-08-21_09-50-03-768x1087.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/08\/2025-08-21_09-50-03-1086x1536.jpg 1086w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/08\/2025-08-21_09-50-03-1150x1627.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/08\/2025-08-21_09-50-03-750x1061.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/08\/2025-08-21_09-50-03-400x566.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/08\/2025-08-21_09-50-03-250x354.jpg 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/08\/2025-08-21_09-50-03.jpg 1268w\" sizes=\"(max-width: 724px) 100vw, 724px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>Next, open the\u00a0<strong>project properties -&gt; C\/C++ Build -&gt; Settings -&gt; GCC Compiler -&gt; Include Path<\/strong>\u00a0and click\u00a0<strong>add button<\/strong>\u00a0to add the folder path here.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"819\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/08\/2025-08-21_09-51-22-1024x819.jpg\" alt=\"\" class=\"wp-image-3704\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/08\/2025-08-21_09-51-22-1024x819.jpg 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/08\/2025-08-21_09-51-22-300x240.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/08\/2025-08-21_09-51-22-768x614.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/08\/2025-08-21_09-51-22-1536x1228.jpg 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/08\/2025-08-21_09-51-22-1150x919.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/08\/2025-08-21_09-51-22-750x600.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/08\/2025-08-21_09-51-22-400x320.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/08\/2025-08-21_09-51-22-250x200.jpg 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/08\/2025-08-21_09-51-22.jpg 1904w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>Add the path as follows and click on Apply and Close.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"654\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/08\/2025-08-21_09-53-04-1024x654.jpg\" alt=\"\" class=\"wp-image-3705\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/08\/2025-08-21_09-53-04-1024x654.jpg 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/08\/2025-08-21_09-53-04-300x192.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/08\/2025-08-21_09-53-04-768x490.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/08\/2025-08-21_09-53-04-1536x981.jpg 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/08\/2025-08-21_09-53-04-2048x1308.jpg 2048w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/08\/2025-08-21_09-53-04-1150x734.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/08\/2025-08-21_09-53-04-750x479.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/08\/2025-08-21_09-53-04-400x255.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/08\/2025-08-21_09-53-04-250x160.jpg 250w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>Now, the library has been added and can be compiled without any issue.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">6. Developing Delay, GPIO and Communication Callback Function:<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">The &#8220;uC specific&#8221; GPIO and Delay callback<a href=\"https:\/\/github.com\/olikraus\/u8g2\/wiki\/Porting-to-new-MCU-platform#the-uc-specific-gpio-and-delay-callback\"><\/a><\/h3>\n\n\n\n<p>GPIO and Delay callback takes care of all the messages regarding the GPIO and Delay.&nbsp;<\/p>\n\n\n\n<p>The&nbsp;<strong>Delay messages<\/strong>&nbsp;might include the delay needed for the display (mostly in millis) or the delay needed to generate the SPI or I2C clocks (mostly in nano or micro) in case the software SPI or I2C is implemented.<\/p>\n\n\n\n<p>The\u00a0<strong>GPIO messages<\/strong>\u00a0include the setting and resetting of the GPIO pins used for interfacing the display. These GPIO pins might include the\u00a0<strong>data pins<\/strong>\u00a0(D0 D1 D2 etc.. in parallel mode) or the\u00a0<strong>control pins<\/strong>\u00a0(CS RST DC in SPI mode).<\/p>\n\n\n\n<p>GPIO and Delay callback function as follows:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">uint8_t u8x8_gpio_and_delay_template(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)\n{\n  switch(msg)\n  {\n    case U8X8_MSG_GPIO_AND_DELAY_INIT:\t\/\/ called once during init phase of u8g2\/u8x8\n      break;\t\t\t\t\t\t\t\/\/ can be used to setup pins\n    case U8X8_MSG_DELAY_NANO:\t\t\t\/\/ delay arg_int * 1 nano second\n      break;    \n    case U8X8_MSG_DELAY_100NANO:\t\t\/\/ delay arg_int * 100 nano seconds\n      break;\n    case U8X8_MSG_DELAY_10MICRO:\t\t\/\/ delay arg_int * 10 micro seconds\n      break;\n    case U8X8_MSG_DELAY_MILLI:\t\t\t\/\/ delay arg_int * 1 milli second\n      break;\n    case U8X8_MSG_DELAY_I2C:\t\t\t\t\/\/ arg_int is the I2C speed in 100KHz, e.g. 4 = 400 KHz\n      break;\t\t\t\t\t\t\t\/\/ arg_int=1: delay by 5us, arg_int = 4: delay by 1.25us\n    case U8X8_MSG_GPIO_D0:\t\t\t\t\/\/ D0 or SPI clock pin: Output level in arg_int\n    \/\/case U8X8_MSG_GPIO_SPI_CLOCK:\n      break;\n    case U8X8_MSG_GPIO_D1:\t\t\t\t\/\/ D1 or SPI data pin: Output level in arg_int\n    \/\/case U8X8_MSG_GPIO_SPI_DATA:\n      break;\n    case U8X8_MSG_GPIO_D2:\t\t\t\t\/\/ D2 pin: Output level in arg_int\n      break;\n    case U8X8_MSG_GPIO_D3:\t\t\t\t\/\/ D3 pin: Output level in arg_int\n      break;\n    case U8X8_MSG_GPIO_D4:\t\t\t\t\/\/ D4 pin: Output level in arg_int\n      break;\n    case U8X8_MSG_GPIO_D5:\t\t\t\t\/\/ D5 pin: Output level in arg_int\n      break;\n    case U8X8_MSG_GPIO_D6:\t\t\t\t\/\/ D6 pin: Output level in arg_int\n      break;\n    case U8X8_MSG_GPIO_D7:\t\t\t\t\/\/ D7 pin: Output level in arg_int\n      break;\n    case U8X8_MSG_GPIO_E:\t\t\t\t\/\/ E\/WR pin: Output level in arg_int\n      break;\n    case U8X8_MSG_GPIO_CS:\t\t\t\t\/\/ CS (chip select) pin: Output level in arg_int\n      break;\n    case U8X8_MSG_GPIO_DC:\t\t\t\t\/\/ DC (data\/cmd, A0, register select) pin: Output level in arg_int\n      break;\n    case U8X8_MSG_GPIO_RESET:\t\t\t\/\/ Reset pin: Output level in arg_int\n      break;\n    case U8X8_MSG_GPIO_CS1:\t\t\t\t\/\/ CS1 (chip select) pin: Output level in arg_int\n      break;\n    case U8X8_MSG_GPIO_CS2:\t\t\t\t\/\/ CS2 (chip select) pin: Output level in arg_int\n      break;\n    case U8X8_MSG_GPIO_I2C_CLOCK:\t\t\/\/ arg_int=0: Output low at I2C clock pin\n      break;\t\t\t\t\t\t\t\/\/ arg_int=1: Input dir with pullup high for I2C clock pin\n    case U8X8_MSG_GPIO_I2C_DATA:\t\t\t\/\/ arg_int=0: Output low at I2C data pin\n      break;\t\t\t\t\t\t\t\/\/ arg_int=1: Input dir with pullup high for I2C data pin\n    case U8X8_MSG_GPIO_MENU_SELECT:\n      u8x8_SetGPIOResult(u8x8, \/* get menu select pin state *\/ 0);\n      break;\n    case U8X8_MSG_GPIO_MENU_NEXT:\n      u8x8_SetGPIOResult(u8x8, \/* get menu next pin state *\/ 0);\n      break;\n    case U8X8_MSG_GPIO_MENU_PREV:\n      u8x8_SetGPIOResult(u8x8, \/* get menu prev pin state *\/ 0);\n      break;\n    case U8X8_MSG_GPIO_MENU_HOME:\n      u8x8_SetGPIOResult(u8x8, \/* get menu home pin state *\/ 0);\n      break;\n    default:\n      u8x8_SetGPIOResult(u8x8, 1);\t\t\t\/\/ default return value\n      break;\n  }\n  return 1;\n}<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>Since we are using hardware i2c and configured properly, we need only the delay function to be port as follows:<\/p>\n\n\n\n<p>First, start by including u8g2 library as follows:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#include &quot;u8g2.h&quot;<\/pre><\/div>\n\n\n\n<p>Next, declare u8g2 structure as follows:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">u8g2_t myDisplay;<\/pre><\/div>\n\n\n\n<p>Declare the delay and gpio function as follows:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">uint8_t u8x8_gpio_and_delay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)\n{\n\t  switch(msg)\n\t  {\n\t  case U8X8_MSG_DELAY_MILLI:\n\t\t  HAL_Delay(arg_int);\n\t\t  break;\n\t  }\n\t  return 1;\n}\n<\/pre><\/div>\n\n\n\n<p>We are only interested in the delay function since the i2c is hardware level.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Function Arguments<\/strong><\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong><code>u8x8_t *u8x8<\/code><\/strong>\n<ul class=\"wp-block-list\">\n<li>Pointer to the U8x8 structure (internal state of the library).<\/li>\n\n\n\n<li>Normally you don\u2019t need to use this directly unless you\u2019re doing advanced things.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong><code>uint8_t msg<\/code><\/strong>\n<ul class=\"wp-block-list\">\n<li>Message code sent by U8g2 telling your function\u00a0<strong>what action to perform<\/strong>.<\/li>\n\n\n\n<li>Examples of messages:\n<ul class=\"wp-block-list\">\n<li><code>U8X8_MSG_GPIO_AND_DELAY_INIT<\/code>\u00a0\u2192 Initialize GPIOs and timers.<\/li>\n\n\n\n<li><code>U8X8_MSG_DELAY_MILLI<\/code>\u00a0\u2192 Delay\u00a0<code>arg_int<\/code>\u00a0milliseconds.<\/li>\n\n\n\n<li><code>U8X8_MSG_DELAY_10MICRO<\/code>\u00a0\u2192 Delay\u00a0<code>arg_int * 10 \u00b5s<\/code>.<\/li>\n\n\n\n<li><code>U8X8_MSG_GPIO_CS<\/code>\u00a0\u2192 Set\u00a0<strong>Chip Select (CS)<\/strong>\u00a0pin (high\/low).<\/li>\n\n\n\n<li><code>U8X8_MSG_GPIO_DC<\/code>\u00a0\u2192 Set\u00a0<strong>Data\/Command (DC)<\/strong>\u00a0pin.<\/li>\n\n\n\n<li><code>U8X8_MSG_GPIO_RESET<\/code>\u00a0\u2192 Set\u00a0<strong>Reset (RES)<\/strong>\u00a0pin.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong><code>uint8_t arg_int<\/code><\/strong>\n<ul class=\"wp-block-list\">\n<li>Integer parameter passed along with the message.<\/li>\n\n\n\n<li>Usage depends on the\u00a0<code>msg<\/code>:\n<ul class=\"wp-block-list\">\n<li>For delay messages \u2192 number of milliseconds or 10\u00b5s units.<\/li>\n\n\n\n<li>For GPIO messages \u2192 value\u00a0<code>0<\/code>\u00a0(low) or\u00a0<code>1<\/code>\u00a0(high).<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong><code>void *arg_ptr<\/code><\/strong>\n<ul class=\"wp-block-list\">\n<li>Pointer argument (rarely used for GPIO\/delay).<\/li>\n\n\n\n<li>Mainly used for things like SPI data transfer in the byte callback, not here.<\/li>\n\n\n\n<li>For GPIO\/delay handler, you usually\u00a0<strong>ignore<\/strong>\u00a0this.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<p><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Communication Callback<\/h3>\n\n\n\n<p>Communication callback is used to handle the messages used during the communication with the display. These messages includes the transfer start, byte send, transfer end, etc.<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">uint8_t u8x8_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)\n{\n  static uint8_t buffer[32];\t\t\/* u8g2\/u8x8 will never send more than 32 bytes between START_TRANSFER and END_TRANSFER *\/\n  static uint8_t buf_idx;\n  uint8_t *data;\n\n  switch(msg)\n  {\n    case U8X8_MSG_BYTE_SEND:\n      data = (uint8_t *)arg_ptr;\n      while( arg_int &gt; 0 )\n      {\n\tbuffer[buf_idx++] = *data;\n\tdata++;\n\targ_int--;\n      }\n      break;\n    case U8X8_MSG_BYTE_START_TRANSFER:\n      buf_idx = 0;\n      break;\n    case U8X8_MSG_BYTE_END_TRANSFER:\n\t\t#define OLED_Addr (0x3D&lt;&lt;1)\n    \tHAL_I2C_Master_Transmit(&amp;hi2c1, OLED_Addr, buffer, buf_idx, 100);\n      break;\n    default:\n      return 0;\n  }\n  return 1;\n}<\/pre><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Arguments:<\/h3>\n\n\n\n<p>This is the&nbsp;<strong>I\u00b2C byte handler callback<\/strong>.<br>U8g2 uses it to send data to the display over I\u00b2C.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><code>u8x8<\/code><\/strong>\u00a0\u2192 Pointer to the U8x8 object (library context). Not used here.<\/li>\n\n\n\n<li><strong><code>msg<\/code><\/strong>\u00a0\u2192 Message code from U8g2 (what action to do).<\/li>\n\n\n\n<li><strong><code>arg_int<\/code><\/strong>\u00a0\u2192 Integer value; depends on the message.<\/li>\n\n\n\n<li><strong><code>arg_ptr<\/code><\/strong>\u00a0\u2192 Pointer; often points to data bytes to send.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">Inside the Function<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Local static variables:<\/h3>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">static uint8_t buffer[32];  \/\/ Local buffer for I2C data\nstatic uint8_t buf_idx;     \/\/ Current write index\n<\/pre><\/div>\n\n\n\n<ul class=\"wp-block-list\">\n<li>U8g2 guarantees it will never request sending\u00a0<strong>more than 32 bytes at once<\/strong>\u00a0(between START and END).<\/li>\n\n\n\n<li>This ensures the buffer is always big enough.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h3 class=\"wp-block-heading\">Handling different messages<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>1. U8X8_MSG_BYTE_SEND<\/strong><\/h4>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">data = (uint8_t *)arg_ptr;\nwhile( arg_int &gt; 0 )\n{\n    buffer[buf_idx++] = *data;\n    data++;\n    arg_int--;\n}\n<\/pre><\/div>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>arg_ptr<\/code>\u00a0points to a chunk of data (one or more bytes) that U8g2 wants to send.<\/li>\n\n\n\n<li><code>arg_int<\/code>\u00a0tells how many bytes.<\/li>\n\n\n\n<li>The code copies those bytes into the local\u00a0<code>buffer<\/code>, increasing\u00a0<code>buf_idx<\/code>.<\/li>\n\n\n\n<li><strong>Nothing is sent yet<\/strong>\u00a0\u2014 just stored.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>2. U8X8_MSG_BYTE_START_TRANSFER<\/strong><\/h4>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">buf_idx = 0;\n<\/pre><\/div>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Marks the\u00a0<strong>beginning<\/strong>\u00a0of an I\u00b2C transfer.<\/li>\n\n\n\n<li>Reset the buffer index so data will start filling from the beginning.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>3. U8X8_MSG_BYTE_END_TRANSFER<\/strong><\/h4>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#define OLED_Addr (0x3D&lt;&lt;1)\nHAL_I2C_Master_Transmit(&amp;hi2c1, OLED_Addr, buffer, buf_idx, 100);\n<\/pre><\/div>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Marks the\u00a0<strong>end<\/strong>\u00a0of the I\u00b2C transfer.<\/li>\n\n\n\n<li>Now send everything in the\u00a0<code>buffer<\/code>\u00a0to the OLED in one I\u00b2C transmission.<\/li>\n\n\n\n<li><code>OLED_Addr<\/code>\u00a0= device address (<code>0x3D<\/code>\u00a0shifted left by 1 \u2192 8-bit I\u00b2C address) (Change it accordingly)<\/li>\n\n\n\n<li>Uses HAL function:<code>HAL_I2C_Master_Transmit(&amp;hi2c1, OLED_Addr, buffer, buf_idx, 100); <\/code>where\n<ul class=\"wp-block-list\">\n<li><code>&amp;hi2c1<\/code>\u00a0\u2192 I\u00b2C handle (configured in CubeMX).<\/li>\n\n\n\n<li><code>OLED_Addr<\/code>\u00a0\u2192 I\u00b2C address of SSD1306.<\/li>\n\n\n\n<li><code>buffer<\/code>\u00a0\u2192 Pointer to data collected.<\/li>\n\n\n\n<li><code>buf_idx<\/code>\u00a0\u2192 How many bytes to send.<\/li>\n\n\n\n<li><code>100<\/code>\u00a0\u2192 Timeout in ms.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>4. Default<\/strong><\/h4>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">return 0;\n<\/pre><\/div>\n\n\n\n<ul class=\"wp-block-list\">\n<li>If the\u00a0<code>msg<\/code>\u00a0isn\u2019t recognized, return 0 = unhandled.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h3 class=\"wp-block-heading\">Return Value<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Always return\u00a0<code>1<\/code>\u00a0if handled successfully.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Summary of Flow<\/strong><\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>START_TRANSFER<\/strong>\u00a0\u2192 reset buffer index.<\/li>\n\n\n\n<li><strong>BYTE_SEND<\/strong>\u00a0\u2192 copy incoming bytes into buffer.<\/li>\n\n\n\n<li><strong>END_TRANSFER<\/strong>\u00a0\u2192 send everything via\u00a0<code>HAL_I2C_Master_Transmit<\/code>.<\/li>\n<\/ol>\n\n\n\n<p>So this function is the&nbsp;<strong>bridge<\/strong>&nbsp;between U8g2 and STM32\u2019s HAL I\u00b2C driver.<br>It batches the display commands into a buffer and sends them efficiently in one I\u00b2C transaction.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Thats all for porting any I2C display.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">7. Firmware Development:<\/h2>\n\n\n\n<p><\/p>\n\n\n\n<p>In main function in user code begin 2, start by linking the display to our bus as follows:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\"> u8g2_Setup_ssd1306_i2c_128x64_noname_f(&amp;myDisplay, U8G2_R0, u8x8_i2c, u8x8_gpio_and_delay);<\/pre><\/div>\n\n\n\n<p>Next, initialize the display as follows:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\"> u8g2_InitDisplay(&amp;myDisplay); \/\/ send init sequence to the display, display is in sleep mode after this,<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>Exit the sleep mode since the display will be in sleep mode after initialization:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">u8g2_SetPowerSave(&amp;myDisplay, 0); \/\/ wake up display<\/pre><\/div>\n\n\n\n<p>Next, we shall start writing to the display.<\/p>\n\n\n\n<p>First, clear the display as follows:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">u8g2_ClearDisplay(&amp;myDisplay);<\/pre><\/div>\n\n\n\n<p>Set font type:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">u8g2_SetFont(&amp;myDisplay, u8g2_font_ncenB14_tr);<\/pre><\/div>\n\n\n\n<p>Display the string as follows:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">u8g2_DrawStr(&amp;myDisplay, 0,15,&quot;Hello world&quot;);<\/pre><\/div>\n\n\n\n<p>Draw a shape (Circle) as follows:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">u8g2_DrawCircle(&amp;myDisplay, 60, 30, 10, U8G2_DRAW_ALL);<\/pre><\/div>\n\n\n\n<p>Send the new content to the display as follows:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\"> u8g2_SendBuffer(&amp;myDisplay);<\/pre><\/div>\n\n\n\n<p>Thats all for the firmware. Save the project and run it on your MCU as follows:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"34\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-03_17-48-35-1024x34.jpg\" alt=\"\" class=\"wp-image-3598\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-03_17-48-35-1024x34.jpg 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-03_17-48-35-300x10.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-03_17-48-35-768x25.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-03_17-48-35-1536x51.jpg 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-03_17-48-35-2048x68.jpg 2048w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-03_17-48-35-1150x38.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-03_17-48-35-750x25.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-03_17-48-35-400x13.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-03_17-48-35-250x8.jpg 250w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">8. Results:<\/h2>\n\n\n\n<p><\/p>\n\n\n\n<p>Once you run the project, you should see the following on your display:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/08\/IMG_7806.heic\" alt=\"\" class=\"wp-image-3706\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>We have successfully integrated U8G2 into our project and display text and shapes on the display.<\/p>\n\n\n\n<p>Next, we shall different type of display, stay tuned.<\/p>\n\n\n\n<p>Happy coding \ud83d\ude09<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this part, we will use the U8g2 library to interface the popular\u00a0SSD1306 OLED display\u00a0with STM32. This will demonstrate how to initialize the display and render text and graphics through U8g2. In this guide, we shall cover the following: 5. Adding U8G2 Library To The Project: After downloading the library from the github repository, extract [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2,19,11,12],"tags":[],"class_list":["post-3700","post","type-post","status-publish","format-standard","hentry","category-embedded-systems","category-lcd","category-peripheral-drivers","category-stm32"],"_links":{"self":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/3700"}],"collection":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3700"}],"version-history":[{"count":1,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/3700\/revisions"}],"predecessor-version":[{"id":3707,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/3700\/revisions\/3707"}],"wp:attachment":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3700"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3700"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3700"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}