cancel
Showing results for 
Search instead for 
Did you mean: 

Looking for STM32 SPI example for SSD1322-based OLED (NHD-2.7-12864WDW3)

durna
Senior

Hi,

I'm trying to get a few lines of text displayed on an OLED screen using 4-wire SPI on an STM32H755 board, but I haven't succeeded yet.

I've looked into the sample code provided by the manufacturer (which is Arduino-based), but it hasn’t helped much so far.

Has anyone worked with this display or with the SSD1322 controller before?

I’m mainly looking for example code for the STM32 platform.
I’ll be uploading my current progress to my GitHub repo.

 

Thanks in advance!

7 REPLIES 7
AScha.3
Super User

Hi,

you set the SPI mode in Cube ?  correct for ssd1322 ? did you check it with a scope ?

+

There are many libs, just look at another lib, copy it + adapt and try .

maybe try:

https://github.com/MartyMacGyver/OLED_SSD1322/blob/master/Arduino/SSD1322_NHD_256x64_mono_demo/SSD1322_NHD_256x64_mono_demo.ino

or this, for stm32F4 :

https://github.com/wjklimek1/SSD1322_OLED_library

 

 

 

If you feel a post has answered your question, please click "Accept as Solution".

Hi @AScha.3 ,

I've spent a long time trying to get it working, but I still can't achieve a clean and proper image. The display behaves as if it's 256x64, not 128x64 — only the left half shows readable content, while the right side is filled with garbage.

 

