hack4electronics.com

How to Connect OLED Display to STM32 Development board (NUCLEO-F303RE) Using Arduino IDE

Integrating microcontrollers with OLED displays is a key requirement in many embedded systems projects. This guide provides a comprehensive overview of how to connect a 0.96-inch SSD1306 I2C OLED display to an STM32 microcontroller ( NUCLEO-F303RE STM32 Development Board ) using Arduino IDE. By the end of this tutorial, you’ll be equipped with the knowledge to create interactive projects leveraging this setup.

What is an OLED Display, and Why Use It?

OLED (Organic Light Emitting Diode) display is a flat, thin display technology that emits light when an electric current flows through organic materials. Unlike LCDs, OLEDs don’t require backlighting, resulting in sharper contrasts, faster refresh rates, and better energy efficiency.

Advantages of OLED Displays:

  1. High contrast ratio.
  2. Wide viewing angles.
  3. Thin and lightweight design.
  4. Energy-efficient for displaying black pixels.

Disadvantages of OLED Displays:

  1. Potential for burn-in over time.
  2. Shorter lifespan compared to traditional LEDs.
  3. Higher cost for larger screen sizes.

Features of the 0.96 Inch I2C 4-Pin OLED Display Module

The 0.96-inch OLED display is a monochrome screen that features a resolution of 128×64 pixels. It utilizes the SSD1306 driver IC and communicates via the I2C protocol, making it easy to connect to microcontrollers like the STM32. 

Key features include:

  • Size: 0.96 inches
  • Resolution: 128×64 pixels
  • Interface: I2C (also known as IIC)
  • Operating Voltage: 3.3V to 5V
  • Display Color: White

Installing Drivers in Arduino IDE

Before programming, ensure that your Arduino IDE is set up correctly with the necessary libraries for the SSD1306 OLED display: To control the OLED display with your STM32, you need to install two libraries in the Arduino IDE:

  1. Adafruit SSD1306 Library
  2. Adafruit GFX Library

Follow these steps to install them:

  • Open Arduino IDE.
  • Navigate to Sketch > Include Library > Manage Libraries.
  • Search for “SSD1306” and install the Adafruit SSD1306 library.
  • Search for “GFX” and install the Adafruit GFX library.

Overview of the NUCLEO-F303RE STM32 Development Board

The Nucleo-F303RE board is based on the ARM Cortex-M4 microcontroller from STMicroelectronics. It supports various interfaces including I2C, making it suitable for connecting to the OLED display. 

Key specifications include:

  • Microcontroller: STM32F303RET6
  • Clock Speed: Up to 72 MHz
  • Flash Memory: 512 KB
  • SRAM: 64 KB + 16 KB
  • I/O Pins: Compatible with Arduino Uno V3 connectors

Connection Diagram Using NUCLEO-F303RE with OLED

Connecting the OLED display to the Nucleo-F303RE involves linking four pins:

OLED PinFunctionNucleo Pin
VCCPower3.3V
GNDGroundGND
SCLClockPB8
SDADataPB9

Ensure that these connections are secure to avoid communication errors.

Programming STM32 using Arduino IDE

Once connected, you can program the OLED display using Arduino IDE. Below is a sample code snippet that initializes the display and shows functions :

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
// The pins for I2C are defined by the Wire-library. 
// On an arduino UNO:       A4(SDA), A5(SCL)
// On an arduino MEGA 2560: 20(SDA), 21(SCL)
// On an arduino LEONARDO:   2(SDA),  3(SCL), ...
#define OLED_RESET     -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

#define NUMFLAKES     10 // Number of snowflakes in the animation example

#define LOGO_HEIGHT   16
#define LOGO_WIDTH    16
static const unsigned char PROGMEM logo_bmp[] =
{ 0b00000000, 0b11000000,
  0b00000001, 0b11000000,
  0b00000001, 0b11000000,
  0b00000011, 0b11100000,
  0b11110011, 0b11100000,
  0b11111110, 0b11111000,
  0b01111110, 0b11111111,
  0b00110011, 0b10011111,
  0b00011111, 0b11111100,
  0b00001101, 0b01110000,
  0b00011011, 0b10100000,
  0b00111111, 0b11100000,
  0b00111111, 0b11110000,
  0b01111100, 0b11110000,
  0b01110000, 0b01110000,
  0b00000000, 0b00110000 };

