wuhanstudio / u8g2-arm-linux

U8g2 for arm linux - a monochrome graphics library
https://github.com/wuhanstudio/u8g2-arm-linux/wiki
Other
51 stars 24 forks source link

4 Wire hardware SPI not working for Pi 0 with ER-OLEDM032-1 (SSD1322) #1

Closed supercrab closed 4 years ago

supercrab commented 5 years ago

Hi

I can't seem to get my 4 wire SPI screen to work out of the box. I noticed that code to set the CS pin is commented out. I've reinstated those lines but it made no difference.

I've used these definitions for my CS and DC pins

#define OLED_SPI_PIN_DC             24 //24
#define OLED_SPI_PIN_CS             8 //8

Thanks Mase

wuhanstudio commented 5 years ago

Hello,

The SPI device used by u8g2 is defined here:

https://github.com/wuhanstudio/u8g2-arm-linux/blob/master/port/U8g2lib.h

static int spi_device;
static const char spi_bus[] = "/dev/spidev0.0";

The CS pin is pre-defined in linux device tree, thus I commented out the code. You may need to find out which CS pin is used by "/dev/spidev0.0".

wuhanstudio commented 5 years ago

For example, the device I used for testing is NanoPi:

http://wiki.friendlyarm.com/wiki/index.php/NanoPi

The CS pin for SPI0 is SS0/GPL13 as shown above.

GPL13 = 32 * 11 (from GPA, GPB, GPC to GPL, 32 pins each) + 13 = 365

As a result, I set OLED_SPI_PIN_CS to 365.

https://github.com/wuhanstudio/u8g2-arm-linux/blob/master/examples/u8g2_4wire_hw_spi/u8g2_4wire_hw_spi.c

#define OLED_SPI_PIN_RES            201
#define OLED_SPI_PIN_DC             199
// #define OLED_SPI_PIN_CS             365

I commented it out because linux SPI driver takes control of CS pin, but the CS pin has to be physically connected with your OLED device's CS pin.

supercrab commented 5 years ago

Hi

Thanks for your reply :)

Hello,

The SPI device used by u8g2 is defined here:

https://github.com/wuhanstudio/u8g2-arm-linux/blob/master/port/U8g2lib.h

static int spi_device;
static const char spi_bus[] = "/dev/spidev0.0";

The CS pin is pre-defined in linux device tree, thus I commented out the code. You may need to find out which CS pin is used by "/dev/spidev0.0".

I know I'm using the right SPI connections as my screen works fine with another project :) My device is attached to /dev/spidev0.0 and works perfectly with my other project. I shall try removing references to CS I put in.

My screen is using GPIO24 for DC but I see you have a strange formula for working out the pin number. What does GPIO24 equate to on the raspberry pi 0. I have it defined as

#define OLED_SPI_PIN_DC 24

wuhanstudio commented 5 years ago

You can find the pin number here:

https://elinux.org/RPi_BCM2711_GPIOs

For example, GPIO8 is used as SPI_CE0_N, and refers to header J8 #24.

gpio

If you are not sure about the pin number, you can test it out by attaching a LED to it, then switch it on and off in terminal with sudo:

GPIO=8

echo $GPIO > /sys/class/gpio/export

# Set pin as output
echo "out" > /sys/class/gpio/gpio$GPIO/direction

# GPIO output HIGH
echo 1 > /sys/class/gpio/gpio$GPIO/value

# GPIO output LOW
echo 0 > /sys/class/gpio/gpio$GPIO/value

Reference: https://elinux.org/GPIO

wuhanstudio commented 5 years ago

By the way, the strange formula you mentioned is defined here:

https://kosagi.com/w/index.php?title=Definitive_GPIO_guide

linux gpio number = (gpio_bank - 1) * 32 + gpio_bit
GPIOA = gpio_bank_1 = 1
GPIOB = gpio_bank_2 = 2
GPIOC = gpio_bank_3 = 3
GPIOD = gpio_bank_4 = 4
...
GPIOL = gpio_bank_12 = 12

