From cd5c7f524a63bdbf412c5f38e36fcc94c35ba4c8 Mon Sep 17 00:00:00 2001 From: servadmin Date: Sun, 21 Nov 2021 18:13:36 -0500 Subject: [PATCH] Work on thread examples and clean up c++ lib some --- sys/arm-linux/README.md | 13 +++- .../u8g2_sw_i2c_thread/u8g2_sw_i2c_thread.c | 3 +- .../u8g2_sw_i2c_thread_cpp/Makefile | 72 +++++++++++++++++++ .../u8g2_sw_i2c_thread.cpp | 67 +++++++++++++++++ sys/arm-linux/port/U8g2lib.h | 8 +-- 5 files changed, 155 insertions(+), 8 deletions(-) create mode 100644 sys/arm-linux/examples/cpp-examples/u8g2_sw_i2c_thread_cpp/Makefile create mode 100644 sys/arm-linux/examples/cpp-examples/u8g2_sw_i2c_thread_cpp/u8g2_sw_i2c_thread.cpp diff --git a/sys/arm-linux/README.md b/sys/arm-linux/README.md index 78e00b70..4ecc1c6a 100644 --- a/sys/arm-linux/README.md +++ b/sys/arm-linux/README.md @@ -4,6 +4,8 @@ * GPIO, I2C and SPI can be closed and unallocated. * Overall performance should be better. * Run as non-root user. +* Thread safe and multiple display capable. +* For Java check out [Java U8g2](https://github.com/sgjava/java-u8g2) which uses arm-linux port. ## Non-root access If you want to access devices without root do the following (you can try udev @@ -25,7 +27,7 @@ chmod -R ug+rw /dev/spidev* ## Modify source as needed * Change example (SPI 4 wire hardware for instance) -* `nano ~/u8g2/sys/arm-linux/examples/c-examples/u8g2_4wire_hw_spi\u8g2_4wire_hw_spi.c` +* `nano ~/u8g2/sys/arm-linux/examples/c-examples/u8g2_4wire_hw_spi/u8g2_4wire_hw_spi.c` * Change the GPIO chip number (0 uses /dev/gpiochip0) * `#define GPIO_CHIP_NUM 0` * Change the SPI bus number (0x10 uses /dev/spidev1.0) @@ -43,3 +45,12 @@ chmod -R ug+rw /dev/spidev* * `cd ~/u8g2/sys/arm-linux` * `make clean` * `make CC=gcc CXX=g++` + +## Multiple display example using pthreads +After building U8g2 using instructions above. +* `nano ~/u8g2/sys/arm-linux/examples/c-examples/u8g2_sw_i2c_thread/u8g2_sw_i2c_thread.c` +* Change display_1, display_2 and display_3 variables. Obviously you can have only two displays, so modify the code accordingly. This uses software I2C since most SBCs will not have three hardware I2C controllers and changing addresses on displays usually required soldering resistor. +* `cd ~/u8g2/sys/arm-linux` +* `make CPPFLAGS=-DPERIPHERY_GPIO_CDEV_SUPPORT=1 CC=gcc CXX=g++` +* `cd bin` +* `./u8g2_sw_i2c_thread` diff --git a/sys/arm-linux/examples/c-examples/u8g2_sw_i2c_thread/u8g2_sw_i2c_thread.c b/sys/arm-linux/examples/c-examples/u8g2_sw_i2c_thread/u8g2_sw_i2c_thread.c index 60ac4b8b..8c84c158 100644 --- a/sys/arm-linux/examples/c-examples/u8g2_sw_i2c_thread/u8g2_sw_i2c_thread.c +++ b/sys/arm-linux/examples/c-examples/u8g2_sw_i2c_thread/u8g2_sw_i2c_thread.c @@ -29,7 +29,7 @@ void* do_display(void *arg) { printf("Thread %lu start\n", id); u8g2_t u8g2; - // Initialization + // CHange setup function call as needed to support your display u8g2_Setup_ssd1306_i2c_128x32_univision_f(&u8g2, U8G2_R0, u8x8_byte_sw_i2c, u8x8_arm_linux_gpio_and_delay); init_i2c_sw(&u8g2, disp.gpio_chip, disp.scl, disp.sda, disp.res, @@ -38,7 +38,6 @@ void* do_display(void *arg) { h = u8g2_GetDisplayHeight(&u8g2); w = u8g2_GetDisplayWidth(&u8g2); u8g2_SetPowerSave(&u8g2, 0); - u8g2_SetFont(&u8g2, u8g2_font_ncenB08_tr); for (int i = 1; i < 200; ++i) { u8g2_ClearBuffer(&u8g2); y1 = rand() % h; diff --git a/sys/arm-linux/examples/cpp-examples/u8g2_sw_i2c_thread_cpp/Makefile b/sys/arm-linux/examples/cpp-examples/u8g2_sw_i2c_thread_cpp/Makefile new file mode 100644 index 00000000..8d68cb51 --- /dev/null +++ b/sys/arm-linux/examples/cpp-examples/u8g2_sw_i2c_thread_cpp/Makefile @@ -0,0 +1,72 @@ + +# Chosse proper compiler for your PI +# NanoPi: arm-linux-gnueabi-gcc +# Raspberry Pi Zero: arm-linux-gnueabi-gcc + +# Raspberry Pi 2: arm-linux-gnueabihf-gcc +# OrangePi Zero: arm-linux-gnueabihf-gcc +# NanoPi NEO: arm-linux-gnueabihf-gcc +# NanoPi NEO Plus 2: arm-linux-gnueabihf-gcc + +# C-SKY Linux: csky-linux-gcc + +CC=arm-linux-gnueabi-gcc +CXX=arm-linux-gnueabi-g++ + +# IP Address of your PI +PI=pi@raspberrypi.local + +TARGET=u8g2_sw_i2c_thread_cpp +IDIR= -I ../../../drivers -I ../../../../../csrc -I ../../../port +CSRCDIR=../../../../../csrc +CXXSRCDIR=../../../port +OBJDIR=../../../obj +OUTDIR=../../../bin +LDIR= -L ../../../lib +LIBS= -lm -lpthread + +CFLAGS= $(IDIR) -W -Wall -D __ARM_LINUX__ + +OBJ+=u8g2_sw_i2c_thread.cpp.o\ + ../../../port/u8g2port.o\ + ../../../drivers/gpio.o\ + ../../../drivers/spi.o\ + ../../../drivers/i2c.o\ + $(OBJDIR)/Print.cpp.o\ + $(OBJDIR)/U8x8lib.cpp.o\ + $(OBJDIR)/U8g2lib.cpp.o\ + +OBJ+=$(patsubst $(CSRCDIR)/%.c,$(OBJDIR)/%.o, $(wildcard $(CSRCDIR)/*.c)) + +all: directories $(TARGET) + +directories: + @mkdir -p $(OBJDIR) + @mkdir -p $(OUTDIR) + +$(TARGET):$(OBJ) + @echo Generating $(TARGET) ... + @$(CXX) -o $(OUTDIR)/$@ $(OBJ) $(LDIR) $(LIBS) + +u8g2_sw_i2c_thread.cpp.o: u8g2_sw_i2c_thread.cpp + $(CXX) -c -o $@ $< $(CFLAGS) $(LDIR) $(LIBS) + +$(OBJDIR)/%.cpp.o: $(CXXSRCDIR)/%.cpp + $(CXX) -c -o $@ $< $(CFLAGS) $(LDIR) $(LIBS) + +$(OBJDIR)/%.o: $(CSRCDIR)/%.c + $(CC) -c -o $@ $< $(CFLAGS) $(LDIR) $(LIBS) + +clean: + @echo RM -rf $(OBJDIR)/ + @rm -rf $(OBJ) + @rm -rf $(OBJDIR) + + @echo RM -rf $(OUTDIR)/ + @rm -rf $(OUTDIR) + +upload: + scp $(OUTDIR)/$(TARGET) $(PI):~/ + +run: + ssh $(PI) diff --git a/sys/arm-linux/examples/cpp-examples/u8g2_sw_i2c_thread_cpp/u8g2_sw_i2c_thread.cpp b/sys/arm-linux/examples/cpp-examples/u8g2_sw_i2c_thread_cpp/u8g2_sw_i2c_thread.cpp new file mode 100644 index 00000000..06b1d692 --- /dev/null +++ b/sys/arm-linux/examples/cpp-examples/u8g2_sw_i2c_thread_cpp/u8g2_sw_i2c_thread.cpp @@ -0,0 +1,67 @@ +#include +#include + +// Encapsulate each thread's info +struct display { + uint8_t gpio_chip; + uint8_t scl; + uint8_t sda; + uint8_t res; + unsigned long delay; +}; + +typedef struct display display_t; + +/* + * Draw random lines with 50 ms delay. + */ +void * doDisplay(void *arg) { + display_t disp = *((display_t*) arg); + pthread_t id = pthread_self(); + uint8_t h, w, y1, y2; + + printf("Thread %lu start\n", id); + U8G2_SSD1306_128X32_UNIVISION_F_SW_I2C u8g2(U8G2_R0, disp.scl, disp.sda, + U8X8_PIN_NONE); + u8g2.initI2cSw(disp.gpio_chip, disp.scl, disp.sda, disp.res, disp.delay); + u8g2.begin(); + h = u8g2.getDisplayHeight(); + w = u8g2.getWidth(); + for (int i = 1; i < 200; ++i) { + u8g2.clearBuffer(); + y1 = rand() % h; + y2 = rand() % h; + u8g2.drawLine(0, y1, w - 1, y2); + u8g2.sendBuffer(); + u8g2.sleepMs(50); + } + u8g2.sleepOn(); + u8g2.doneUserData(); + printf("Thread %lu end\n", id); + return NULL; +} + +int main(void) { + pthread_t id1; + pthread_t id2; + pthread_t id3; + + void *retVal1; + void *retVal2; + void *retVal3; + + display_t display1 = { 0, 14, 13, U8X8_PIN_NONE, 0 }; + display_t display2 = { 0, 15, 16, U8X8_PIN_NONE, 0 }; + display_t display3 = { 0, 198, 199, U8X8_PIN_NONE, 0 }; + + pthread_create(&id1, NULL, &doDisplay, &display1); + pthread_create(&id2, NULL, &doDisplay, &display2); + pthread_create(&id3, NULL, &doDisplay, &display3); + + pthread_join(id1, (void**) &retVal1); + pthread_join(id2, (void**) &retVal2); + pthread_join(id3, (void**) &retVal3); + printf("Done\n"); + + return 0; +} diff --git a/sys/arm-linux/port/U8g2lib.h b/sys/arm-linux/port/U8g2lib.h index c23fea81..8a357ef2 100644 --- a/sys/arm-linux/port/U8g2lib.h +++ b/sys/arm-linux/port/U8g2lib.h @@ -212,7 +212,7 @@ public: void begin(void) { initDisplay(); clearDisplay(); - setPowerSave(0); + sleepOff(); } void beginSimple(void) { @@ -614,16 +614,14 @@ public: } /* connect to u8g2, draw to u8g2 whenever required */ - bool begin(class U8G2 &u8g2, uint8_t width, uint8_t height, uint8_t *buf) { + void begin(class U8G2 &u8g2, uint8_t width, uint8_t height, uint8_t *buf) { u8log_Init(&u8log, width, height, buf); u8log_SetCallback(&u8log, u8log_u8g2_cb, u8g2.getU8g2()); - return true; } /* disconnected version, manual redraw required */ - bool begin(uint8_t width, uint8_t height, uint8_t *buf) { + void begin(uint8_t width, uint8_t height, uint8_t *buf) { u8log_Init(&u8log, width, height, buf); - return true; } void setLineHeightOffset(int8_t line_height_offset) {