void setup() {
  Wire.setSDA(PB9);
  Wire.setSCL(PB8);
  Serial.begin(115200);

  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }

  // Show initial display buffer contents on the screen --
  // the library initializes this with an Adafruit splash screen.
  display.display();
  delay(2000); // Pause for 2 seconds

  // Clear the buffer
  display.clearDisplay();

  // Draw a single pixel in white
  display.drawPixel(10, 10, SSD1306_WHITE);

  // Show the display buffer on the screen. You MUST call display() after
  // drawing commands to make them visible on screen!
  display.display();
  delay(2000);
  // display.display() is NOT necessary after every single drawing command,
  // unless that's what you want...rather, you can batch up a bunch of
  // drawing operations and then update the screen all at once by calling
  // display.display(). These examples demonstrate both approaches...

  testdrawline();      // Draw many lines

  testdrawrect();      // Draw rectangles (outlines)

  testfillrect();      // Draw rectangles (filled)

  testdrawcircle();    // Draw circles (outlines)

  testfillcircle();    // Draw circles (filled)

  testdrawroundrect(); // Draw rounded rectangles (outlines)

  testfillroundrect(); // Draw rounded rectangles (filled)

  testdrawtriangle();  // Draw triangles (outlines)

  testfilltriangle();  // Draw triangles (filled)

  testdrawchar();      // Draw characters of the default font

  testdrawstyles();    // Draw 'stylized' characters

  testscrolltext();    // Draw scrolling text

  testdrawbitmap();    // Draw a small bitmap image

  // Invert and restore display, pausing in-between
  display.invertDisplay(true);
  delay(1000);
  display.invertDisplay(false);
  delay(1000);

  testanimate(logo_bmp, LOGO_WIDTH, LOGO_HEIGHT); // Animate bitmaps
}

void loop() {
}

void testdrawline() {
  int16_t i;

  display.clearDisplay(); // Clear display buffer

  for(i=0; i<display.width(); i+=4) {
    display.drawLine(0, 0, i, display.height()-1, SSD1306_WHITE);
    display.display(); // Update screen with each newly-drawn line
    delay(1);
  }
  for(i=0; i<display.height(); i+=4) {
    display.drawLine(0, 0, display.width()-1, i, SSD1306_WHITE);
    display.display();
    delay(1);
  }
  delay(250);

  display.clearDisplay();

  for(i=0; i<display.width(); i+=4) {
    display.drawLine(0, display.height()-1, i, 0, SSD1306_WHITE);
    display.display();
    delay(1);
  }
  for(i=display.height()-1; i>=0; i-=4) {
    display.drawLine(0, display.height()-1, display.width()-1, i, SSD1306_WHITE);
    display.display();
    delay(1);
  }
  delay(250);

  display.clearDisplay();

  for(i=display.width()-1; i>=0; i-=4) {
    display.drawLine(display.width()-1, display.height()-1, i, 0, SSD1306_WHITE);
    display.display();
    delay(1);
  }
  for(i=display.height()-1; i>=0; i-=4) {
    display.drawLine(display.width()-1, display.height()-1, 0, i, SSD1306_WHITE);
    display.display();
    delay(1);
  }
  delay(250);

  display.clearDisplay();

  for(i=0; i<display.height(); i+=4) {
    display.drawLine(display.width()-1, 0, 0, i, SSD1306_WHITE);
    display.display();
    delay(1);
  }
  for(i=0; i<display.width(); i+=4) {
    display.drawLine(display.width()-1, 0, i, display.height()-1, SSD1306_WHITE);
    display.display();
    delay(1);
  }

  delay(2000); // Pause for 2 seconds
}

void testdrawrect(void) {
  display.clearDisplay();

  for(int16_t i=0; i<display.height()/2; i+=2) {
    display.drawRect(i, i, display.width()-2*i, display.height()-2*i, SSD1306_WHITE);
    display.display(); // Update screen with each newly-drawn rectangle
    delay(1);
  }

  delay(2000);
}

