
The SH1106 is a popular monochrome OLED display driver, commonly used in small screens ranging from 0.96″ to 1.3″, offering high contrast and low power consumption. It communicates via SPI or I²C interfaces, making it suitable for microcontroller projects requiring compact graphical displays.
In this guide, we shall cover the following:
- STM32CubeMX Configuration.
- Connection.
- Firmware Development.
- Results.
1. STM32CubeMX Configuration:
From the previous project, open u8g2.ioc file as follows:

STM32CubeMX window shall appears.
Next, head to Clock Configuration and set the frequency to 100MHz (or what maximum can be handled by your STM32) as follows:

Next, from Pinout & Configuration, select SPI1 and set to Master Transmit only (Display sends nothing back) as follows:

This will automatically enable PA5 as SCK and PA7 as MOSI as shown below:

Next, configure the SPI as follows:
- Frame Format to Motorola.
- Data size to 8-bit.
- First bit is MSB first.
- Set prescaler to get between 20 and 25 Mbit/s.
- Clock Polarity to low.
- Clock phase to 1 edge

Next, Enable PA0 and PA1 and give a name of CS and DC respectively as shown below:

Thats all for STM32CubeMX configuration. Save the project and this will generate the code.
2. Connection:
The connection as follows:
SH1106 SPI OLED Display | STM32F411 Nucleo-64 |
GND | GND |
Vcc | 5V |
SDA | PA5 (D13 of Arduino pins) |
SCL | PA7 (D11 of Arduino pins) |
DC | PA1 (A1 of Arduino pins) |
CS | PA0 (A0 of Arduino pins) |

3. Firmware Development:
We start off by defining the gpio and delay function as follows:
uint8_t u8x8_gpio_and_delay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr) { switch(msg) { case U8X8_MSG_DELAY_MILLI: HAL_Delay(arg_int); break; case U8X8_MSG_GPIO_CS: HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, arg_int); break; case U8X8_MSG_GPIO_DC: HAL_GPIO_WritePin(DC_GPIO_Port, DC_Pin, arg_int); break; } return 1; }
Purpose
This function serves as a bridge between the U8G2 graphics library and the STM32 hardware, handling GPIO control and timing delays.
Function Parameters
u8x8_t *u8x8
: U8G2 display structure pointeruint8_t msg
: Message type indicating what operation to performuint8_t arg_int
: Integer argument (like pin state or delay time)void *arg_ptr
: Pointer argument (not used here)
Message Handling
1. U8X8_MSG_DELAY_MILLI
- Purpose: Implements millisecond delays
- Implementation: Uses STM32’s HAL_Delay() function
- Usage:
arg_int
contains the number of milliseconds to delay
2. U8X8_MSG_GPIO_CS
- Purpose: Controls the Chip Select (CS) pin
- Implementation: Uses HAL_GPIO_WritePin() to set CS pin state
- Usage:
arg_int
determines pin state (0 = low, 1 = high)
3. U8X8_MSG_GPIO_DC
- Purpose: Controls the Data/Command (DC) pin
- Implementation: Uses HAL_GPIO_WritePin() to set DC pin state
- Usage:
arg_int
determines pin state (0 = command mode, 1 = data mode)
Next, spi communication as follows:
uint8_t u8x8_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr) { switch(msg) { case U8X8_MSG_BYTE_SET_DC: HAL_GPIO_WritePin(DC_GPIO_Port, DC_Pin, arg_int); break; case U8X8_MSG_BYTE_SEND: HAL_SPI_Transmit(&hspi1, (uint8_t *)arg_ptr, arg_int, 1000); break; case U8X8_MSG_BYTE_START_TRANSFER: HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_RESET); break; case U8X8_MSG_BYTE_END_TRANSFER: HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_SET); break; default: break; } return 1; }
Purpose
This function handles the low-level SPI communication between the STM32 microcontroller and the display, managing data/command mode, data transmission, and chip select control.
Message Handling
1. U8X8_MSG_BYTE_SET_DC
- Purpose: Sets the Data/Command (DC) pin state
- Implementation: Uses
HAL_GPIO_WritePin()
to control the DC pin - Usage:
arg_int
determines the mode:0
: Command mode (sending display instructions)1
: Data mode (sending pixel data)
2. U8X8_MSG_BYTE_SEND
- Purpose: Transmits data over SPI
- Implementation: Uses
HAL_SPI_Transmit()
to send data - Parameters:
&hspi1
: SPI handle (SPI1 peripheral)(uint8_t *)arg_ptr
: Pointer to the data buffer to transmitarg_int
: Number of bytes to transmit1000
: Timeout in milliseconds
3. U8X8_MSG_BYTE_START_TRANSFER
- Purpose: Begins an SPI transaction
- Implementation: Pulls CS (Chip Select) pin LOW to enable the display chip
- Usage:
GPIO_PIN_RESET
sets the pin LOW (active)
4. U8X8_MSG_BYTE_END_TRANSFER
- Purpose: Ends an SPI transaction
- Implementation: Pulls CS (Chip Select) pin HIGH to disable the display chip
- Usage:
GPIO_PIN_SET
sets the pin HIGH (inactive)
In main function, link the display to the defined functions as follows:
u8g2_Setup_sh1106_128x64_noname_f(&myDisplay, U8G2_R0, u8x8_spi, u8x8_gpio_and_delay);
- Purpose: Sets up the display driver for a specific OLED model
- Display: SH1106 controller, 128×64 resolution
- Variant:
noname_f
– typically refers to a common generic display module
Parameters:
1. &myDisplay
- Type:
u8g2_t
structure pointer - Purpose: This is the main display object that will store all display state, buffer, and configuration information
2. U8G2_R0
- Purpose: Sets the display rotation/orientation
- Options:
U8G2_R0
: No rotation (0°)U8G2_R1
: 90° rotationU8G2_R2
: 180° rotationU8G2_R3
: 270° rotationU8G2_MIRROR
: Flipped horizontally
3. u8x8_spi
- Purpose: Pointer to your SPI communication function
- Role: This is the function that handles actual data transmission over SPI (the one you showed earlier)
4. u8x8_gpio_and_delay
- Purpose: Pointer to your GPIO and delay function
- Role: This function handles pin control (CS, DC) and timing delays
Next, initialize the LCD:
u8g2_InitDisplay(&myDisplay); // send init sequence to the display, display is in sleep mode after this,
Then, wake up the display:
u8g2_SetPowerSave(&myDisplay, 0); // wake up display
Next, draw some text and shape as follows:
u8g2_ClearDisplay(&myDisplay); u8g2_SetFont(&myDisplay, u8g2_font_ncenB14_tr); u8g2_DrawStr(&myDisplay, 0,15,"Hello world"); u8g2_DrawCircle(&myDisplay, 60, 30, 10, U8G2_DRAW_ALL); u8g2_SendBuffer(&myDisplay);
Thats all for the firmware. Save the project and run it on your MCU as follows:

4. Results:
You should see the following on the display:

We have successfully made it work with STM32 and display text and shape.
Happy coding 😉
Add Comment