Xiao ESP32C3 display on SSD1306 128x64 OLED (I2C & SPI) using U8g2 Library

Xiao ESP32C3 (arduino-esp32 framework) exercise to display 128x64 SSD1306 OLED, both I2C and SPI. Tested on XIAO Expansion boardSSD1315 I2C OLED (SSD1306 compatible) and SSD1306 SPI OLED.


U8g2 Library is used to drive the OLEDs, make sure it's installed in Arduino IDE.

Connection
for SPI interface:
OLED SPI	Xiao ESP32C3
GND		GND
VCC		3V3
SCL		GPIO8
SDA		GPIO10
RST		GPIO2
D/C		GPIO3

for I2C interface:
OLED I2C	Xiao ESP32C3
GND		GND
VCC		3V3
SCL		GPIO7
SDA		GPIO6

Exercise Code:

XiaoESP32C3_Serial_Terminal.ino
Accept user input from Serial Monitor, and display on OLED as a terminal (U8X8LOG).
/*
 * Read from Serial and display on 
 * XIAO Expansion board I2C SSD1306 OLED (128x64)
 * using U8g2 library.
 * In this exercise, the OLED act as a terminal (U8X8LOG).
*/

#include <Arduino.h>
#include <U8x8lib.h>

#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif

// U8x8 Contructor
U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8(/* reset=*/ U8X8_PIN_NONE); 	      

// setup the terminal (U8X8LOG) and connect to u8g2 for automatic refresh of the display
// The size (width * height) depends on the display 

#define U8LOG_WIDTH 16
#define U8LOG_HEIGHT 8
uint8_t u8log_buffer[U8LOG_WIDTH*U8LOG_HEIGHT];
U8X8LOG u8x8log;

void setup(void)
{
  Serial.begin(115200);
  u8x8.begin();
  u8x8.setFont(u8x8_font_chroma48medium8_r);
  
  u8x8log.begin(u8x8, U8LOG_WIDTH, U8LOG_HEIGHT, u8log_buffer);
  u8x8log.setRedrawMode(1);		// 0: Update screen with newline, 1: Update screen for every char  

  u8x8log.println("- Xiao ESP32C3 -");
  u8x8log.println("Read from Serial and display on I2C SSD1306 OLED using U8g2 library.");

  Serial.println("\nEnter something and Send");
}


void loop(void) {

  while (Serial.available() > 0) {
    String term_in = Serial.readString();
    Serial.print(term_in);
    u8x8log.print(term_in);
  }
  
  delay(100);
}


XiaoESP32C3_u8x8_GraphicsTest_128x64_SSD1306_I2C_and_SPI.ino
Modified from u8x8 example GraphicsTest, tested on both I2C and SPI OLED.
/*
 * Modified from Exampls > U8g2 > u8x8 > GraphicsTest
 * Run on Xiao ESP32C3 to display on 128x64 SSD1306 (I2C/SPI)
 * 
 */

/*

  GraphicsTest.ino
  
  Some graphics/text output for U8x8 API

  Universal 8bit Graphics Library (https://github.com/olikraus/u8g2/)

  Copyright (c) 2016, olikraus@gmail.com
  All rights reserved.

  Redistribution and use in source and binary forms, with or without modification, 
  are permitted provided that the following conditions are met:

  * Redistributions of source code must retain the above copyright notice, this list 
    of conditions and the following disclaimer.
    
  * Redistributions in binary form must reproduce the above copyright notice, this 
    list of conditions and the following disclaimer in the documentation and/or other 
    materials provided with the distribution.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 
  CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 
  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  

*/
#include <Arduino.h>
#include <U8x8lib.h>

#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif

#define TFTspi_RST  2
#define TFTspi_DC   3

// U8x8 Contructor
// The complete list is available here: https://github.com/olikraus/u8g2/wiki/u8x8setupcpp
//- For SPI SSD1306 -
U8X8_SSD1306_128X64_NONAME_4W_HW_SPI u8x8(/* cs=*/ U8X8_PIN_NONE, /* dc=*/ TFTspi_DC, /* reset=*/ TFTspi_RST);
//- For I2C SSD1306 -
//U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8(/* reset=*/ U8X8_PIN_NONE); 	      


/*
  This example will probably not work with the SSD1606, because of the
  internal buffer swapping
*/

void setup(void)
{
  delay(500);
  Serial.begin(115200);
  delay(500);
  //I2C & SPI pins assigment
  Serial.println("\n- For I2C SSD1306 -");
  Serial.println("I2C pins:");
  Serial.printf("\tSDA: GPIO%d\n", SDA);
  Serial.printf("\tSCL: GPIO%d\n", SCL);

  Serial.println("\n- For SPI SSD1306 -");
  Serial.println("SPI pins:");
  Serial.printf("\tSS  : GPIO%d \t(not used)\n", SS);
  Serial.printf("\tMOSI: GPIO%d\n", MOSI);
  Serial.printf("\tMISO: GPIO%d \t(not used)\n", MISO);
  Serial.printf("\tSCK : GPIO%d\n", SCK);
  Serial.printf("\tRST : GPIO%d\n", TFTspi_RST);
  Serial.printf("\tD/C : GPIO%d\n", TFTspi_DC);
  
  u8x8.begin();
  //u8x8.setFlipMode(1);

}