void testfillrect(void) {
  display.clearDisplay();

  for(int16_t i=0; i<display.height()/2; i+=3) {
    // The INVERSE color is used so rectangles alternate white/black
    display.fillRect(i, i, display.width()-i*2, display.height()-i*2, SSD1306_INVERSE);
    display.display(); // Update screen with each newly-drawn rectangle
    delay(1);
  }

  delay(2000);
}

void testdrawcircle(void) {
  display.clearDisplay();

  for(int16_t i=0; i<max(display.width(),display.height())/2; i+=2) {
    display.drawCircle(display.width()/2, display.height()/2, i, SSD1306_WHITE);
    display.display();
    delay(1);
  }

  delay(2000);
}

void testfillcircle(void) {
  display.clearDisplay();

  for(int16_t i=max(display.width(),display.height())/2; i>0; i-=3) {
    // The INVERSE color is used so circles alternate white/black
    display.fillCircle(display.width() / 2, display.height() / 2, i, SSD1306_INVERSE);
    display.display(); // Update screen with each newly-drawn circle
    delay(1);
  }

  delay(2000);
}

void testdrawroundrect(void) {
  display.clearDisplay();

  for(int16_t i=0; i<display.height()/2-2; i+=2) {
    display.drawRoundRect(i, i, display.width()-2*i, display.height()-2*i,
      display.height()/4, SSD1306_WHITE);
    display.display();
    delay(1);
  }

  delay(2000);
}

void testfillroundrect(void) {
  display.clearDisplay();

  for(int16_t i=0; i<display.height()/2-2; i+=2) {
    // The INVERSE color is used so round-rects alternate white/black
    display.fillRoundRect(i, i, display.width()-2*i, display.height()-2*i,
      display.height()/4, SSD1306_INVERSE);
    display.display();
    delay(1);
  }

  delay(2000);
}

void testdrawtriangle(void) {
  display.clearDisplay();

  for(int16_t i=0; i<max(display.width(),display.height())/2; i+=5) {
    display.drawTriangle(
      display.width()/2  , display.height()/2-i,
      display.width()/2-i, display.height()/2+i,
      display.width()/2+i, display.height()/2+i, SSD1306_WHITE);
    display.display();
    delay(1);
  }

  delay(2000);
}

void testfilltriangle(void) {
  display.clearDisplay();

  for(int16_t i=max(display.width(),display.height())/2; i>0; i-=5) {
    // The INVERSE color is used so triangles alternate white/black
    display.fillTriangle(
      display.width()/2  , display.height()/2-i,
      display.width()/2-i, display.height()/2+i,
      display.width()/2+i, display.height()/2+i, SSD1306_INVERSE);
    display.display();
    delay(1);
  }

  delay(2000);
}

void testdrawchar(void) {
  display.clearDisplay();

  display.setTextSize(1);      // Normal 1:1 pixel scale
  display.setTextColor(SSD1306_WHITE); // Draw white text
  display.setCursor(0, 0);     // Start at top-left corner
  display.cp437(true);         // Use full 256 char 'Code Page 437' font

  // Not all the characters will fit on the display. This is normal.
  // Library will draw what it can and the rest will be clipped.
  for(int16_t i=0; i<256; i++) {
    if(i == '\n') display.write(' ');
    else          display.write(i);
  }

  display.display();
  delay(2000);
}

void testdrawstyles(void) {
  display.clearDisplay();

  display.setTextSize(1);             // Normal 1:1 pixel scale
  display.setTextColor(SSD1306_WHITE);        // Draw white text
  display.setCursor(0,0);             // Start at top-left corner
  display.println(F("Hello, world!"));

  display.setTextColor(SSD1306_BLACK, SSD1306_WHITE); // Draw 'inverse' text
  display.println(3.141592);

  display.setTextSize(2);             // Draw 2X-scale text
  display.setTextColor(SSD1306_WHITE);
  display.print(F("0x")); display.println(0xDEADBEEF, HEX);

  display.display();
  delay(2000);
}

void testscrolltext(void) {
  display.clearDisplay();

  display.setTextSize(2); // Draw 2X-scale text
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(10, 0);
  display.println(F("scroll"));
  display.display();      // Show initial text
  delay(100);

  // Scroll in various directions, pausing in-between:
  display.startscrollright(0x00, 0x0F);
  delay(2000);
  display.stopscroll();
  delay(1000);
  display.startscrollleft(0x00, 0x0F);
  delay(2000);
  display.stopscroll();
  delay(1000);
  display.startscrolldiagright(0x00, 0x07);
  delay(2000);
  display.startscrolldiagleft(0x00, 0x07);
  delay(2000);
  display.stopscroll();
  delay(1000);
}

