Closed karlo922 closed 7 months ago
It does work with your SW-SPI - but is there any chance to use HW-SPI?
Hi,
For the Linux driver, I replaced the sysfs with gpiod six months ago.
Could you please check if gpiod is supported by the Linux kernel you are using?
The previous port that used sysfs: https://github.com/wuhanstudio/u8g2-arm-linux/tree/31a02e6e22ece76fe9bca45d472ed28c4dea720b
The upstream port: https://github.com/olikraus/u8g2/tree/master/sys/arm-linux
Hi, I use the most current operating system in my Raspi4B - how can I test this?
I build the code from you with
make CPPFLAGS=-DPERIPHERY_GPIO_CDEV_SUPPORT=1 CC=gcc CXX=g++
The one within Olis lib does not compile, it has open includes so I used yours directly.
I guess gpiod is included, as it shows "already installed" when trying to install via sudo apt install gpiod
and also this output is working:
sudo gpioinfo
gpiochip0 - 58 lines:
line 0: "ID_SDA" unused input active-high
line 1: "ID_SCL" unused input active-high
line 2: "SDA1" unused input active-high
line 3: "SCL1" unused input active-high
line 4: "GPIO_GCLK" unused input active-high
line 5: "GPIO5" unused input active-high
line 6: "GPIO6" unused input active-high
line 7: "SPI_CE1_N" "spi0 CS1" output active-low [used]
line 8: "SPI_CE0_N" "spi0 CS0" output active-low [used]
line 9: "SPI_MISO" unused input active-high
line 10: "SPI_MOSI" unused input active-high
line 11: "SPI_SCLK" unused input active-high
line 12: "GPIO12" unused input active-high
line 13: "GPIO13" unused input active-high
line 14: "TXD1" unused input active-high
line 15: "RXD1" unused input active-high
line 16: "GPIO16" unused input active-high
line 17: "GPIO17" unused input active-high
line 18: "GPIO18" unused input active-high
line 19: "GPIO19" unused input active-high
line 20: "GPIO20" unused input active-high
line 21: "GPIO21" unused input active-high
line 22: "GPIO22" unused input active-high
line 23: "GPIO23" unused input active-high
line 24: "GPIO24" unused input active-high
line 25: "GPIO25" unused input active-high
line 26: "GPIO26" unused input active-high
line 27: "GPIO27" unused input active-high
line 28: "RGMII_MDIO" unused input active-high
line 29: "RGMIO_MDC" unused input active-high
line 30: "CTS0" unused input active-high
line 31: "RTS0" unused input active-high
line 32: "TXD0" unused input active-high
line 33: "RXD0" unused input active-high
line 34: "SD1_CLK" unused input active-high
line 35: "SD1_CMD" unused input active-high
line 36: "SD1_DATA0" unused input active-high
line 37: "SD1_DATA1" unused input active-high
line 38: "SD1_DATA2" unused input active-high
line 39: "SD1_DATA3" unused input active-high
line 40: "PWM0_MISO" unused input active-high
line 41: "PWM1_MOSI" unused input active-high
line 42: "STATUS_LED_G_CLK" "ACT" output active-high [used]
line 43: "SPIFLASH_CE_N" unused input active-high
line 44: "SDA0" unused input active-high
line 45: "SCL0" unused input active-high
line 46: "RGMII_RXCLK" unused input active-high
line 47: "RGMII_RXCTL" unused input active-high
line 48: "RGMII_RXD0" unused input active-high
line 49: "RGMII_RXD1" unused input active-high
line 50: "RGMII_RXD2" unused input active-high
line 51: "RGMII_RXD3" unused input active-high
line 52: "RGMII_TXCLK" unused input active-high
line 53: "RGMII_TXCTL" unused input active-high
line 54: "RGMII_TXD0" unused input active-high
line 55: "RGMII_TXD1" unused input active-high
line 56: "RGMII_TXD2" unused input active-high
line 57: "RGMII_TXD3" unused input active-high
gpiochip1 - 8 lines:
line 0: "BT_ON" unused output active-high
line 1: "WL_ON" unused output active-high
line 2: "PWR_LED_OFF" "PWR" output active-low [used]
line 3: "GLOBAL_RESET" unused output active-high
line 4: "VDD_SD_IO_SEL" "vdd-sd-io" output active-high [used]
line 5: "CAM_GPIO" "cam1_regulator" output active-high [used]
line 6: "SD_PWR_ON" "sd_vcc_reg" output active-high [used]
line 7: "SD_OC_N" unused input active-high
I've read at other places that using SPI with "active high" CS is not easily possible using spidev
? But those comments are rather old...
The DC pin works - forget this part of the heading.
Hi I find a solution that solves this problem by changing the device tree:
https://forums.raspberrypi.com/viewtopic.php?t=304156
fragment@0 {
target = <&spi0>;
frag0: __overlay__ {
spidev@0 {
spi-cs-high;
};
spidev@1 {
spi-cs-high;
};
};
};
But this will force it to be "always" high, if active, correct?
Because the real issue will then be, that I have one display using 2 controllers in master/slave configuration for left and right half of it. With CS = 1 you select the master, with CS = 0 you select the slave one.
The rest of the pins are shared, so in u8g2 I will call 2 constructors for the same pins, but once with a constructor that uses CS high as active and once with CS low as active.
Will this work with this workaround? Or is it fully impossible even with SW-SPI to handle 2 displays with your port like that?
My working arduino code:
U8G2_S1D15300_97X32_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 9, /* dc=*/ 7, /* reset=*/ U8X8_PIN_NONE);
U8G2_S1D15300_100X32I_F_4W_HW_SPI u8g2i(U8G2_R0, /* cs=*/ 9, /* dc=*/ 7, /* reset=*/ U8X8_PIN_NONE);
U8G2 *u8g2_current;
u8g2_uint_t offset;
void setLeftSide() {
u8g2_current = &u8g2i;
offset = 0;
}
void setRightSide() {
u8g2_current = &u8g2;
offset = 100;
}
void drawStr(u8g2_uint_t x, u8g2_uint_t y, const char *s) {
u8g2_current->drawStr(x-offset,y,s);
}
void drawWelcome() {
u8g2_current->setFont(u8g2_font_ncenB10_tr);
drawStr(5, 22, "Cappuccino, Mausebaer?");
}
void setup(void) {
u8g2i.begin();
u8g2.begin();
}
void loop(void) {
setLeftSide();
u8g2_current->firstPage();
do { drawWelcome(); }
while (u8g2_current->nextPage());
setRightSide();
u8g2_current->firstPage();
do { drawWelcome(); }
while ( u8g2_current->nextPage());
}
A possible solution is to add an inverter to one of the CS pins.
https://forums.raspberrypi.com/viewtopic.php?t=331853
As for the Linux device tree, the SPI bus can either work in the active-high or active-low mode.
As an inverter would not do the trick using both levels for the master/slave setup, I hope SW SPI should work?
Yes, SW SPI should work.
Unlike Arduino, the Linux HW SPI is defined in the kernel and configured via device tree, which is beyond u8g2's control.
I'll try and let you know here
After updating to the most current u8g2 with your auto_sync
tool, I tried to convert the working ardiuno code https://github.com/wuhanstudio/u8g2-arm-linux/issues/8#issuecomment-2002553996 like that:
#include "u8g2port.h"
#define GPIO_CHIP_NUM 0
#define OLED_SPI_PIN_MOSI 17
#define OLED_SPI_PIN_SCK 27
#define OLED_SPI_PIN_RES U8X8_PIN_NONE
#define OLED_SPI_PIN_DC 2
#define OLED_SPI_PIN_CS 3
u8g2_t u8g2i;
u8g2_t u8g2;
u8g2_t u8g2_current;
u8g2_uint_t offset;
void setLeftSide() {
u8g2_current = u8g2i;
offset = 0;
}
void setRightSide() {
u8g2_current = u8g2;
offset = 100;
}
void drawStr(u8g2_uint_t x, u8g2_uint_t y, const char *s) {
u8g2_DrawStr(&u8g2_current,x-offset,y,s);
}
void drawWelcome() {
u8g2_SetFont(&u8g2_current,u8g2_font_ncenB10_tr);
drawStr(5, 22, "LEFT SIDE AND RIGHT SIDE");
}
int main(void) {
// Initialization
u8g2_Setup_s1d15300_100x32i_f(&u8g2i, U8G2_R0, u8x8_byte_4wire_sw_spi,u8x8_arm_linux_gpio_and_delay);
init_spi_sw(&u8g2i, GPIO_CHIP_NUM, OLED_SPI_PIN_DC, OLED_SPI_PIN_RES,OLED_SPI_PIN_MOSI, OLED_SPI_PIN_SCK, OLED_SPI_PIN_CS, 0);
u8g2_InitDisplay(&u8g2i);
u8g2_ClearDisplay(&u8g2i);
u8g2_SetPowerSave(&u8g2i, 0);
u8g2_Setup_s1d15300_97x32_1(&u8g2, U8G2_R0, u8x8_byte_4wire_sw_spi,u8x8_arm_linux_gpio_and_delay);
init_spi_sw(&u8g2, U8X8_PIN_NONE, U8X8_PIN_NONE, U8X8_PIN_NONE, U8X8_PIN_NONE, U8X8_PIN_NONE, U8X8_PIN_NONE, 0);
u8g2_InitDisplay(&u8g2);
u8g2_ClearDisplay(&u8g2);
u8g2_SetPowerSave(&u8g2, 0);
// Draw
setLeftSide();
u8g2_FirstPage(&u8g2_current);
do { drawWelcome(); }
while (u8g2_NextPage(&u8g2_current));
setRightSide();
u8g2_FirstPage(&u8g2_current);
do { drawWelcome(); }
while ( u8g2_NextPage(&u8g2_current));
printf("Initialized ...\n");
sleep_ms(5000);
// Close and deallocate GPIO resources
done_user_data(&u8g2i);
done_user_data(&u8g2);
printf("Done\n");
return 0;
}
But it only shows the left part of the display. I guess because with setting all pins of the "right" constructor to U8X8_PIN_NONE
the right constructor u8g2
does not do anything on the hardware.
But if I give the rigth controller the same pins like in u8g2i
a fault will be triggered:
u8g2_Setup_s1d15300_100x32i_f(&u8g2i, U8G2_R0, u8x8_byte_4wire_sw_spi,u8x8_arm_linux_gpio_and_delay);
init_spi_sw(&u8g2i, GPIO_CHIP_NUM, OLED_SPI_PIN_DC, OLED_SPI_PIN_RES,OLED_SPI_PIN_MOSI, OLED_SPI_PIN_SCK, OLED_SPI_PIN_CS, 0);
u8g2_InitDisplay(&u8g2i);
u8g2_ClearDisplay(&u8g2i);
u8g2_SetPowerSave(&u8g2i, 0);
u8g2_Setup_s1d15300_97x32_1(&u8g2, U8G2_R0, u8x8_byte_4wire_sw_spi,u8x8_arm_linux_gpio_and_delay);
init_spi_sw(&u8g2, GPIO_CHIP_NUM, OLED_SPI_PIN_DC, OLED_SPI_PIN_RES,OLED_SPI_PIN_MOSI, OLED_SPI_PIN_SCK, OLED_SPI_PIN_CS, 0);
u8g2_InitDisplay(&u8g2);
u8g2_ClearDisplay(&u8g2);
u8g2_SetPowerSave(&u8g2, 0);
...
...
gpio_open(): pin 27, Opening output line handle: Device or resource busy [errno 16]
gpio_open(): pin 17, Opening output line handle: Device or resource busy [errno 16]
gpio_open(): pin 3, Opening output line handle: Device or resource busy [errno 16]
gpio_open(): pin 2, Opening output line handle: Device or resource busy [errno 16]
How can I achieve the same I do with the original arduino lib using the two constructors with the same pins with your port of the lib?
Hi,
Could you please use different gpio ports for the other screen? Because Linux gpio ports are mounted as files, which cannot be opened by two constructors.
I cannot use different pins, as the I have only 4 wires to the display. But on the display PCB, two controllers are soldererd in master/slave mode. You control with the one CS line (high: master / low: slave) wich of the two shall do something. They share the same display, the master one controls the left half, the slave one the right half.
similar like this:
So I need to use the exact same pins as the hardware needs me to do that. I have checked this out with olikraus with his lib, and what you see in my "working arduino code example" was the solution.
I have now tested it with always calling done_user_data(&u8g2i);
or done_user_data(&u8g2);
so in between writing to the display, I free the other controller. It works but may be slow? So you do not have any other idea how I could do this? With arduino itself it was no issue with writing to the same pins.
One possible solution is to synchronise the file descriptors (all gpio pins) for two u8g2 instances, so that you don’t have to close and reopen it every time.
The file descriptors are saved in user_data->pins[i]
void done_user_data(u8g2_t *u8g2) {
user_data_t *user_data = u8g2_GetUserPtr(u8g2);
if (user_data != NULL) {
// Close all GPIO pins
for (int i = 0; i < U8X8_PIN_CNT; ++i) {
if (user_data->pins[i] != NULL) {
gpio_close(user_data->pins[i]);
gpio_free(user_data->pins[i]);
}
}
// Free internal buffer
free(user_data->int_buf);
// Free user data struct
free(user_data);
u8g2_SetUserPtr(u8g2, NULL);
}
}
Thanks for pointing to that although I have not yet got your idea ;) Do you mean to create a kind of "mapper" so I would give dummy pins to the two constructors and merge them somehow to one real pin? Or what did you mean with "synchronise the pins"?
For example, to avoid always calling done_user_data(&u8g2i)
:
// Get GPIO file descriptors
user_data_t *user_data = u8g2_GetUserPtr(u8g2);
user_data_t *user_data_i = u8g2_GetUserPtr(u8g2i);
// Copy file descriptors from u8g2 to u8g2i
if ( (user_data != NULL) && (user_data_i != NULL) ){
for (int i = 0; i < U8X8_PIN_CNT; ++i) {
if (user_data->pins[i] != NULL) {
user_data_i->pins[i] = user_data->pins[i]; // Copy the file descriptor
}
}
// Now, u8g2 and u8g2i share the same file descriptors, so that we don't need to repeatedly close and reopen gpio ports
// At the end of the program, please be careful with `done_user_data(u8g2)` to avoid double free.
Thank you, this works with some changes :)
Cheers !
Hi,
I'm trying to use your code to control a HW SPI display connected to:
DC = GPIO2 RES = not connected CS = CE0 (GPIO4) SCK = SPI0 (GPIO11) MOSI = SPI0 (GPIO10)
with following code:
On SCK and MOSI the correct signals come, but my display needs CS to be HIGH instead of low - I fixed this in the c.file of s1d15300_lm6023 but it does not work - CS will be low when activated.
This is the part of the u8g2 lib what I changed - and I know it works as when I use this on arduino, it works. I also check with my oscilloscope and saw that CS is low when active and not high.