thus:

GPIOL_13 = (12 - 1) * 32 + 13 = 365
supercrab commented 5 years ago

I'm definitely using the right pin for DC #define OLED_SPI_PIN_DC 24

I know the pin works and is defined properly because it works in a different project (RPI_V2_GPIO_P1_18 = 24).

I'll try putting an LED on that pin. I can't think of anything else I can try. I'm sure it's something simple! :)

Have you had success with 4 wire SPI?

wuhanstudio commented 5 years ago

Are you using this example, it uses 4 wire SPI and it works for me using SSD1306:

https://github.com/wuhanstudio/u8g2-arm-linux/blob/master/examples/u8g2_4wire_hw_spi/u8g2_4wire_hw_spi.c

// Initialization
u8g2_Setup_ssd1306_128x64_noname_f(&u8g2, U8G2_R0, u8x8_byte_arm_linux_hw_spi, u8x8_arm_linux_gpio_and_delay);
u8x8_SetPin(u8g2_GetU8x8(&u8g2), U8X8_PIN_DC, OLED_SPI_PIN_DC);
u8x8_SetPin(u8g2_GetU8x8(&u8g2), U8X8_PIN_RESET, OLED_SPI_PIN_RES);
// u8x8_SetPin(u8g2_GetU8x8(&u8g2), U8X8_PIN_CS, OLED_SPI_PIN_CS);
u8g2_InitDisplay(&u8g2);

The initialization code above is for OLED with SSD1306 controller. If you are using OLED with a different controller, you need to modify the setup code accordingly.

Here's the full list of supported controllers:

https://github.com/olikraus/u8g2/wiki/u8g2setupc

supercrab commented 5 years ago

Yup, I'm using u8g2_4wire_hw_spi.c with the following setup

      // Initialization
    u8g2_Setup_ssd1322_nhd_256x64_f(&u8g2, U8G2_R0, u8x8_byte_arm_linux_hw_spi, u8x8_arm_linux_gpio_and_delay);
    u8x8_SetPin(u8g2_GetU8x8(&u8g2), U8X8_PIN_DC, OLED_SPI_PIN_DC);
    //u8x8_SetPin(u8g2_GetU8x8(&u8g2), U8X8_PIN_RESET, OLED_SPI_PIN_RES);
    //u8x8_SetPin(u8g2_GetU8x8(&u8g2), U8X8_PIN_CS, OLED_SPI_PIN_CS);

    u8g2_InitDisplay(&u8g2);

u8g2 works fine on my Arduino. I don't have reset connected as the screen works without it.

supercrab commented 5 years ago

When an LED is connected to the DC pin, it flashes and appears to write data to it OK. Weird...

wuhanstudio commented 5 years ago

When an LED is connected to the DC pin, it flashes and appears to write data to it OK. Weird...

Now that DC works, the only possible issue is SPI communication. I'll test it out with my raspi zero today.

By the way, are you using a screen like this:

TIM截图20190926091723

If so, you may need to set contrast since the image may be too dim to be noticed.

void u8g2_SetContrast(u8g2_t *u8g2, uint8_t value);
wuhanstudio commented 5 years ago

It works with raspi zero + ssd1306

sudo ./u8g2_4wire_hw_spi  # Please use sudo

IMG_20190926_123905

My connection is:

VCC --> 5V
GND --> GND
D0 --> SCK (GPIO11 )
D1 --> MOSI (GPIO10)
RES --> GPIO25
DC --> GPIO24

And the code:

#define OLED_SPI_PIN_RES            25
#define OLED_SPI_PIN_DC             24
// #define OLED_SPI_PIN_CS             365