void testdrawbitmap(void) {
  display.clearDisplay();

  display.drawBitmap(
    (display.width()  - LOGO_WIDTH ) / 2,
    (display.height() - LOGO_HEIGHT) / 2,
    logo_bmp, LOGO_WIDTH, LOGO_HEIGHT, 1);
  display.display();
  delay(1000);
}

#define XPOS   0 // Indexes into the 'icons' array in function below
#define YPOS   1
#define DELTAY 2

void testanimate(const uint8_t *bitmap, uint8_t w, uint8_t h) {
  int8_t f, icons[NUMFLAKES][3];

  // Initialize 'snowflake' positions
  for(f=0; f< NUMFLAKES; f++) {
    icons[f][XPOS]   = random(1 - LOGO_WIDTH, display.width());
    icons[f][YPOS]   = -LOGO_HEIGHT;
    icons[f][DELTAY] = random(1, 6);
    Serial.print(F("x: "));
    Serial.print(icons[f][XPOS], DEC);
    Serial.print(F(" y: "));
    Serial.print(icons[f][YPOS], DEC);
    Serial.print(F(" dy: "));
    Serial.println(icons[f][DELTAY], DEC);
  }

  for(;;) { // Loop forever...
    display.clearDisplay(); // Clear the display buffer

    // Draw each snowflake:
    for(f=0; f< NUMFLAKES; f++) {
      display.drawBitmap(icons[f][XPOS], icons[f][YPOS], bitmap, w, h, SSD1306_WHITE);
    }

    display.display(); // Show the display buffer on the screen
    delay(200);        // Pause for 1/10 second

    // Then update coordinates of each flake...
    for(f=0; f< NUMFLAKES; f++) {
      icons[f][YPOS] += icons[f][DELTAY];
      // If snowflake is off the bottom of the screen...
      if (icons[f][YPOS] >= display.height()) {
        // Reinitialize to a random position, just off the top
        icons[f][XPOS]   = random(1 - LOGO_WIDTH, display.width());
        icons[f][YPOS]   = -LOGO_HEIGHT;
        icons[f][DELTAY] = random(1, 6);
      }
    }
  }
}

Detailed Explanation of the Code

Library Inclusions

The code begins by including necessary libraries such as WireAdafruit_GFX, and Adafruit_SSD1306. These libraries handle communication and graphics rendering on the OLED.

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

Defining Display Parameters

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET     -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
  • Screen Dimensions: This OLED display has a resolution of 128×64 pixels, where SCREEN_WIDTH is the width and SCREEN_HEIGHT is the height.
  • Reset Pin: The OLED_RESET value is set to -1 to indicate that the OLED shares the Arduino’s reset line.
  • I²C Address: The default address is 0x3C. If your display has a different address (e.g., 0x3D), you’ll need to modify this value.
  • Adafruit SSD1306 Object: An instance of Adafruit_SSD1306 is created to interact with the display.

Setting Up the OLED Display

void setup() {
  Wire.setSDA(PB9);
  Wire.setSCL(PB8);
  Serial.begin(115200);

  if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;);
  }

  display.display(); // Show Adafruit splash screen
  delay(2000);
  display.clearDisplay(); // Clear display buffer
}
  • I²C Pins: Wire.setSDA and Wire.setSCL specify the I²C pins (SDA and SCL). This is necessary for microcontrollers like STM32 where custom pin assignment is required.
  • Initialization: The display.begin method initializes the display. The parameter SSD1306_SWITCHCAPVCC generates the required display voltage from 3.3V. If initialization fails, the code enters an infinite loop.
  • Splash Screen: After initialization, the library automatically displays a default Adafruit splash screen.
  • Clearing Buffer: display.clearDisplay() clears the display’s buffer to prepare for new graphics.

Drawing a Single Pixel

display.drawPixel(10, 10, SSD1306_WHITE);
display.display();
delay(2000);
  • Pixel Drawing: The function drawPixel(x, y, color) draws a single pixel at coordinates (10, 10) with the color SSD1306_WHITE (white).
  • Update Screen: display.display() updates the OLED with the new drawing.

