I bought a Waveshare 128x128 RGB OLED display that uses the SSD1351 controller. I started writing some code for the Milk-V Duo, using the WiringX SPI library commands. After wasting a few hours I realized, once again, that WiringX just doesn't work. It needs a lot of work. The way it is now is useless.
So, back to bitbang SPI. No problems - SPI is super simple. The only thing I ran into is that the WiringX digitalWrite command is SLOW, and my code, with no delays whatsoever, updates the display way too slowly. Oh well, good enough for now. Some inline assembly code would get some speed out of this thing, but I would need a good datasheet for the Duo's MCU to do that.
As usual, Solomon Systech's datasheet is super cryptic and has some errors. It took me lots of trial and error and test code to figure out what they meant by some things, and to find out that they describe their startup sequence the opposite of how you should do it. What fun!
Photos and videos of the display are terrible because the display refresh gets caught at random times by my Pixel 7 phone camera, which has no shutter speed control, and, in fact, no advanced controls whatsoever. Don't buy a Google phone. I don't completely hate the Pixel, but my old Samsung was so much better.
Super simple demo code. This isn't even remotely close to being a driver yet. It's just the most minimal code for getting the display initialized and putting some colors on the screen. I'll do something more ambitious later:
ssd1351_128x128_rgb.c
#include <unistd.h>
#include <wiringx.h>
#include "ssd1351_128x128_rgb.h"
int rst = 15; //reset - physical pin 20
int dc = 14; //D/C - physical pin 19
int clk = 6; //clk - physical pin 9
int dat = 7; //dat - physical pin 10
unsigned char framebuff[0x8000];
int main(void){
init();
cls();
while(1){
for (int x=0;x<0x8000;x+=2){
framebuff[x] = 0xf8;
framebuff[x+1] = 0x00;
}
transbuff();
for (int x=0;x<0x8000;x+=2){
framebuff[x] = 0x07;
framebuff[x+1] = 0xe0;
}
transbuff();
for (int x=0;x<0x8000;x+=2){
framebuff[x] = 0x00;
framebuff[x+1] = 0x1f;
}
transbuff();
}
}
void cls(void){
for(int x=0;x<0x8000;x++)
framebuff[x] = 0;
transbuff();
}
//write framebuff to GDDRAM
void transbuff(){
digitalWrite(dc,LOW); //command
spiwrite(0x5c);
digitalWrite(dc,HIGH); //data
for(int x=0;x<0x8000;x++)
spiwrite(framebuff[x]);
}
void spiwrite(unsigned char p){
for(int x=0;x<8;x++){
if(p & 0x80)
digitalWrite(dat,HIGH);
else
digitalWrite(dat,LOW);
digitalWrite(clk,HIGH);
digitalWrite(clk,LOW);
p <<= 1;
}
}
int init(){
//wiringx init
if(wiringXSetup("duo", NULL) == -1){
wiringXGC();
}
pinMode(dc,PINMODE_OUTPUT);
pinMode(rst,PINMODE_OUTPUT);
pinMode(clk,PINMODE_OUTPUT);
pinMode(dat,PINMODE_OUTPUT);
digitalWrite(clk,LOW);
//OLED init
usleep(6000); //OLED reset
digitalWrite(rst,1);
usleep(10000);
digitalWrite(rst,0);
usleep(50000);
digitalWrite(rst,1);
digitalWrite(dc,0); //send command
spiwrite(0xae); //display OFF
spiwrite(0xfd); //unlock MCU protect
digitalWrite(dc,1); //send data
spiwrite(0x12);
digitalWrite(dc,0);
spiwrite(0xfd); //make a2 accessible
digitalWrite(dc,1);
spiwrite(0xb1);
digitalWrite(dc,0);
spiwrite(0xa2); //set vertical scroll by row
digitalWrite(dc,1);
spiwrite(0x00);
digitalWrite(dc,0);
spiwrite(0xb3); //clock speed
digitalWrite(dc,1);
spiwrite(0xf0); //max clock speed
digitalWrite(dc,0);
spiwrite(0xa0); //remap/color depth 65k
digitalWrite(dc,1);
spiwrite(0x74);
digitalWrite(dc,0);
spiwrite(0xaf); //display ON
}
ssd1351_128x128_rgb.h
void transbuff(void);
void cls(void);
void spiwrite(unsigned char);
int init(void);