Quantcast
Channel: Raspberry Pi Forums
Viewing all articles
Browse latest Browse all 4654

General • SH1107 OLED 128x128 with C

$
0
0
Hello,
I would like to ask for help with getting an OLED display working.

Hardware
  • Raspberry Pi Pico (RP2040)
  • SH1107 OLED display 128x128, single color
The display is from local store which recommends use of Adafruit library for Arduino applications.
Datasheet can be found here: https://www.laskakit.cz/user/related_fi ... 7_v2-1.pdf

I am able to initiate display and draw whole screen white.
However when I try to draw something (even empty screen), it looks like noise.
oled.png
I did take most of the code from SSD1306 example, which was working for me on display with that driver and made changes according to Adafruit library:

Code:

#include <stdio.h>#include <string.h>#include <stdlib.h>#include <ctype.h>#include "pico/stdlib.h"#include "pico/binary_info.h"#include "hardware/i2c.h"#include "raspberry26x32.h"#include "ssd1306_font.h"/*   GPIO PICO_DEFAULT_I2C_SDA_PIN (on Pico this is GP4 (pin 6)) -> SDA on display   board   GPIO PICO_DEFAULT_I2C_SCL_PIN (on Pico this is GP5 (pin 7)) -> SCL on   display board   3.3v (pin 36) -> VCC on display board   GND (pin 38)  -> GND on display board*/// Define the size of the display we have attached. This can vary, make sure you// have the right size defined or the output will look rather odd!// Code has been tested on 128x32 and 128x64 OLED displays#define SH1107_HEIGHT128#define SH1107_WIDTH128#define SH1107_I2C_ADDR_u(0x3C)// 400 is usual, but often these can be overclocked to improve display response.// Tested at 1000 on both 32 and 84 pixel height devices and it worked.#define SH1107_I2C_CLK400#define SH1107_BLACK0 // draw black pixel#define SH1107_WHITE1 // draw white pixel#define SH1107_INVERSE2 // invert pixels// commands (see datasheet)#define SH1107_SET_MEM_MODE_u(0x20)#define SH1107_SET_COL_ADDR_u(0x21)#define SH1107_SET_PAGE_ADDR_u(0xB0)#define SH1107_SET_LOW_COL_u(0x00)#define SH1107_SET_HIGH_COL_u(0x10)#define SH1107_SET_START_LINE_u(0x40)#define SH1107_SET_CONTRAST_u(0x81)#define SH1107_SET_CHARGE_PUMP_u(0x8D)#define SH1107_SET_SEG_REMAP_u(0xA0)#define SH1107_SET_ENTIRE_ON_u(0xA4)#define SH1107_SET_ALL_ON_u(0xA5)#define SH1107_SET_NORM_DISP_u(0xA6)#define SH1107_SET_INV_DISP_u(0xA7)#define SH1107_SET_MUX_RATIO_u(0xA8)#define SH1107_SET_DISP_OFF_u(0xAE)#define SH1107_SET_DCDC_u(0xAD)#define SH1107_SET_DISP_ON_u(0xAF)#define SH1107_SET_COM_OUT_DIR_u(0xC0)#define SH1107_SET_DISP_OFFSET_u(0xD3)#define SH1107_SET_DISP_CLK_DIV_u(0xD5)#define SH1107_SET_PRECHARGE_u(0xD9)#define SH1107_SET_COM_PIN_CFG_u(0xDA)#define SH1107_SET_VCOM_DESEL_u(0xDB)#define SH1107_SET_DISP_START_LINE_u(0xDC)#define SH1107_PAGE_HEIGHT_u(8)#define SH1107_NUM_PAGES(SH1107_HEIGHT / SH1107_PAGE_HEIGHT)#define SH1107_BUF_LEN(SH1107_NUM_PAGES * SH1107_WIDTH)struct render_area {    uint8_t start_col;    uint8_t end_col;    uint8_t start_page;    uint8_t end_page;    int buflen;};void calc_render_area_buflen(struct render_area *area) {    // calculate how long the flattened buffer will be for a render area    area->buflen = (area->end_col - area->start_col + 1) * (area->end_page - area->start_page + 1);}#ifdef i2c_defaultvoid SH1107_send_cmd(uint8_t cmd) {    // I2C write process expects a control byte followed by data    // this "data" can be a command or data to follow up a command    // Co = 1, D/C = 0 => the driver expects a command    uint8_t buf[2] = {0x80, cmd};    i2c_write_blocking(i2c_default, SH1107_I2C_ADDR, buf, 2, false);}void SH1107_send_cmd_list(uint8_t *buf, int num) {    for (int i=0;i<num;i++)        SH1107_send_cmd(buf[i]);}void SH1107_send_buf(uint8_t buf[], int buflen) {    // in horizontal addressing mode, the column address pointer auto-increments    // and then wraps around to the next page, so we can send the entire frame    // buffer in one gooooooo!    // copy our frame buffer into a new buffer because we need to add the control byte    // to the beginning    uint8_t *temp_buf = malloc(buflen + 1);    temp_buf[0] = 0x40;    memcpy(temp_buf+1, buf, buflen);    i2c_write_blocking(i2c_default, SH1107_I2C_ADDR, temp_buf, buflen + 1, false);    free(temp_buf);}void SH1107_init() {// Some of these commands are not strictly necessary as the reset// process defaults to some of these but they are shown here// to demonstrate what the initialization sequence looks like// Some configuration values are recommended by the board manufacturer// Init sequence got from SSD1306, modifieduint8_t cmds[] = {SH1107_SET_DISP_OFF,SH1107_SET_MEM_MODE|0x00,SH1107_SET_DISP_START_LINE|0x00,SH1107_SET_SEG_REMAP,SH1107_SET_MUX_RATIO|0x7F,SH1107_HEIGHT -1,SH1107_SET_COM_OUT_DIR|0x08,SH1107_SET_DISP_OFFSET|0x00,SH1107_SET_DISP_CLK_DIV|0x80,SH1107_SET_PRECHARGE|0xF1,SH1107_SET_VCOM_DESEL|0x30,SH1107_SET_CONTRAST|0xFF,SH1107_SET_DCDC|0x81,SH1107_SET_ENTIRE_ON,SH1107_SET_NORM_DISP,SH1107_SET_CHARGE_PUMP|0x14,SH1107_SET_DISP_ON,};SH1107_send_cmd_list(cmds, count_of(cmds));}void render(uint8_t *buf, struct render_area *area) {    // update a portion of the display with a render area    uint8_t cmds[] = {        SH1107_SET_COL_ADDR,        area->start_col,        area->end_col,        SH1107_SET_PAGE_ADDR,        area->start_page,        area->end_page    };    SH1107_send_cmd_list(cmds, count_of(cmds));    SH1107_send_buf(buf, area->buflen);}// Draw Pixel yoinked from adafruitstatic void SetPixel(int16_t x, int16_t y) {uint8_t buf[x + (y / 8) * SH1107_WIDTH]; //|= (1 << (y & 7));}static inline int GetFontIndex(uint8_t ch) {    if (ch >= 'A' && ch <='Z') {        return  ch - 'A' + 1;    }    else if (ch >= '0' && ch <='9') {        return  ch - '0' + 27;    }    else return  0; // Not got that char so space.}static void WriteChar(uint8_t *buf, int16_t x, int16_t y, uint8_t ch) {    if (x > SH1107_WIDTH - 8 || y > SH1107_HEIGHT - 8)        return;    // For the moment, only write on Y row boundaries (every 8 vertical pixels)    y = y/8;    ch = toupper(ch);    int idx = GetFontIndex(ch);    int fb_idx = y * 128 + x;    for (int i=0;i<8;i++) {        buf[fb_idx++] = font[idx * 8 + i];    }}static void WriteString(uint8_t *buf, int16_t x, int16_t y, char *str) {    // Cull out any string off the screen    if (x > SH1107_WIDTH - 8 || y > SH1107_HEIGHT - 8)        return;    while (*str) {        WriteChar(buf, x, y, *str++);        x+=8;    }}#endifvoid SH1107_clearDisplay(void) {uint8_t buf[SH1107_BUF_LEN];memset (buf, 0, SH1107_WIDTH * ((SH1107_HEIGHT + 7) / 8));struct render_area frame_area = {start_col: 0,end_col: SH1107_WIDTH -1,start_page: 0,end_page: SH1107_NUM_PAGES -1};render(buf, &frame_area);}int main() {stdio_init_all();// I2C is "open drain", pull ups to keep signal high when no data is being// senti2c_init(i2c_default, SH1107_I2C_CLK * 1000);gpio_set_function(PICO_DEFAULT_I2C_SDA_PIN, GPIO_FUNC_I2C);gpio_set_function(PICO_DEFAULT_I2C_SCL_PIN, GPIO_FUNC_I2C);gpio_pull_up(PICO_DEFAULT_I2C_SDA_PIN);gpio_pull_up(PICO_DEFAULT_I2C_SCL_PIN);// run through the complete initialization processSH1107_init();// Initialize render area for entire frame (SH1107_WIDTH pixels by SH1107_NUM_PAGES pages)struct render_area frame_area = {start_col: 0,end_col : SH1107_WIDTH -1,start_page : 0,        end_page : SH1107_NUM_PAGES -1};calc_render_area_buflen(&frame_area);// zero the entire displayuint8_t buf[SH1107_BUF_LEN];memset(buf, 0, SH1107_BUF_LEN);render(buf, &frame_area);// intro sequence: flash the screen 3 timesfor (int i = 0; i < 3; i++) {SH1107_send_cmd(SH1107_SET_ALL_ON);    // Set all pixels onsleep_ms(500);SH1107_send_cmd(SH1107_SET_ENTIRE_ON); // go back to RAM for pixel statesleep_ms(500);}// Loop code herewhile(1){SH1107_clearDisplay();// This should clear displaysleep_ms(5000);SH1107_send_cmd(SH1107_SET_ALL_ON);// Set all pixels onsleep_ms(500);SH1107_send_cmd(SH1107_SET_ENTIRE_ON);// Render back what's in memorySetPixel(64, 64);// Render singel pixel in middlerender(buf, &frame_area);// Send buffer to rendersleep_ms(1000);}}
I don't have problem with detection and initialization of the display so I suspect there is something wrong with rendering code but I don't know what or where to look for the problem. I hope someone could point me to the right direction because I am lost at the moment.

I hope I wrote everything I know but if there is any info missing, I will try to supply it.

Thank you in advance :)

Statistics: Posted by Janez — Sat Dec 14, 2024 5:41 pm — Replies 0 — Views 7



Viewing all articles
Browse latest Browse all 4654

Trending Articles