int main(void)
{
    u8g2_t u8g2;

    // Initialization
    u8g2_Setup_ssd1306_128x64_noname_f(&u8g2, U8G2_R0, u8x8_byte_arm_linux_hw_spi, u8x8_arm_linux_gpio_and_delay);
    u8x8_SetPin(u8g2_GetU8x8(&u8g2), U8X8_PIN_DC, OLED_SPI_PIN_DC);
    u8x8_SetPin(u8g2_GetU8x8(&u8g2), U8X8_PIN_RESET, OLED_SPI_PIN_RES);
    // u8x8_SetPin(u8g2_GetU8x8(&u8g2), U8X8_PIN_CS, OLED_SPI_PIN_CS);
    u8g2_InitDisplay(&u8g2);
    u8g2_SetPowerSave(&u8g2, 0);

    // Draw
    /* full buffer example, setup procedure ends in _f */
    u8g2_ClearBuffer(&u8g2);
    u8g2_SetFont(&u8g2, u8g2_font_ncenB08_tr);
    u8g2_DrawStr(&u8g2, 1, 18, "U8g2 on C-SKY");
    u8g2_SendBuffer(&u8g2);

    u8g2_SetFont(&u8g2, u8g2_font_unifont_t_symbols);
    u8g2_DrawGlyph(&u8g2, 112, 56, 0x2603 );
    u8g2_SendBuffer(&u8g2);

    printf("Initialized ...\n");

    return 0;
}

As it works with SSD1306, the SPI communication should be fine. If the issue still can't be solved, I may try to get the same LCD as yours and run some tests.

supercrab commented 5 years ago

Thanks for double checking 4 wire communication! :)

The only thing different between your setup and mine is that you have the reset pin connected. I've manged to get the screen working on arduino and pi without this being connected, so I don't think it's that. I will try connecting it just to rule out. I will also try setting brightness too!

Also, my screen is 4 bit colour, perhaps u8g2 is writing the colour value of 1 which would be very dim! I need to test this tonight by setting u8g2_SetDrawColor(&u8g2, 15); I think that could be the issue - will test later!

I've compared the specs of the SSD1322 and SSD1780 and the 4 wire methods of communications are exactly the same. I also know that u8g2 works on Arduino too.

Here's a pic of my screen working using my other code.
screen

supercrab commented 5 years ago

In addition to my thoughts in the previous post, I've just realised I've forgotten to uncomment the line #define U8G2_16BIT in u8g2.h because my screen is 256 pixels wide.

Will test when I get home!

supercrab commented 5 years ago

I'm gonna try a smaller I2C screen tonight and see if that works!

wuhanstudio commented 5 years ago
  • Uncommented #define U8G2_16BIT in u8g2.h because my screen is 256 pixels wide.
  • 8g2_SetDrawColor only takes 0, 1, 2 so nothing to change there

I'm gonna try a smaller I2C screen tonight and see if that works!

A screen with i2c interface is gonna be much easier to interact with using i2c-tools from official debian packages, which can find out all devices attached to a specific i2c bus.

As for SPI, you may have tried:

  1. Add RES pin.
  2. Uncomment #define U8G2_16BIT
  3. Set contrast

If none of these works, I'll try to get a screen to find out the reason. I hope this issue can be solved at last.

wuhanstudio commented 5 years ago

I have just added software SPI support, you may test it out using:

https://github.com/wuhanstudio/u8g2-arm-linux/blob/master/examples/u8g2_4wire_sw_spi/u8g2_4wire_sw_spi.c

And software I2C and 8080 mode will be released in a day or two.

supercrab commented 5 years ago

Hi

I tried:

I tried with my small i2c OLED (address 3c) but that couldn't connect. I received this error message repeated, running the HW i2c example with sudo:

Failed to write to the i2c bus.
Failed to acquire bus access and/or talk to slave

I tried the screen in my other project (mpd_oled) and it worked fine. Weird. Still not sure what else it could be.

wuhanstudio commented 5 years ago

Hi

I tried:

  • Adding RES pin
  • Defined U8G2_16BIT
  • Set contrast