In fact, I had to manually offset text by 57 pixels from the left just to make it display properly. Without that, even the left part of the screen would appear distorted. :(

 

Here’s what I’ve tried so far:

  • Reviewed the Arduino example code provided by the display manufacturer.
  • Examined two GitHub repos written for SSD1322, but they both target 256x64 panels.
  • Even tried some AI tools for troubleshooting, but none of the suggestions resolved the issue.

I'm now wondering — maybe someone here has experience using an SSD1322 display with a physical resolution of 128x64, not 256x64?

Could the issue be caused by incorrect column address setup, remap configuration, or GDDRAM write pattern?

I’ll share my code if needed.

/* oled_ssd1322.c */

#include <string.h>
#include <stdio.h>
#include "oled_ssd1322.h"
#include "font6x8.h"

/* If your logo is large, get it as extern */
extern const uint8_t NHD_Logo[];

/* Inline control helpers */
static inline void CS_LOW (void) { HAL_GPIO_WritePin(SSD1322_CS_Port,  SSD1322_CS_Pin,  GPIO_PIN_RESET); }
static inline void CS_HIGH(void) { HAL_GPIO_WritePin(SSD1322_CS_Port,  SSD1322_CS_Pin,  GPIO_PIN_SET);   }
static inline void DC_CMD (void) { HAL_GPIO_WritePin(SSD1322_DC_Port,  SSD1322_DC_Pin,  GPIO_PIN_RESET); }
static inline void DC_DAT (void) { HAL_GPIO_WritePin(SSD1322_DC_Port,  SSD1322_DC_Pin,  GPIO_PIN_SET);   }
static inline void DEBUG_TOGGLE(void) { HAL_GPIO_TogglePin(DEBUG_PIN_PORT, DEBUG_PIN_PIN); }
static inline void DEBUG_HIGH(void) { HAL_GPIO_WritePin(DEBUG_PIN_PORT, DEBUG_PIN_PIN, GPIO_PIN_SET); }
static inline void DEBUG_LOW(void)  { HAL_GPIO_WritePin(DEBUG_PIN_PORT, DEBUG_PIN_PIN, GPIO_PIN_RESET); }

/* Transmit with SPI (retry) */
static HAL_StatusTypeDef ssd1322_spi_tx(const uint8_t *data, uint16_t len)
{
    HAL_StatusTypeDef ret;
    for (int attempt = 0; attempt < SSD1322_SPI_RETRY_MAX; ++attempt) {
        ret = HAL_SPI_Transmit(&hspi2, (uint8_t*)data, len, 100);
        if (ret == HAL_OK) return HAL_OK;
        HAL_Delay(1);
    }
    return ret;
}


void SSD1322_EntireDisplayOn(void) {
    SSD1322_SendCommand(0xA5); // Entire display ON (all pixels white)
}

void SSD1322_EntireDisplayOff(void) {
    SSD1322_SendCommand(0xA4); // Entire display OFF (normal)
}


/* Send command */
void SSD1322_SendCommand(uint8_t cmd)
{
    DC_CMD();
    CS_LOW();
    ssd1322_spi_tx(&cmd, 1);
    CS_HIGH();
}

/* Command + data */
void SSD1322_SendCommandWithData(uint8_t cmd, const uint8_t *data, uint16_t len)
{
    DC_CMD();
    CS_LOW();
    ssd1322_spi_tx(&cmd, 1);
    if (len) {
        DC_DAT();
        ssd1322_spi_tx(data, len);
    }
    CS_HIGH();
}

/* Reset pulse */
static void SSD1322_Reset(void)
{
    HAL_GPIO_WritePin(SSD1322_RST_Port, SSD1322_RST_Pin, GPIO_PIN_RESET);
    HAL_Delay(150);
    HAL_GPIO_WritePin(SSD1322_RST_Port, SSD1322_RST_Pin, GPIO_PIN_SET);
    HAL_Delay(150);
}

/* Column/row settings */
void SSD1322_SetColumn(uint8_t a, uint8_t b)
{
    SSD1322_SendCommandWithData(0x15, (uint8_t[]){a, b}, 2);
}

void SSD1322_SetRow(uint8_t a, uint8_t b)
{
    SSD1322_SendCommandWithData(0x75, (uint8_t[]){a, b}, 2);
}

/* Display ON/OFF */
void SSD1322_DisplayOnOff(bool on)
{
    if (on) SSD1322_SendCommand(0xAF);
    else    SSD1322_SendCommand(0xAE);
}

/* Initialization sequence */
void SSD1322_Init(void)
{
    SSD1322_Reset();

    SSD1322_DisplayOnOff(false);

    SSD1322_SendCommandWithData(0xFD, (uint8_t[]){0x12},1);     // Command Lock
    SSD1322_SendCommandWithData(0xB3, (uint8_t[]){0x91},1);     // Display Clock
    SSD1322_SendCommandWithData(0xCA, (uint8_t[]){0x3F},1);     // MUX Ratio
    SSD1322_SendCommandWithData(0xA2, (uint8_t[]){0x00},1);     // Display Offset
    SSD1322_SendCommandWithData(0xAB, (uint8_t[]){0x01},1);     // Function Select (internal VDD)
    SSD1322_SendCommandWithData(0xA1, (uint8_t[]){0x00},1);     // Start Line

    SSD1322_SendCommandWithData(0xA0, (uint8_t[]){0x16,0x11},2); // Remap

    SSD1322_SendCommandWithData(0xC7, (uint8_t[]){0x0F},1);     // Master Contrast
    SSD1322_SendCommandWithData(0xC1, (uint8_t[]){0x9F},1);     // Contrast

    SSD1322_SendCommandWithData(0xB1, (uint8_t[]){0x72},1);     // Phase Length
    SSD1322_SendCommandWithData(0xBB, (uint8_t[]){0x1F},1);     // Precharge Voltage
    SSD1322_SendCommandWithData(0xB4, (uint8_t[]){0xA0,0xFD},2);// Display Enhancement A (VSL)
    SSD1322_SendCommandWithData(0xBE, (uint8_t[]){0x04},1);     // VCOMH

    SSD1322_SendCommand(0xA6);                   // Normal Display
    SSD1322_SendCommand(0xA9);                   // Exit Partial
    SSD1322_SendCommandWithData(0xD1, (uint8_t[]){0xA2,0x20},2); // Display Enhancement B
    SSD1322_SendCommandWithData(0xB5, (uint8_t[]){0x00},1);     // GPIO
    SSD1322_SendCommand(0xB9);                   // Default Grayscale
    SSD1322_SendCommandWithData(0xB6, (uint8_t[]){0x08},1);     // 2nd Precharge

    SSD1322_DisplayOnOff(true);
}

/* Framebuffer: 2-bit grayscale (0..3), 64 rows x 128 columns */
 uint8_t framebuf[64][128];

/* 2-bit -> byte mapping */
static inline uint8_t gray2byte(uint8_t g) {
    switch (g & 0x03) {
        case 0: return 0x00;
        case 1: return 0x55;
        case 2: return 0xAA;
        case 3: return 0xFF;
        default: return 0x00;
    }
}

/* Writes framebuffer to GDDRAM */
void SSD1322_RefreshFromFramebuffer(void)
{
    SSD1322_SetColumn(0x00, 0x7F);
    SSD1322_SetRow(0x00, 0x3F);
    SSD1322_SendCommand(0x5C); // Write RAM

    uint8_t linebuf[256];
    for (int row = 0; row < 64; row++) {
        for (int col = 0; col < 128; col++) {
            uint8_t b = gray2byte(framebuf[row][col]);
//            linebuf[col * 2 + 0] = b;
//            linebuf[col * 2 + 1] = b;
            linebuf[col] = b;
        }
        DC_DAT();
        CS_LOW();
        ssd1322_spi_tx(linebuf, sizeof(linebuf));
        CS_HIGH();
    }
}

void DrawText(const char *s, int y)
{
    int len = strlen(s);
    int x0 = 57;        // leaves 57 pixels of space from the left

    for (int i = 0; i < len; i++) {
        SSD1322_DrawChar(x0 + i * 6, y, s[i]);
    }
}


/* Simple character drawing (6x8) */
void SSD1322_DrawChar(int x, int y, char c)
{
    if (c < 32 || c > 127) return;
    const uint8_t *glyph = Font6x8[c - 32];

    for (int col = 0; col < 6; col++) {
        int fx = x + col;
        if (fx < 0 || fx >= 128) continue;
        uint8_t column_bits = glyph[col];
        for (int row = 0; row < 8; row++) {
            int fy = y + row;
            if (fy < 0 || fy >= 64) continue;
            uint8_t pixel_on = (column_bits >> row) & 0x01;
            framebuf[fy][fx] = pixel_on ? 3 : 0;
        }
    }
}


/* Clears the display via framebuffer */
void SSD1322_Clear(void)
{
    for (int r=0; r<64; r++)
        for (int c=0; c<128; c++)
            framebuf[r][c] = 0;
    SSD1322_RefreshFromFramebuffer();
}


/* Centered string (single line) */
void SSD1322_DrawStringCentered(const char *s)
{
    int len = 0;
    for (const char *p = s; *p; ++p) len++;
    int total_width = len * 6 + (len - 1) * 1;
    int x0 = (128 - total_width) / 2;
    int y0 = (64 - 8) / 2;

    /* clear */
    for (int r=0;r<64;r++)
        for (int c=0;c<128;c++)
            framebuf[r][c]=0;

    for (int i = 0; i < len; i++) {
        int x = x0 + i * (6 + 1);
        SSD1322_DrawChar(x, y0, s[i]);
    }
    SSD1322_RefreshFromFramebuffer();
}

/* Draws a scrolling string with offset (horizontal scroll) */
void SSD1322_DrawStringAtOffset(const char *s, int y, int offset)
{
    // Clear only that line
    for (int row = y; row < y + 8; row++)
        for (int col = 0; col < 128; col++)
            if (row >= 0 && row < 64)
                framebuf[row][col] = 0;

    int x = -offset;
    for (int i = 0; s[i]; i++) {
        SSD1322_DrawChar(x, y, s[i]);
        x += 7; // 6px + 1 space
    }
}

/* Scroll line structure and management */
void ScrollLine_Init(scrolling_line_t *line, const char *fmt, int y)
{
    snprintf(line->text, sizeof(line->text), fmt);
    int len = 0;
    for (const char *p = line->text; *p; ++p) len++;
    line->text_pixel_width = len * 7 - 1;
    line->offset = 0;
    line->direction = 1;
    line->y = y;
}

void ScrollLine_Tick(scrolling_line_t *line)
{
    if (line->text_pixel_width <= 128) {
        int pad = (128 - line->text_pixel_width) / 2;
        SSD1322_DrawStringAtOffset(line->text, line->y, -pad);
    } else {
        SSD1322_DrawStringAtOffset(line->text, line->y, line->offset);
        line->offset += line->direction;
        if (line->offset + 128 >= line->text_pixel_width) line->direction = -1;
        if (line->offset <= 0) line->direction = 1;
    }
}

/* Helper to clear the framebuffer */
void SSD1322_ClearFramebuffer(void)
{
    // Since static framebuf is defined in this file, we can access it directly
    for (int r = 0; r < 64; r++) {
        for (int c = 0; c < 128; c++) {
            framebuf[r][c] = 0;
        }
    }
}

// Set a single pixel
void SSD1322_SetPixel(int x, int y, uint8_t gray)
{
    if (x < 0 || x >= 128 || y < 0 || y >= 64) return;
    framebuf[y][x] = gray & 0x03; // 0..3
}

error_oled.jpeg

1. GOOD - so far, some success.

2. >issue be caused by incorrect column address setup, remap configuration

Yes, this looks typical for wrong address/pixel count/offset etc. , or a missing/puzzled data line.

So : is manufact.exaple correct ? there should be the matching values for the init-values.

 

Size of screen is set here, so check values for display size here:

/* Column/row settings */
void SSD1322_SetColumn(uint8_t a, uint8_t b)
{
    SSD1322_SendCommandWithData(0x15, (uint8_t[]){a, b}, 2);
}

void SSD1322_SetRow(uint8_t a, uint8_t b)
{
    SSD1322_SendCommandWithData(0x75, (uint8_t[]){a, b}, 2);
}

you dont show your code...so i only can guess.

 

If you feel a post has answered your question, please click "Accept as Solution".

Strangely, when I use the values shared by the manufacturer for the line, the image becomes more distorted. It's a very strange situation.

 

Below, I share the sample code provided by the manufacturer for Arduino.

 

 

/*
/ Program for writing to NHD-2.7-12864 OLED with SSD1322 controller with 4-wire Serial Interface
/ This code is written for the Arduino Due using Serial Interface
/
/ Newhaven Display invests time and resources providing this open source code,
/ Please support Newhaven Display by purchasing products from Newhaven Display!

* Copyright (c) 2025, Newhaven Display International
*
* This code is provided as an example only and without any warranty by Newhaven Display. 
* Newhaven Display accepts no responsibility for any issues resulting from its use. 
* The developer of the final application incorporating any parts of this 
* sample code is responsible for ensuring its safe and correct operation
* and for any consequences resulting from its use.
* See the GNU General Public License for more details. 
* 
* Use Horizontal Orientation when converting BMP to hex code to display custom image using LCD assistant.  
*/
//---------------------------------------------------------

#define OLED_DC    49    //Register Select signal
#define OLED_RESET 48    //Reset signal
#define OLED_CS    47    //Chip select signal
#define OLED_CLK   52    //Serial clock signal 
#define OLED_MOSI  51    //Serial data signal 

/****************************************************
*               Hex Table for Image Pic             *
*****************************************************/

unsigned char NHD_Logo [] = {     
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0xFF, 0xFF, 0xD9, 0x83, 0xC6, 0x31, 0x98, 0xC1, 0x82, 0x0C, 0x3C, 0x63, 0x00, 0x00, 0x00, 0x00, 0xFF,
  0xFF, 0xD9, 0x87, 0xC6, 0x33, 0x98, 0xC1, 0x83, 0x0C, 0x7C, 0x73, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x1D, 0x86,
  0x03, 0x33, 0x18, 0xC3, 0xC3, 0x18, 0xC0, 0x7B, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x7F, 0xDD, 0x8E, 0xE3, 0x7B, 0x1F, 
  0xC3, 0x61, 0xB8, 0xFC, 0x7B, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xDF, 0x8F, 0xC1, 0xDF, 0x1F, 0xC6, 0x61, 0xB1, 
  0xFC, 0x6F, 0x00, 0x00, 0x00, 0x3C, 0x01, 0xC0, 0x1B, 0x84, 0x01, 0xCE, 0x18, 0xC7, 0xE0, 0xF0, 0xC0, 0x67, 0x00,
  0x00, 0x00, 0x7E, 0x07, 0x9F, 0xDB, 0x87, 0xE1, 0xCE, 0x18, 0xCE, 0x70, 0xE0, 0x7C, 0x67, 0x00, 0x00, 0x00, 0x7F,
  0xFE, 0x3F, 0xD9, 0x83, 0xE0, 0xCC, 0x18, 0xCC, 0x38, 0x60, 0x3C, 0x63, 0x00, 0x00, 0x00, 0xFF, 0xFC, 0xE0, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x01, 0xC0, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x3C, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x07, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x1F, 0x80, 0x0E, 0x00, 0x3F, 0x0C, 0x3F, 0x8F, 0xC3, 0x00, 0xC3, 0x18, 0x00, 0x00, 0x00, 0x00, 0x3F,
  0xFF, 0xFC, 0x00, 0x3F, 0x8C, 0x3F, 0x8C, 0xE3, 0x01, 0xC3, 0x98, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00,
  0x31, 0xCC, 0x30, 0x0C, 0x63, 0x01, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x80, 0x00, 0x00, 0x30, 0xCC, 0x3F, 
  0x0E, 0xC3, 0x03, 0x20, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x30, 0xCC, 0x03, 0x8F, 0xC3, 0x03, 
  0xF0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x8C, 0x3F, 0x8C, 0x03, 0x07, 0xF0, 0x60, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x8C, 0x3F, 0x0C, 0x03, 0xE6, 0x18, 0x60, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x83, 0x41, 0xE0, 0x70, 0x78, 0x24, 0x0C, 
  0x0F, 0x06, 0x0F, 0x06, 0x81, 0x80, 0x80, 0x00, 0x01, 0x83, 0xC0, 0xC0, 0xE0, 0x58, 0x34, 0x0C, 0x06, 0x06, 0x09,
  0x07, 0x81, 0x80, 0x80, 0x00, 0x01, 0x82, 0xC0, 0xC0, 0xC0, 0x70, 0x3C, 0x1E, 0x06, 0x06, 0x09, 0x05, 0x83, 0xC0, 
  0x80, 0x00, 0x01, 0x82, 0x40, 0xC0, 0x70, 0x58, 0x2C, 0x12, 0x06, 0x06, 0x0F, 0x04, 0x82, 0x40, 0xE0, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

/****************************************************
*                 Function Commands                  *
*****************************************************/

void data(unsigned char d) // Data Output Serial Interface
{
  digitalWrite(OLED_CS, LOW); 
  digitalWrite(OLED_DC, HIGH); 

  for (unsigned int n = 0; n < 8; n++) {
    digitalWrite(OLED_MOSI, (d & 0x80) ? HIGH : LOW); // Set MOSI based on the MSB
    d <<= 1;                                          // Shift data left
    digitalWrite(OLED_CLK, LOW);
    digitalWrite(OLED_CLK, HIGH);                     // Pulse the clock
  }

  digitalWrite(OLED_CS, HIGH);
}


void command(unsigned char d) // Command Output Serial Interface
{
  digitalWrite(OLED_CS, LOW); 
  digitalWrite(OLED_DC, LOW); 

  for (unsigned int n = 0; n < 8; n++) {
    digitalWrite(OLED_MOSI, (d & 0x80) ? HIGH : LOW);  // Set MOSI based on the MSB
    d <<= 1;  // Shift the data left by 1 bit
    digitalWrite(OLED_CLK, LOW);
    digitalWrite(OLED_CLK, HIGH);                     // Pulse the clock
  }

  digitalWrite(OLED_CS, HIGH);
}

/****************************************************
*                 Display Commands                   *
*****************************************************/

void Set_Column_Address_12864(unsigned char a, unsigned char b)
{
  command(0x15);  // Set Column Address
  data(a);        //   Default => 0x00
  data(b);        //   Default => 0x77
}
//--------------------------------------------------------------------------

void Set_Write_RAM_12864()
{
  command(0x5C);  // Enable MCU to Write DATA RAM
}
//--------------------------------------------------------------------------

void Set_Row_Address_12864(unsigned char a, unsigned char b)
{
  command(0x75);  // Set Row Start and End Address
  data(a);        // Default => 0x00
  data(b);        // Default => 0x7F
}
//--------------------------------------------------------------------------

void Set_Remap_12864(unsigned char a, unsigned char b)
{
  command(0xA0);  // Set Remap
  data(a);        // Default => 0x00
  data(b);        // Default => 0x00
}
//--------------------------------------------------------------------------

void Set_Display_Start_Line_12864(unsigned char a)
{
  command(0xA1);  // Set Display RAM Display Start Line
  data(a);        // Default => 0x00
}
//--------------------------------------------------------------------------

void Set_Display_Offset_12864(unsigned char a)
{
  command(0xA2);  // Set Verticle Shift
  data(a);        // Default => 0x00
}
//--------------------------------------------------------------------------

void Display_Mode_12864(unsigned char a)
{
  command(a);     // 0xA4 => Entire Display OFF 
                  // 0xA5 => Entire Display ON, all pixels Grayscale level 15
                  // 0xA6 => Normal Display (Default)
                  // 0xA7 => Inverse Display
}
//--------------------------------------------------------------------------

void Enable_Partial_Display_12864(unsigned char a, unsigned char b)
{
  command(0xA8);  // Turns ON partial mode 
  data(a);        // Address of start row
  data(b);        // Address of end row. 
}
//--------------------------------------------------------------------------

void Exit_Partial_Display_12864()
{
  command(0xA9);  // Exit Partial Display Mode
}
//--------------------------------------------------------------------------

void Function_Selection_12864(unsigned char a)
{
  command(0xAB);  // Function Selection
  data(a);        // Default => 0x01
}
//--------------------------------------------------------------------------

void Set_Sleep_Mode_12864(unsigned char a)
{
  command(a);     // 0xAE => Sleep Mode ON
                  // 0xAF => Sleep Mode OFF
}
//--------------------------------------------------------------------------

void Set_Phase_Length_12864(unsigned char a)
{
  command(0xB1);  // Set Phase Length
  data(a);        // Default => 0x97
}
//--------------------------------------------------------------------------

void Set_Display_Clock__Oscillator_Frequency_12864(unsigned char a)
{
  command(0xB3);  // Set Osc Frequency
  data(a);        // 
}
//--------------------------------------------------------------------------

void Enable_External_VSL(unsigned char a, unsigned char b)
{
  command(0xB4);  // Enable External VSL
  data(a);        // 
  data(b);        //  
}
//--------------------------------------------------------------------------

void Set_GPIO_12864(unsigned char a)
{
  command(0xB5);  // Set GPIO
  data(a);        // 
}
//--------------------------------------------------------------------------

void Set_Second_Precharge_Period_12864(unsigned char a)
{
  command(0xB6);  // Set Second Precharge Period
  data(a);        // 
}
//--------------------------------------------------------------------------

void Default_Grayscale_Command_12864()
{
  command(0xB9);  // Sets Default Grayscale
}
//--------------------------------------------------------------------------

void Set_Precharge_Voltage_12864(unsigned char a)
{
  command(0xBB);  // Set Precharge Voltage Level
  data(a);        // Default => 0x17
}
//--------------------------------------------------------------------------

void Set_VCOMH_Voltage_12864(unsigned char a)
{
  command(0xBE);  // Set Second Precharge Period
  data(a);        // Default => 0x04
}
//--------------------------------------------------------------------------

void Set_Contrast_Control_12864(unsigned char a)
{
  command(0xC1);  // Set Contrast Control Level
  data(a);        // Default => 0x7F
}
//--------------------------------------------------------------------------

void Master_Contrast_Control_12864(unsigned char a)
{
  command(0xC7);  // Master Contrast Control
  data(a);        // Default => 0x0F
}
//--------------------------------------------------------------------------

void Set_Multiplex_Ratio_12864(unsigned char a)
{
  command(0xCA);  // Set MUX Ratio
  data(a);        // Default => 0x7F
}
//--------------------------------------------------------------------------

void Display_Enhancement_12864(unsigned char a)
{
  command(0xD1);  // Display Enhancement
  data(a);        // 
  data(0x20);     // 
}
//--------------------------------------------------------------------------

void Set_Command_Lock_12864(unsigned char a)
{
  command(0xFD);  // Set Lock/Unlock Commands
  data(a);        // Default => 0x12
}
//--------------------------------------------------------------------------


//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//  Show Blank (Clear Screen)

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

void ClearPixel_12864()
{
  Set_Column_Address_12864(0x1C, 0x5B);
  Set_Row_Address_12864(0x00, 0x3F);
  Set_Write_RAM_12864();

  for (unsigned int i = 0; i < 64 * 128; i++) {
    data(0x00);  // Clear pixel by sending 0
    delayMicroseconds(100);
  }
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//  Show Checkboard (Full Screen)
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

void FillPixel_12864()    
{
  unsigned int i, j; 
  Set_Column_Address_12864(0x1C,0x5B); //1C & 5B = DISPLAY Start & End address.
  Set_Row_Address_12864(0x00,0x3F);
  Set_Write_RAM_12864();
  for(i=0;i<32;i++)   //Columns
  {
    for(j=0;j<64;j++) //Rows
    {
      data(0xFF);
      delayMicroseconds(100);
      data(0x00);
      delayMicroseconds(100);
    }
    for(j=0;j<64;j++) //Rows
    {
      data(0x00);
      delayMicroseconds(100);
      data(0xFF);
      delayMicroseconds(100);
    }
  }
}

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//  Show Image (Full Screen)
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//  Driver IC Mapping = 256x64 (2 SEG Lines Tied to 1 COM Line to form 1 Pixel)  
//  8 bits (1 Byte) = 1 Pixel. 
//  Function parses through Hex Table Data and spreads 1 Byte of data over 8 Pixels. 
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

void ImageDisplay_12864(unsigned char *image)
{
  unsigned int i, l, n, buff;   
  
//Set_Remap_12864(0x04,0x11);         //To flip 180 degrees 
  Set_Column_Address_12864(0x1C,0x5B);
  Set_Row_Address_12864(0x00,0x3F);
  Set_Write_RAM_12864();
  for(i=0;i<1024;i++){  
    buff = *image;
    n = 7;         
    for(l=0;l<8;l++){
      if((buff >> n) & 0x80 == 0x80){
        data(0xFF);
        }
      else{
        data(0x00);
        }
      n--;
    }
      image++;      
  }
}

/****************************************************
*           Initialization For controller           *
*****************************************************/

void OLED_Init_12864()
{
  // Turn off the display before starting initialization
  Set_Sleep_Mode_12864(0xAE);                               // Display OFF
  
  // Unlock commands for OLED
  Set_Command_Lock_12864(0x12);
  
  // Set display clock and oscillator frequency
  Set_Display_Clock__Oscillator_Frequency_12864(0x91);
  
  // Configure display settings
  Set_Multiplex_Ratio_12864(0x3F);                          // Set Multiplex Ratio
  Set_Display_Offset_12864(0x00);                           // Set Display Offset
  Function_Selection_12864(0x01);                           // Function Selection
  Set_Display_Start_Line_12864(0x00);                       // Set Display Start Line
  
  // Set remap for display orientation
  Set_Remap_12864(0x16, 0x11);                             // Adjust A[1] & A[4] to flip display
  
  // Adjust contrast and phase length
  Master_Contrast_Control_12864(0x0F);                      // Master Contrast Control
  Set_Contrast_Control_12864(0x9F);                         // Set Contrast Control
  Set_Phase_Length_12864(0x72);                             // Set Phase Length
  
  // Set voltage and charge settings
  Set_Precharge_Voltage_12864(0x1F);                        // Set Precharge Voltage
  Enable_External_VSL(0xA0, 0xFD);                          // Enable External VSL
  Set_VCOMH_Voltage_12864(0x04);                            // Set VCOMH Voltage
  
  // Configure display mode and enhancement
  Display_Mode_12864(0xA6);                                 // Normal Display Mode
  Display_Enhancement_12864(0xA2);                          // Display Enhancement
  
  // Set GPIO and default grayscale settings
  Set_GPIO_12864(0x00);                                     // Set GPIO
  Default_Grayscale_Command_12864();                        // Default Linear Grayscale Table
  
  // Set second precharge period
  Set_Second_Precharge_Period_12864(0x08);                  // Set Second Precharge Period
  
  // Turn the display back on after initialization
  Set_Sleep_Mode_12864(0xAF);                               // Display ON
}

/*****************************************************
*           Setup Function, to run once              *
*****************************************************/

void setup()
{
  pinMode(OLED_CLK, OUTPUT);
  pinMode(OLED_MOSI, OUTPUT);
  pinMode(OLED_DC, OUTPUT);
  pinMode(OLED_RESET, OUTPUT);
  pinMode(OLED_CS, OUTPUT);
  
  digitalWrite(OLED_RESET, LOW);
  delay(150);
  digitalWrite(OLED_RESET, HIGH);
  delay(150);

  OLED_Init_12864(); //Initialization Sequence
 
  delay(10);
}

/*****************************************************
*           Loop Function, to run repeatedly         *
*****************************************************/

void loop() {
  FillPixel_12864();
  delay(1000);        //1 second delay
  ClearPixel_12864();  
  delay(250);         //1/4 second delay
  ImageDisplay_12864(NHD_Logo);
  delay(2000);        //2 second delay
  command(0xA7);
  delay(2000);        //2 second delay
  command(0xA6);
  delay(2000);        //2 second delay
  ClearPixel_12864();  
  delay(250);         //1/4 second delay
  
}

Hmmm.

did you set 128x64 pix ? ->

/* Column/row settings */
void SSD1322_SetColumn(uint8_t a, uint8_t b)
{
    SSD1322_SendCommandWithData(0x15, (uint8_t[]){a, b}, 2);
}

void SSD1322_SetRow(uint8_t a, uint8_t b)
{
    SSD1322_SendCommandWithData(0x75, (uint8_t[]){a, b}, 2);
}

this:

 Set_Column_Address_12864(0x1C,0x5B);
  Set_Row_Address_12864(0x00,0x3F);

then it should show 128x64 pix.

If you feel a post has answered your question, please click "Accept as Solution".

I've tryied it and  result :(

WhatsApp Image 2025-09-01 at 15.00.47.jpeg

 I don't understand that where is the problem

Ok. :)

So what i do with new display:

- first find driver, that should work. (ok now.)

- init display, then cls (write all pixel with...black here.) try. -> shows clean...nothing, if working ok.

- maybe next: write full area in...white. -> full bright area, can see if all pixel working, addr ok..etc. try.

- then cls, black, write some char at pos 4;4; to see is orientation ok, char font ok , try.

- then..use it, now it should work as it should.

 

+

With your "error pattern" : is it 100% constant on some reset/restarts ? (to exclude errors on connection lines).

or some lines/gaps always litte bit different positions?

If you feel a post has answered your question, please click "Accept as Solution".