Drawing Graphics

The following methods demonstrate how to draw shapes and patterns on the OLED. Each operation updates the display buffer, which is then rendered using display.display().

//Drawing Lines
void testdrawline() {
  display.clearDisplay();
  for(int16_t i = 0; i < display.width(); i += 4) {
    display.drawLine(0, 0, i, display.height() - 1, SSD1306_WHITE);
    display.display();
  }
}
  • Purpose: Draws lines originating from the top-left corner (0, 0) and extending to various points along the display’s edges.
  • Loop: Iterates through the display’s width, drawing a line every 4 pixels
//Drawing Rectangles
void testdrawrect() {
  display.clearDisplay();
  for(int16_t i = 0; i < display.height() / 2; i += 2) {
    display.drawRect(i, i, display.width() - 2 * i, display.height() - 2 * i, SSD1306_WHITE);
    display.display();
  }
}
  • Drawing Rectangles: The drawRect function draws rectangles with top-left corner (x, y) and dimensions width and height.
  • Loop: Reduces the size of successive rectangles, creating a nested rectangle effect.

//Drawing Circles
void testdrawcircle() {
  display.clearDisplay();
  for(int16_t i = 0; i < max(display.width(), display.height()) / 2; i += 2) {
    display.drawCircle(display.width() / 2, display.height() / 2, i, SSD1306_WHITE);
    display.display();
  }
}
  • Purpose: Draws concentric circles centered on the display.
  • Dynamic Radius: The radius increases in increments of 2 pixels.
void testscrolltext() {
  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(10, 0);
  display.println(F("scroll"));
  display.display();

  display.startscrollright(0x00, 0x0F);
  delay(2000);
  display.stopscroll();
}
  • Text Rendering: The text “scroll” is displayed with size 2 and color SSD1306_WHITE.
  • Scrolling: The text scrolls to the right using startscrollright(startPage, endPage). Scrolling is stopped using stopscroll().
void testanimate(const uint8_t *bitmap, uint8_t w, uint8_t h) {
  for(int8_t f = 0; f < NUMFLAKES; f++) {
    icons[f][XPOS] = random(1 - LOGO_WIDTH, display.width());
    icons[f][YPOS] = -LOGO_HEIGHT;
    icons[f][DELTAY] = random(1, 6);
  }
  for(;;) {
    display.clearDisplay();
    for(int8_t f = 0; f < NUMFLAKES; f++) {
      display.drawBitmap(icons[f][XPOS], icons[f][YPOS], bitmap, w, h, SSD1306_WHITE);
      icons[f][YPOS] += icons[f][DELTAY];
      if(icons[f][YPOS] >= display.height()) {
        icons[f][YPOS] = -LOGO_HEIGHT;
      }
    }
    display.display();
    delay(200);
  }
}
  • Purpose: Animates snowflakes falling across the screen.Bitmap: Each snowflake is represented using the logo_bmp bitmap.Random Motion: Snowflakes have random positions and speeds, creating a natural falling effect.

This setup allows you to easily modify text and graphics displayed on your OLED screen by changing parameters in your code.

By following this guide, you can successfully connect and program a 0.96-inch SSD1306 OLED display with an STM32 microcontroller using Arduino IDE. This setup is ideal for a wide range of projects, including data loggers, interactive interfaces, and compact displays.

For further exploration, dive deeper into the Adafruit GFX library to create complex graphics or display custom animations.

1 thought on “How to Connect OLED Display to STM32 Development board (NUCLEO-F303RE) Using Arduino IDE

  1. Почивка на Гран Канария: райски отдих, най-добрите места за почивка.
    Гид за плажовете на Гран Канария: изберете идеалното място за слънчева баня.
    Кулинарно пътешествие до Гран Канария: насладете се на вкуса на местната кухня.
    Почивка на Гран Канария: екскурзии за истински пътешественици.
    Спа хотели на Гран Канария: релаксирайте и се наслаждавайте на почивката.
    Семейна почивка на Гран Канария: отличен избор за цялото семейство.
    Семейна почивка в Гран Канария bohemia.bg .

Leave a Reply

Your email address will not be published. Required fields are marked *