I tried with my small i2c OLED (address 3c) but that couldn't connect. I received this error message repeated, running the HW i2c example with sudo:

Failed to write to the i2c bus. Failed to acquire bus access and/or talk to slave

I tried the screen in my other project (mpd_oled) and it worked fine. Weird. Still not sure what else it could be.

Seems we are using the same OLED (address 3c) ), and I reproduced your error by using default "/dev/i2c-0" as defined here: https://github.com/wuhanstudio/u8g2-arm-linux/blob/master/port/U8g2lib.h

pi@raspberrypi:~/$ sudo i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- 3c -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --

Now I've changed it to "/dev/i2c-1" for conveniences of most PI users. If your are using:

GPIO2 - SDA
GPIO3 - SCL

IMG_20191001_090817

Then it's "/dev/i2c-1" for pi zero rather than "/dev/i2c-0".

And I have just added software I2C and 8080 support.

IMG_20191001_091143

supercrab commented 5 years ago

Yes, I can confirm that my display is on /dev/i2c-1 I wasn't sure where it was defined but I'm confident your change U8g2lib.h will fix this. I will test the software SPI and the i2c device name change when I get home tonight :)

Cheers

supercrab commented 5 years ago

i2c works on /dev/i2c-1 :) It shows that your code is compiling and running properly! Need to test software defined pins for SPI

43B6F493-BDED-4B2E-A2DD-2E469061D475

wuhanstudio commented 5 years ago

i2c works on /dev/i2c-1 :) It shows that your code is compiling and running properly! Need to test software defined pins for SPI

43B6F493-BDED-4B2E-A2DD-2E469061D475

Cheers, and the latest source code now supports all of software/hardware I2C, SPI, and 8080 mode.

supercrab commented 5 years ago

Software SPI works! It's very slow on my 256x64 4BPP. I moved all the pins back to the hardware SPI and retested but nothing on screen. I tried my other project and the screen was working again.

Pic of SW working. No idea why SPI doesn't work. Does your SPI screen have a DC pin? u8g2

wuhanstudio commented 5 years ago

Software SPI works! It's very slow on my 256x64 4BPP. I moved all the pins back to the hardware SPI and retested but nothing on screen. I tried my other project and the screen was working again.

Pic of SW working. No idea why SPI doesn't work. Does your SPI screen have a DC pin? u8g2

Yes, my connections are:

VCC --> 5V
GND --> GND
D0 --> SCK (GPIO11)
D1 --> MOSI (GPIO10)
RES --> GPIO25
DC --> GPIO24
CS --> CE_0 (GPIO8)

It's better to make sure that no SPI hardware pins is exported as GPIO before. For example, if CE_0 (GPIO8) was used as SW SPI pin, then HW SPI won't work unless rebooting the system or unexport it.

You can find which pins are exported as GPIOs using:

ls /sys/class/gpio/

If there is /sys/class/gpio/gpio8, it can be unexported using:

GPIO=8
sudo echo $GPIO > /sys/class/gpio/unexport

Now, all of SW I2C, HW I2C, and SW SPI are working. Hope HW SPI will be working.

supercrab commented 5 years ago