void pre(void)
{
  u8x8.setFont(u8x8_font_amstrad_cpc_extended_f);    
  u8x8.clear();

  u8x8.inverse();
  u8x8.print(" U8x8 Library ");
  u8x8.setFont(u8x8_font_chroma48medium8_r);  
  u8x8.noInverse();
  u8x8.setCursor(0,1);
}

void draw_bar(uint8_t c, uint8_t is_inverse)
{	
  uint8_t r;
  u8x8.setInverseFont(is_inverse);
  for( r = 0; r < u8x8.getRows(); r++ )
  {
    u8x8.setCursor(c, r);
    u8x8.print(" ");
  }
}

void draw_ascii_row(uint8_t r, int start)
{
  int a;
  uint8_t c;
  for( c = 0; c < u8x8.getCols(); c++ )
  {
    u8x8.setCursor(c,r);
    a = start + c;
    if ( a <= 255 )
      u8x8.write(a);
  }
}

void loop(void)
{
  int i;
  uint8_t c, r, d;
  pre();
  u8x8.print("github.com/");
  u8x8.setCursor(0,2);
  u8x8.print("olikraus/u8g2");
  delay(2000);
  u8x8.setCursor(0,3);
  u8x8.print("Tile size:");
  u8x8.print((int)u8x8.getCols());
  u8x8.print("x");
  u8x8.print((int)u8x8.getRows());
  
  delay(2000);
   
  pre();
  for( i = 19; i > 0; i-- )
  {
    u8x8.setCursor(3,2);
    u8x8.print(i);
    u8x8.print("  ");
    delay(150);
  }
  
  draw_bar(0, 1);
  for( c = 1; c < u8x8.getCols(); c++ )
  {
    draw_bar(c, 1);
    draw_bar(c-1, 0);
    delay(50);
  }
  draw_bar(u8x8.getCols()-1, 0);

  pre();
  u8x8.setFont(u8x8_font_amstrad_cpc_extended_f); 
  for( d = 0; d < 8; d ++ )
  {
    for( r = 1; r < u8x8.getRows(); r++ )
    {
      draw_ascii_row(r, (r-1+d)*u8x8.getCols() + 32);
    }
    delay(400);
  }

  draw_bar(u8x8.getCols()-1, 1);
  for( c = u8x8.getCols()-1; c > 0; c--)
  {
    draw_bar(c-1, 1);
    draw_bar(c, 0);
    delay(50);
  }
  draw_bar(0, 0);

  pre();
  u8x8.drawString(0, 2, "Small");
  u8x8.draw2x2String(0, 5, "Scale Up");
  delay(3000);

  pre();
  u8x8.drawString(0, 2, "Small");
  u8x8.setFont(u8x8_font_px437wyse700b_2x2_r);
  u8x8.drawString(0, 5, "2x2 Font");
  delay(3000);

  pre();
  u8x8.drawString(0, 1, "3x6 Font");
  u8x8.setFont(u8x8_font_inb33_3x6_n);
  for(i = 0; i < 100; i++ )
  {
    u8x8.setCursor(0, 2);
    u8x8.print(i);			// Arduino Print function
    delay(10);
  }
  for(i = 0; i < 100; i++ )
  {
    u8x8.drawString(0, 2, u8x8_u16toa(i, 5));	// U8g2 Build-In functions
    delay(10);		
  }

  pre();
  u8x8.drawString(0, 2, "Weather");
  u8x8.setFont(u8x8_font_open_iconic_weather_4x4);
  for(c = 0; c < 6; c++ )
  {
    u8x8.drawGlyph(0, 4, '@'+c);
    delay(300);
  }
  

  pre();
  u8x8.print("print \\n\n");
  delay(500);
  u8x8.println("println");
  delay(500);
  u8x8.println("done");
  delay(1500);

  pre();
  u8x8.fillDisplay();
  for( r = 0; r < u8x8.getRows(); r++ )
  {
    u8x8.clearLine(r);
    delay(100);
  }
  delay(1000);

}


XiaoESP32C3_u8g2_128x64_SSD1306.ino
U8g2lib exercise to draw something on both OLEDs, compare the duration of sendBuffer() function between SPI and I2C.
/*
 * Run on Xiao ESP32C3 to display on 128x64 SSD1306 (I2C/SPI)
 * U8g2lib exercise
 * Compare the running duration of sendBuffer() function between SPI and I2C
 * 
 */

#include <Arduino.h>
#include <U8g2lib.h>

#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif

#define TFTspi_RST  2
#define TFTspi_DC   3

// U8g2 Contructor (Frame Buffer)

