From a7b8883bc34a0602fd1ca390387975226b7f5bf1 Mon Sep 17 00:00:00 2001 From: servadmin Date: Mon, 1 Nov 2021 20:10:46 -0400 Subject: [PATCH] Refactor to allow sysfs or charater device for GPIO --- sys/arm-linux/README.md | 29 ++++ .../u8g2_4wire_hw_spi/u8g2_4wire_hw_spi.c | 5 +- sys/arm-linux/port/u8g2port.c | 156 ++++++++---------- sys/arm-linux/port/u8g2port.h | 2 + 4 files changed, 103 insertions(+), 89 deletions(-) create mode 100644 sys/arm-linux/README.md diff --git a/sys/arm-linux/README.md b/sys/arm-linux/README.md new file mode 100644 index 00000000..c1034d79 --- /dev/null +++ b/sys/arm-linux/README.md @@ -0,0 +1,29 @@ +![Title](images/title.png) + +[U8g2 for arm-linux](https://github.com/wuhanstudio/u8g2-arm-linux) has been modified to use +[c-periphery](https://github.com/vsergeev/c-periphery) userspace library. +* Deprecated sysfs method is no longer used for GPIO thus increasing speed and stability. +* GPIO pins can be unallocated which is useful for testing multiple times. +* I2C and SPI also use c-periphery. + +## Download U8g2 project +* `cd ~/` +* `git clone --depth 1 https://github.com/olikraus/u8g2` + +## Modify source as needed +Currently GPIO device, I2C and SPI buses are hard coded in u8g2port.c. +* Change values as needed +* `nano ~/u8g2/sys/arm-linux/port/u8g2port.c` +* 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` +* Change the DC and RESET as needed (NanoPi Duo here using tx1 and rx1) +* `#define OLED_SPI_PIN_RES 199` +* `#define OLED_SPI_PIN_DC 198` + +## Build source with GPIO character device +* `cd ~/u8g2/sys/arm-linux` +* `make CPPFLAGS=-DPERIPHERY_GPIO_CDEV_SUPPORT=1 CC=gcc CXX=g++` + +## Build source with GPIO sysfs +* `cd ~/u8g2/sys/arm-linux` +* `make CC=gcc CXX=g++` diff --git a/sys/arm-linux/examples/c-examples/u8g2_4wire_hw_spi/u8g2_4wire_hw_spi.c b/sys/arm-linux/examples/c-examples/u8g2_4wire_hw_spi/u8g2_4wire_hw_spi.c index 2b499713..2cfa9f8c 100644 --- a/sys/arm-linux/examples/c-examples/u8g2_4wire_hw_spi/u8g2_4wire_hw_spi.c +++ b/sys/arm-linux/examples/c-examples/u8g2_4wire_hw_spi/u8g2_4wire_hw_spi.c @@ -34,6 +34,9 @@ int main(void) u8g2_SendBuffer(&u8g2); printf("Initialized ...\n"); - + sleep_ms(5000); + u8g2_SetPowerSave(&u8g2, 1); + // Deallocate GPIO pins + done_pins(); return 0; } diff --git a/sys/arm-linux/port/u8g2port.c b/sys/arm-linux/port/u8g2port.c index bd91cf6b..0343a6d2 100644 --- a/sys/arm-linux/port/u8g2port.c +++ b/sys/arm-linux/port/u8g2port.c @@ -9,13 +9,49 @@ static const char spi_bus[] = "/dev/spidev0.0"; static const char gpio_device[] = "/dev/gpiochip0"; // c-periphery GPIO pins -gpio_t *pins[U8X8_PIN_CNT]; +gpio_t *pins[U8X8_PIN_CNT] = { }; +/** + * Initialize pin if not set to U8X8_PIN_NONE. + */ void init_pin(u8x8_t *u8x8, int pin) { - pins[pin] = gpio_new(); + if (u8x8->pins[pin] != U8X8_PIN_NONE) { + pins[pin] = gpio_new(); +// Support character device +#if PERIPHERY_GPIO_CDEV_SUPPORT if (gpio_open(pins[pin], gpio_device, u8x8->pins[pin], GPIO_DIR_OUT_HIGH) < 0) { - fprintf(stderr, "gpio_open(): %s\n", gpio_errmsg(pins[pin])); + fprintf(stderr, "gpio_open(): pin %d, %s\n", pin, gpio_errmsg(pins[pin])); + } +// Support deprecated sysfs +#else + if (gpio_open_sysfs(pins[pin], u8x8->pins[pin], GPIO_DIR_OUT_HIGH) + < 0) { + fprintf(stderr, "gpio_open_sysfs(): pin %d, %s\n", pin, + gpio_errmsg(pins[pin])); + } +#endif + } +} + +/* + * Close and free gpio_t. + */ +void done_pins() { + for (int i = 0; i < U8X8_PIN_CNT; ++i) { + if (pins[i] != NULL) { + gpio_close(pins[i]); + gpio_free(pins[i]); + } + } +} + +/** + * Write pin if not set to U8X8_PIN_NONE. + */ +void write_pin(u8x8_t *u8x8, int pin, int value) { + if (u8x8->pins[pin] != U8X8_PIN_NONE) { + gpio_write(pins[pin], value); } } @@ -56,54 +92,26 @@ uint8_t u8x8_arm_linux_gpio_and_delay(u8x8_t *u8x8, uint8_t msg, // printf("SDA:%d, SCL:%d\n", u8x8->pins[U8X8_PIN_I2C_DATA], u8x8->pins[U8X8_PIN_I2C_CLOCK]); // SPI Pins - if (u8x8->pins[U8X8_PIN_SPI_CLOCK] != U8X8_PIN_NONE) { - init_pin(u8x8, U8X8_PIN_SPI_CLOCK); - } - if (u8x8->pins[U8X8_PIN_SPI_DATA] != U8X8_PIN_NONE) { - init_pin(u8x8, U8X8_PIN_SPI_DATA); - } - if (u8x8->pins[U8X8_PIN_CS] != U8X8_PIN_NONE) { - init_pin(u8x8, U8X8_PIN_CS); - } + init_pin(u8x8, U8X8_PIN_SPI_CLOCK); + init_pin(u8x8, U8X8_PIN_SPI_DATA); + init_pin(u8x8, U8X8_PIN_CS); // 8080 mode // D0 --> spi clock // D1 --> spi data - if (u8x8->pins[U8X8_PIN_D2] != U8X8_PIN_NONE) { - init_pin(u8x8, U8X8_PIN_D2); - } - if (u8x8->pins[U8X8_PIN_D3] != U8X8_PIN_NONE) { - init_pin(u8x8, U8X8_PIN_D3); - } - if (u8x8->pins[U8X8_PIN_D4] != U8X8_PIN_NONE) { - init_pin(u8x8, U8X8_PIN_D4); - } - if (u8x8->pins[U8X8_PIN_D5] != U8X8_PIN_NONE) { - init_pin(u8x8, U8X8_PIN_D5); - } - if (u8x8->pins[U8X8_PIN_D6] != U8X8_PIN_NONE) { - init_pin(u8x8, U8X8_PIN_D6); - } - if (u8x8->pins[U8X8_PIN_D7] != U8X8_PIN_NONE) { - init_pin(u8x8, U8X8_PIN_D7); - } - if (u8x8->pins[U8X8_PIN_E] != U8X8_PIN_NONE) { - init_pin(u8x8, U8X8_PIN_E); - } - if (u8x8->pins[U8X8_PIN_RESET] != U8X8_PIN_NONE) { - init_pin(u8x8, U8X8_PIN_RESET); - } - if (u8x8->pins[U8X8_PIN_DC] != U8X8_PIN_NONE) { - init_pin(u8x8, U8X8_PIN_DC); - } + init_pin(u8x8, U8X8_PIN_D2); + init_pin(u8x8, U8X8_PIN_D3); + init_pin(u8x8, U8X8_PIN_D4); + init_pin(u8x8, U8X8_PIN_D5); + init_pin(u8x8, U8X8_PIN_D6); + init_pin(u8x8, U8X8_PIN_D7); + init_pin(u8x8, U8X8_PIN_E); + init_pin(u8x8, U8X8_PIN_RESET); + init_pin(u8x8, U8X8_PIN_DC); // I2c pins - if (u8x8->pins[U8X8_PIN_I2C_DATA] != U8X8_PIN_NONE) { - init_pin(u8x8, U8X8_PIN_I2C_DATA); - } - if (u8x8->pins[U8X8_PIN_I2C_CLOCK] != U8X8_PIN_NONE) { - init_pin(u8x8, U8X8_PIN_I2C_CLOCK); - } + init_pin(u8x8, U8X8_PIN_I2C_DATA); + init_pin(u8x8, U8X8_PIN_I2C_CLOCK); break; @@ -114,96 +122,68 @@ uint8_t u8x8_arm_linux_gpio_and_delay(u8x8_t *u8x8, uint8_t msg, //case U8X8_MSG_GPIO_SPI_DATA: case U8X8_MSG_GPIO_D2: // D2 pin: Output level in arg_int - if (u8x8->pins[U8X8_PIN_D2] != U8X8_PIN_NONE) { - gpio_write(pins[U8X8_PIN_D2], arg_int); - } + write_pin(u8x8, U8X8_PIN_D2, arg_int); break; case U8X8_MSG_GPIO_D3: // D3 pin: Output level in arg_int - if (u8x8->pins[U8X8_PIN_D3] != U8X8_PIN_NONE) { - gpio_write(pins[U8X8_PIN_D3], arg_int); - } + write_pin(u8x8, U8X8_PIN_D3, arg_int); break; case U8X8_MSG_GPIO_D4: // D4 pin: Output level in arg_int - if (u8x8->pins[U8X8_PIN_D4] != U8X8_PIN_NONE) { - gpio_write(pins[U8X8_PIN_D4], arg_int); - } + write_pin(u8x8, U8X8_PIN_D4, arg_int); break; case U8X8_MSG_GPIO_D5: // D5 pin: Output level in arg_int - if (u8x8->pins[U8X8_PIN_D5] != U8X8_PIN_NONE) { - gpio_write(pins[U8X8_PIN_D5], arg_int); - } + write_pin(u8x8, U8X8_PIN_D5, arg_int); break; case U8X8_MSG_GPIO_D6: // D6 pin: Output level in arg_int - if (u8x8->pins[U8X8_PIN_D6] != U8X8_PIN_NONE) { - gpio_write(pins[U8X8_PIN_D6], arg_int); - } + write_pin(u8x8, U8X8_PIN_D6, arg_int); break; case U8X8_MSG_GPIO_D7: // D7 pin: Output level in arg_int - if (u8x8->pins[U8X8_PIN_D7] != U8X8_PIN_NONE) { - gpio_write(pins[U8X8_PIN_D7], arg_int); - } + write_pin(u8x8, U8X8_PIN_D7, arg_int); break; case U8X8_MSG_GPIO_E: // E/WR pin: Output level in arg_int - if (u8x8->pins[U8X8_PIN_E] != U8X8_PIN_NONE) { - gpio_write(pins[U8X8_PIN_E], arg_int); - } + write_pin(u8x8, U8X8_PIN_E, arg_int); break; case U8X8_MSG_GPIO_I2C_CLOCK: // arg_int=0: Output low at I2C clock pin // arg_int=1: Input dir with pullup high for I2C clock pin - if (u8x8->pins[U8X8_PIN_I2C_CLOCK] != U8X8_PIN_NONE) { - gpio_write(pins[U8X8_PIN_I2C_CLOCK], arg_int); - } + write_pin(u8x8, U8X8_PIN_I2C_CLOCK, arg_int); break; case U8X8_MSG_GPIO_I2C_DATA: // arg_int=0: Output low at I2C data pin // arg_int=1: Input dir with pullup high for I2C data pin - if (u8x8->pins[U8X8_PIN_I2C_DATA] != U8X8_PIN_NONE) { - gpio_write(pins[U8X8_PIN_I2C_DATA], arg_int); - } + write_pin(u8x8, U8X8_PIN_I2C_DATA, arg_int); break; case U8X8_MSG_GPIO_SPI_CLOCK: //Function to define the logic level of the clockline - if (u8x8->pins[U8X8_PIN_SPI_CLOCK] != U8X8_PIN_NONE) { - gpio_write(pins[U8X8_PIN_SPI_CLOCK], arg_int); - } + write_pin(u8x8, U8X8_PIN_SPI_CLOCK, arg_int); break; case U8X8_MSG_GPIO_SPI_DATA: //Function to define the logic level of the data line to the display - if (u8x8->pins[U8X8_PIN_SPI_DATA] != U8X8_PIN_NONE) { - gpio_write(pins[U8X8_PIN_SPI_DATA], arg_int); - } + write_pin(u8x8, U8X8_PIN_SPI_DATA, arg_int); break; case U8X8_MSG_GPIO_CS: // Function to define the logic level of the CS line - if (u8x8->pins[U8X8_PIN_CS] != U8X8_PIN_NONE) { - gpio_write(pins[U8X8_PIN_CS], arg_int); - } + write_pin(u8x8, U8X8_PIN_CS, arg_int); break; case U8X8_MSG_GPIO_DC: //Function to define the logic level of the Data/ Command line - if (u8x8->pins[U8X8_PIN_DC] != U8X8_PIN_NONE) { - gpio_write(pins[U8X8_PIN_DC], arg_int); - } + write_pin(u8x8, U8X8_PIN_DC, arg_int); break; case U8X8_MSG_GPIO_RESET: //Function to define the logic level of the RESET line - if (u8x8->pins[U8X8_PIN_RESET] != U8X8_PIN_NONE) { - gpio_write(pins[U8X8_PIN_RESET], arg_int); - } + write_pin(u8x8, U8X8_PIN_RESET, arg_int); break; default: @@ -263,7 +243,7 @@ uint8_t u8x8_byte_arm_linux_hw_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, while (arg_int > 0) { // printf("%.2X ", (uint8_t)*data); - tx[0] = (uint8_t) * data; + tx[0] = (uint8_t) *data; struct spi_ioc_transfer tr = { .tx_buf = (unsigned long) tx, .rx_buf = (unsigned long) rx, .len = 1, .delay_usecs = 0, .speed_hz = 500000, .bits_per_word = 8, }; diff --git a/sys/arm-linux/port/u8g2port.h b/sys/arm-linux/port/u8g2port.h index 7f595121..7c05a757 100644 --- a/sys/arm-linux/port/u8g2port.h +++ b/sys/arm-linux/port/u8g2port.h @@ -11,6 +11,8 @@ #include "spi.h" void init_pin(u8x8_t *u8x8, int pin); +void done_pins(); +void write_pin(u8x8_t *u8x8, int pin, int value); uint8_t u8x8_arm_linux_gpio_and_delay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr); uint8_t u8x8_byte_arm_linux_hw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr); uint8_t u8x8_byte_arm_linux_hw_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);