My hardware SPI pins were not exported. I unexported the pins that were exported but nothing changed. :(

wuhanstudio commented 5 years ago

My hardware SPI pins were not exported. I unexported the pins that were exported but nothing changed. :(

Well, I'll try to get the same OLED as yours (SSD1322 SPI 256*64) and test it out on my pi zero recently.

wuhanstudio commented 5 years ago

After testing it out, now I get it what SLOW means !!! It's incredibly SLOW.

This is caused by constantly performing open, write, close on the same file which can be improved by tracking file descriptors, so that the same file does not need to be opened multiple times, and I've added this to TODOs in README.

ssd1322_sw_spi

It seems 4_wire_hw_spi works on my screen and it's pretty fast.

ssd1322_hw_spi

You may test it out using:

#include <stdio.h>
#include "U8g2lib.h"

// By default, SPI bus /dev/spidev0.0 is used, as defined in port/U8g2lib.h
#define OLED_SPI_PIN_RES            25
#define OLED_SPI_PIN_DC             24

// CS pin is controlled by linux spi driver, thus not defined here, but need to be wired
// #define OLED_SPI_PIN_CS             8

int main(void)
{
    u8g2_t u8g2;

    // Initialization
    u8g2_Setup_ssd1322_nhd_256x64_f(&u8g2, U8G2_R0, u8x8_byte_arm_linux_hw_spi, u8x8_arm_linux_gpio_and_delay);
    u8x8_SetPin(u8g2_GetU8x8(&u8g2), U8X8_PIN_DC, OLED_SPI_PIN_DC);
    u8x8_SetPin(u8g2_GetU8x8(&u8g2), U8X8_PIN_RESET, OLED_SPI_PIN_RES);
    // u8x8_SetPin(u8g2_GetU8x8(&u8g2), U8X8_PIN_CS, OLED_SPI_PIN_CS);

    u8g2_InitDisplay(&u8g2);
    u8g2_SetPowerSave(&u8g2, 0);
    u8g2_SetContrast(&u8g2, 125);

    // Draw
    /* full buffer example, setup procedure ends in _f */
    u8g2_ClearBuffer(&u8g2);

    u8g2_SetFont(&u8g2, u8g2_font_ncenB08_tr);
    u8g2_DrawStr(&u8g2, 1, 18, "U8g2 HW SPI SSD1322 RT-Thread");

    u8g2_SetFont(&u8g2, u8g2_font_unifont_t_symbols);
    u8g2_DrawGlyph(&u8g2, 112, 56, 0x2603 );

    u8g2_SendBuffer(&u8g2);

    printf("Initialized ...\n");

    return 0;
}
supercrab commented 5 years ago

Big thanks for getting the screen. I had this working and also have the speed issue.

Have you tried controlling the screen using hardware SPI pins at all?

wuhanstudio commented 5 years ago

Big thanks for getting the screen. I had this working and also have the speed issue.

Have you tried controlling the screen using hardware SPI pins at all?

Yes, the code above uses hardware SPI and it works for me. The two images demonstrate SW SPI and HW SPI respectively. (Though the two images are very similar, you can tell it that they use different pins)

Sorry I made a mistake, copied the wrong code. Will fix soon.

wuhanstudio commented 5 years ago

The code above has been updated. Didn't realize that I copied the wrong code. Now it uses HW SPI and works on raspi zero.

supercrab commented 4 years ago

Hi again!

I've been doing some more investigation and I've asked someone with the same screen as me to run your code and it works as it should! They were running a Pi 3. My screen is wired exactly the same as his. I tried running the example again but nothing.

Here's the weird thing: my display code works for me but not for him and your library works for him but not for me! Wired both the same too. Crazy! I have another screen to test....

wuhanstudio commented 4 years ago

Hi again!

I've been doing some more investigation and I've asked someone with the same screen as me to run your code and it works as it should! They were running a Pi 3. My screen is wired exactly the same as his. I tried running the example again but nothing.

Here's the weird thing: my display code works for me but not for him and your library works for him but not for me! Wired both the same too. Crazy! I have another screen to test....

That's weird. Maybe you can try to get another screen (the same model) to test it out, I think it may have something to do with manufacturing.

supercrab commented 4 years ago

I tried a different screen and that behaved the same as my existing screen; my display drive code work, your example didn't. :|

TLDR: (for the benefit of people reading this whole thread) I still am unsure as to what is stopping this code from working on my Pi Zero! I will report back here if I ever find what caused my issue.

I do know that for 2 people (you and another) your code works with your screen and I can't see anything wrong with your code so am happy to mark this as closed.

Thanks again!