//- For SPI SSD1306 -
U8G2_SSD1306_128X64_NONAME_F_4W_HW_SPI u8g2_spi(U8G2_R0, /* cs=*/ U8X8_PIN_NONE, /* dc=*/ TFTspi_DC, /* reset=*/ TFTspi_RST);

//- For I2C SSD1306 -
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2_i2c(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);

int step_cnt = 0;
int step_x = 2;
int step_y = 1;

int pt0_x = 0;
int pt0_y;
int pt1_x;
int pt1_y;
int pt2_x;
int pt2_y;
int pt3_x;
int pt3_y;

void walkStep(){
  if (step_cnt==0){
    pt0_x = 0;
    pt0_y = 0;
    pt1_x = 127;
    pt1_y = 0;
    pt2_x = 127;
    pt2_y = 63;
    pt3_x = 0;
    pt3_y = 63;
  }else{
    pt0_x = pt0_x + step_x;
    pt1_y = pt1_y + step_y;
    pt2_x = pt2_x - step_x;
    pt3_y = pt3_y - step_y;
  }

  step_cnt++;
  if(step_cnt == 64){
    step_cnt=0;
    u8g2_spi.clearBuffer();
    u8g2_i2c.clearBuffer();
  }
}

void setup(void) {

  delay(500);
  Serial.begin(115200);
  delay(500);
  //I2C & SPI pins assigment

  Serial.println("\n- For I2C SSD1306 -");
  Serial.println("I2C pins:");
  Serial.printf("\tSDA: GPIO%d\n", SDA);
  Serial.printf("\tSCL: GPIO%d\n", SCL);

  Serial.println("\n- For SPI SSD1306 -");
  Serial.println("SPI pins:");
  Serial.printf("\tSS  : GPIO%d \t(not used)\n", SS);
  Serial.printf("\tMOSI: GPIO%d\n", MOSI);
  Serial.printf("\tMISO: GPIO%d \t(not used)\n", MISO);
  Serial.printf("\tSCK : GPIO%d\n", SCK);
  Serial.printf("\tRST : GPIO%d\n", TFTspi_RST);
  Serial.printf("\tD/C : GPIO%d\n", TFTspi_DC);
  
  u8g2_spi.begin();
  u8g2_i2c.begin();
  Serial.println("\n- SPI SSD1306 Display -");
  Serial.printf("width  : %d\n", u8g2_spi.getDisplayWidth());
  Serial.printf("height : %d\n", u8g2_spi.getDisplayHeight());
  Serial.println("\n- I2C SSD1306 Display -");
  Serial.printf("width  : %d\n", u8g2_i2c.getDisplayWidth());
  Serial.printf("height : %d\n", u8g2_i2c.getDisplayHeight());

  Serial.println();
  Serial.println("duration of sendBuffer() micros:\tSPI\tI2C");

  u8g2_spi.clearBuffer();          // clear the internal memory
  u8g2_i2c.clearBuffer();
  u8g2_spi.setFont(u8g2_font_ncenB08_tr); // choose a suitable font
  u8g2_i2c.setFont(u8g2_font_ncenB08_tr);
  u8g2_spi.drawStr(0,10,"Hello World!");  // write something to the internal memory
  u8g2_i2c.drawStr(0,10,"Hello World!");

  u8g2_spi.sendBuffer();
  u8g2_i2c.sendBuffer();

  delay(2000);

}

void drawSomething(){
  u8g2_spi.drawLine(pt0_x, pt0_y, pt1_x, pt1_y);
  u8g2_spi.drawLine(pt1_x, pt1_y, pt2_x, pt2_y);
  u8g2_spi.drawLine(pt2_x, pt2_y, pt3_x, pt3_y);
  u8g2_spi.drawLine(pt3_x, pt3_y, pt0_x, pt0_y);
  
  u8g2_i2c.drawLine(pt0_x, pt0_y, pt1_x, pt1_y);
  u8g2_i2c.drawLine(pt1_x, pt1_y, pt2_x, pt2_y);
  u8g2_i2c.drawLine(pt2_x, pt2_y, pt3_x, pt3_y);
  u8g2_i2c.drawLine(pt3_x, pt3_y, pt0_x, pt0_y);

}

void loop(void) {
  drawSomething();
  walkStep();

  unsigned long start_time_spi = micros();
  u8g2_spi.sendBuffer();					// transfer internal memory to the display
  unsigned long end_time_spi = micros();
  unsigned long start_time_i2c = micros();
  u8g2_i2c.sendBuffer();          // transfer internal memory to the display
  unsigned long end_time_i2c = micros();
  Serial.printf("\t\t\t\t\t%lu\t%lu\n", end_time_spi-start_time_spi, end_time_i2c-start_time_i2c);

  delay(200);  
}




Comments

Popular posts from this blog

MicroPython/ESP32-C3 + 1.8" 128x160 TFT ST7735 SPI, using boochow/MicroPython-ST7735 library.

CameraWebServe: ESP32-S3 (arduino-esp32) + OV5640 camera module