GPIO, I2C and SPI working

This commit is contained in:
servadmin 2021-11-06 22:29:46 -04:00
parent 8c3254d251
commit 7f95cc3811
12 changed files with 120 additions and 52 deletions

View File

@ -415,8 +415,14 @@ void u8g2_ClearDisplay(u8g2_t *u8g2);
#define u8g2_GetDisplayWidth(u8g2) ((u8g2)->width)
#define u8g2_GetDrawColor(u8g2) ((u8g2)->draw_color)
#define u8g2_SetI2CAddress(u8g2, address) ((u8g2_GetU8x8(u8g2))->i2c_address = (address))
#define u8g2_GetGPIOChip(u8g2) u8x8_GetGPIOChip(u8g2_GetU8x8(u8g2))
#define u8g2_SetGPIOChip(u8g2, chip_num) ((u8g2_GetU8x8(u8g2))->gpio_chip_num = (chip_num))
#define u8g2_GetSPIBus(u8g2) u8x8_GetSPIBus(u8g2_GetU8x8(u8g2))
#define u8g2_SetSPIBus(u8g2, bus_num) ((u8g2_GetU8x8(u8g2))->spi_bus_num = (bus_num))
#define u8g2_GetI2CBus(u8g2) u8x8_GetI2CBus(u8g2_GetU8x8(u8g2))
#define u8g2_SetI2CBus(u8g2, bus_num) ((u8g2_GetU8x8(u8g2))->i2c_bus_num = (bus_num))
#define u8g2_GetI2CAddress(u8g2) u8x8_GetI2CAddress(u8g2_GetU8x8(u8g2))
#define u8g2_SetI2CAddress(u8g2, address) ((u8g2_GetU8x8(u8g2))->i2c_address = (address))
#ifdef U8X8_USE_PINS
#define u8g2_SetMenuSelectPin(u8g2, val) u8x8_SetMenuSelectPin(u8g2_GetU8x8(u8g2), (val))

View File

@ -346,6 +346,7 @@ struct u8x8_struct
uint16_t encoding; /* encoding result for utf8 decoder in next_cb */
uint8_t x_offset; /* copied from info struct, can be modified in flip mode */
uint8_t is_font_inverse_mode; /* 0: normal, 1: font glyphs are inverted */
uint8_t gpio_chip_num; /* gpio chip */
uint8_t spi_bus_num; /* spi bus to use */
uint8_t i2c_bus_num; /* i2c bus to use */
uint8_t i2c_address; /* a valid i2c adr. Initially this is 255, but this is set to something usefull during DISPLAY_INIT */
@ -375,6 +376,8 @@ struct u8x8_struct
#define u8x8_GetCols(u8x8) ((u8x8)->display_info->tile_width)
#define u8x8_GetRows(u8x8) ((u8x8)->display_info->tile_height)
#define u8x8_GetGPIOChip(u8x8) ((u8x8)->gpio_chip_num)
#define u8x8_SetGPIOChip(u8x8, chip_num) ((u8x8)->gpio_chip_num = (chip_num))
#define u8x8_GetSPIBus(u8x8) ((u8x8)->spi_bus_num)
#define u8x8_SetSPIBus(u8x8, bus_num) ((u8x8)->spi_bus_num = (bus_num))
#define u8x8_GetI2CBus(u8x8) ((u8x8)->i2c_bus_num)

View File

@ -1,6 +1,9 @@
#include "u8g2port.h"
// By default, SPI bus /dev/spidev0.0 is used, as defined in port/U8g2lib.h
// GPIO chip number for character device
#define GPIO_CHIP_NUM 0
// SPI bus uses upper 4 bits and lower 4 bits, so 0x10 will be /dev/spidev1.0
#define SPI_BUS 0x10
#define OLED_SPI_PIN_RES 199
#define OLED_SPI_PIN_DC 198
@ -13,9 +16,10 @@ int main(void)
// Initialization
u8g2_Setup_ssd1306_128x64_noname_f(&u8g2, U8G2_R0, u8x8_byte_arm_linux_hw_spi, u8x8_arm_linux_gpio_and_delay);
u8g2_SetGPIOChip(&u8g2, GPIO_CHIP_NUM);
u8g2_SetSPIBus(&u8g2, SPI_BUS);
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);

View File

@ -1,5 +1,7 @@
#include "u8g2port.h"
// GPIO chip number for character device
#define GPIO_CHIP_NUM 0
#define OLED_SPI_PIN_MOSI 13
#define OLED_SPI_PIN_SCK 26
@ -15,6 +17,7 @@ int main(void)
// Initialization
u8g2_Setup_ssd1306_128x64_noname_f(&u8g2, U8G2_R0, u8x8_byte_4wire_sw_spi, u8x8_arm_linux_gpio_and_delay);
u8g2_SetGPIOChip(&u8g2, GPIO_CHIP_NUM);
u8x8_SetPin(u8g2_GetU8x8(&u8g2), U8X8_PIN_RESET, OLED_SPI_PIN_RES);
u8x8_SetPin(u8g2_GetU8x8(&u8g2), U8X8_PIN_DC, OLED_SPI_PIN_DC);
u8x8_SetPin(u8g2_GetU8x8(&u8g2), U8X8_PIN_SPI_DATA, OLED_SPI_PIN_MOSI);

View File

@ -1,11 +1,17 @@
#include <u8g2port.h>
// Set I2C bus and address
#define I2C_BUS 0
#define I2C_ADDRESS 0x3c * 2
int main(void)
{
u8g2_t u8g2;
// Initialization
u8g2_Setup_ssd1306_i2c_128x64_noname_f( &u8g2, U8G2_R0, u8x8_byte_arm_linux_hw_i2c, u8x8_arm_linux_gpio_and_delay);
u8g2_SetI2CBus(&u8g2, I2C_BUS);
u8g2_SetI2CAddress(&u8g2, I2C_ADDRESS);
u8g2_InitDisplay(&u8g2);
u8g2_SetPowerSave(&u8g2, 0);

View File

@ -1,5 +1,7 @@
#include "u8g2port.h"
// GPIO chip number for character device
#define GPIO_CHIP_NUM 0
#define OLED_I2C_PIN_SCL 20
#define OLED_I2C_PIN_SDA 21
@ -9,6 +11,7 @@ int main(void)
// Initialization
u8g2_Setup_ssd1306_i2c_128x64_noname_f( &u8g2, U8G2_R0, u8x8_byte_sw_i2c, u8x8_arm_linux_gpio_and_delay);
u8g2_SetGPIOChip(&u8g2, GPIO_CHIP_NUM);
u8x8_SetPin(u8g2_GetU8x8(&u8g2), U8X8_PIN_I2C_CLOCK, OLED_I2C_PIN_SCL);
u8x8_SetPin(u8g2_GetU8x8(&u8g2), U8X8_PIN_I2C_DATA, OLED_I2C_PIN_SDA);
u8x8_SetPin(u8g2_GetU8x8(&u8g2), U8X8_PIN_RESET, U8X8_PIN_NONE);

View File

@ -1,6 +1,9 @@
#include <U8g2lib.h>
// By default, SPI bus /dev/spidev0.0 is used, as defined in port/U8g2lib.h
// GPIO chip number for character device
#define GPIO_CHIP_NUM 0
// SPI bus uses upper 4 bits and lower 4 bits, so 0x10 will be /dev/spidev1.0
#define SPI_BUS 0x10
#define OLED_SPI_PIN_RES 199
#define OLED_SPI_PIN_DC 198
@ -16,8 +19,9 @@ static U8G2_SSD1306_128X64_NONAME_F_4W_HW_SPI u8g2(U8G2_R0,
int main()
{
u8g2.setGpioChip(GPIO_CHIP_NUM);
u8g2.setSpiBus(SPI_BUS);
u8g2.begin();
u8g2.clearBuffer(); // clear the internal memory
u8g2.setFont(u8g2_font_6x13_tr); // choose a suitable font
u8g2.drawStr(1, 18, "U8g2 on HW SPI"); // write something to the internal memory
u8g2.sendBuffer(); // transfer internal memory to the display

View File

@ -1,5 +1,7 @@
#include <U8g2lib.h>
// GPIO chip number for character device
#define GPIO_CHIP_NUM 0
#define OLED_SPI_PIN_MOSI 13
#define OLED_SPI_PIN_SCK 26
@ -18,6 +20,7 @@ static U8G2_SSD1306_128X64_NONAME_F_4W_SW_SPI u8g2(U8G2_R0,\
int main()
{
u8g2.setGpioChip(GPIO_CHIP_NUM);
u8g2.begin();
u8g2.clearBuffer(); // clear the internal memory
u8g2.setFont(u8g2_font_6x13_tr); // choose a suitable font

View File

@ -1,12 +1,16 @@
#include <U8g2lib.h>
// Set I2C bus and address
#define I2C_BUS 0
#define I2C_ADDRESS 0x3c * 2
// Check https://github.com/olikraus/u8g2/wiki/u8g2setupcpp for all supported devices
static U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
int main(void)
{
u8g2.setI2cBus(I2C_BUS);
u8g2.setI2CAddress(I2C_ADDRESS);
u8g2.begin();
u8g2.clearBuffer(); // clear the internal memory
u8g2.setFont(u8g2_font_6x13_tr); // choose a suitable font
u8g2.drawStr(1, 18, "U8g2 on HW I2C"); // write something to the internal memory
u8g2.sendBuffer(); // transfer internal memory to the display

View File

@ -1,5 +1,7 @@
#include <U8g2lib.h>
// GPIO chip number for character device
#define GPIO_CHIP_NUM 0
#define OLED_I2C_PIN_SCL 20
#define OLED_I2C_PIN_SDA 21
@ -12,6 +14,7 @@ static U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0,
int main(void)
{
u8g2.setGpioChip(GPIO_CHIP_NUM);
u8g2.begin();
u8g2.clearBuffer(); // clear the internal memory
u8g2.setFont(u8g2_font_6x13_tr); // choose a suitable font

View File

@ -69,6 +69,16 @@ class U8G2 : public Print
uint32_t getBusClock(void) { return u8g2_GetU8x8(&u8g2)->bus_clock; }
void setBusClock(uint32_t clock_speed) { u8g2_GetU8x8(&u8g2)->bus_clock = clock_speed; }
uint8_t getGpioChip(void) { return u8x8_GetGPIOChip(u8g2_GetU8x8(&u8g2)); }
void setGpioChip(uint8_t num) { u8x8_SetGPIOChip(u8g2_GetU8x8(&u8g2), num); }
uint8_t getSpiBus(void) { return u8x8_GetSPIBus(u8g2_GetU8x8(&u8g2)); }
void setSpiBus(uint8_t num) { u8x8_SetSPIBus(u8g2_GetU8x8(&u8g2), num); }
uint8_t getI2cBus(void) { return u8x8_GetI2CBus(u8g2_GetU8x8(&u8g2)); }
void setI2cBus(uint8_t num) { u8x8_SetI2CBus(u8g2_GetU8x8(&u8g2), num); }
uint8_t getI2CAddress(void) { return u8g2_GetI2CAddress(&u8g2); }
void setI2CAddress(uint8_t adr) { u8g2_SetI2CAddress(&u8g2, adr); }

View File

@ -1,26 +1,18 @@
/*
* This code is not thread safe and should be reworked to make multiple displays
* work in a thread safe way. At this point you can only have one I2C or
* SPI bus, but have multiple devices on the bus.
* This code should support multiple displays, but only one hardware bus each
* for I2C and SPI currently.
*/
#include "u8g2port.h"
// c-periphery i2c handle
static i2c_t *i2c_device;
static const char i2c_bus[] = "/dev/i2c-0";
// c-periphery I2C handle
static i2c_t *i2c_handle = NULL;
// c-periphery spi handle
static spi_t *spi_device;
static const char spi_bus[] = "/dev/spidev1.0";
// TODO: This should be 1 to 1 with pins
#if PERIPHERY_GPIO_CDEV_SUPPORT
static const char gpio_device[] = "/dev/gpiochip0";
#endif
// c-periphery SPI handle
static spi_t *spi_handle = NULL;
// c-periphery GPIO pins
gpio_t *pins[U8X8_PIN_CNT] = { };
static gpio_t *pins[U8X8_PIN_CNT] = { };
/*
* Sleep milliseconds.
@ -55,25 +47,32 @@ void sleep_ns(unsigned long nanoseconds) {
/**
* Initialize pin if not set to U8X8_PIN_NONE.
*/
#if PERIPHERY_GPIO_CDEV_SUPPORT
void init_pin(u8x8_t *u8x8, int pin) {
char filename[16];
if (u8x8->pins[pin] != U8X8_PIN_NONE) {
snprintf(filename, sizeof(filename), "/dev/gpiochip%d",
u8x8->gpio_chip_num);
pins[pin] = gpio_new();
if (gpio_open(pins[pin], filename, u8x8->pins[pin], GPIO_DIR_OUT_HIGH)
< 0) {
fprintf(stderr, "gpio_open(): pin %d, %s\n", u8x8->pins[pin],
gpio_errmsg(pins[pin]));
}
}
}
#else
void init_pin(u8x8_t *u8x8, int pin) {
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(): pin %d, %s\n", u8x8->pins[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", u8x8->pins[pin],
gpio_errmsg(pins[pin]));
}
#endif
}
}
#endif
/*
* Close and free gpio_t for all pins.
@ -83,6 +82,7 @@ void done_pins() {
if (pins[i] != NULL) {
gpio_close(pins[i]);
gpio_free(pins[i]);
pins[i] = NULL;
}
}
}
@ -91,16 +91,22 @@ void done_pins() {
* Close and free i2c_t.
*/
void done_i2c() {
i2c_close(i2c_device);
i2c_free(i2c_device);
if (i2c_handle != NULL) {
i2c_close(i2c_handle);
i2c_free(i2c_handle);
i2c_handle = NULL;
}
}
/*
* Close and free spi_t.
*/
void done_spi() {
spi_close(spi_device);
spi_free(spi_device);
if (spi_handle != NULL) {
spi_close(spi_handle);
spi_free(spi_handle);
spi_handle = NULL;
}
}
/**
@ -250,9 +256,8 @@ uint8_t u8x8_arm_linux_gpio_and_delay(u8x8_t *u8x8, uint8_t msg,
}
/*
* I2c callback. This should be reworked to make it thread safe. The static
* variables can be corrupted if more than one thread at a time accesses this
* function.
* I2c callback. The static variables can be corrupted if more than one thread
* at a time accesses this function. Calling program neds to be aware of this.
*/
uint8_t u8x8_byte_arm_linux_hw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int,
void *arg_ptr) {
@ -261,6 +266,7 @@ uint8_t u8x8_byte_arm_linux_hw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int,
static uint8_t buf_idx;
uint8_t *data;
struct i2c_msg msgs[1];
char filename[11];
switch (msg) {
case U8X8_MSG_BYTE_SEND:
@ -273,9 +279,15 @@ uint8_t u8x8_byte_arm_linux_hw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int,
break;
case U8X8_MSG_BYTE_INIT:
i2c_device = i2c_new();
if (i2c_open(i2c_device, i2c_bus) < 0) {
fprintf(stderr, "i2c_open(): %s\n", i2c_errmsg(i2c_device));
// Only open bus once
if (i2c_handle == NULL) {
snprintf(filename, sizeof(filename), "/dev/i2c-%d",
u8x8->i2c_bus_num);
i2c_handle = i2c_new();
if (i2c_open(i2c_handle, filename) < 0) {
fprintf(stderr, "i2c_open(): %s\n", i2c_errmsg(i2c_handle));
i2c_free(i2c_handle);
}
}
break;
@ -288,7 +300,7 @@ uint8_t u8x8_byte_arm_linux_hw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int,
msgs[0].flags = 0; // Write
msgs[0].len = buf_idx;
msgs[0].buf = buffer;
i2c_transfer(i2c_device, msgs, 1);
i2c_transfer(i2c_handle, msgs, 1);
break;
default:
@ -306,6 +318,7 @@ uint8_t u8x8_byte_arm_linux_hw_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int,
uint8_t buffer[128];
uint8_t buf_idx;
uint8_t *data;
char filename[15];
switch (msg) {
case U8X8_MSG_BYTE_SEND:
@ -316,20 +329,26 @@ uint8_t u8x8_byte_arm_linux_hw_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int,
data++;
arg_int--;
}
spi_transfer(spi_device, buffer, buffer, buf_idx);
spi_transfer(spi_handle, buffer, buffer, buf_idx);
break;
case U8X8_MSG_BYTE_INIT:
spi_device = spi_new();
//u8x8_gpio_SetCS(u8x8, u8x8->display_info->chip_disable_level);
/* SPI mode has to be mapped to the mode of the current controller, at least Uno, Due, 101 have different SPI_MODEx values */
/* 0: clock active high, data out on falling edge, clock default value is zero, takover on rising edge */
/* 1: clock active high, data out on rising edge, clock default value is zero, takover on falling edge */
/* 2: clock active low, data out on rising edge */
/* 3: clock active low, data out on falling edge */
if (spi_open(spi_device, spi_bus, u8x8->display_info->spi_mode, 500000)
< 0) {
fprintf(stderr, "spi_open(): %s\n", spi_errmsg(spi_device));
// Only open bus once
if (spi_handle == NULL) {
// spi_bus_num should be in the format 0x12 for /dev/spidev1.2
snprintf(filename, sizeof(filename), "/dev/spidev%d.%d",
u8x8->spi_bus_num >> 4, u8x8->spi_bus_num & 0x0f);
spi_handle = spi_new();
//u8x8_gpio_SetCS(u8x8, u8x8->display_info->chip_disable_level);
/* SPI mode has to be mapped to the mode of the current controller, at least Uno, Due, 101 have different SPI_MODEx values */
/* 0: clock active high, data out on falling edge, clock default value is zero, takover on rising edge */
/* 1: clock active high, data out on rising edge, clock default value is zero, takover on falling edge */
/* 2: clock active low, data out on rising edge */
/* 3: clock active low, data out on falling edge */
if (spi_open(spi_handle, filename, u8x8->display_info->spi_mode,
500000) < 0) {
fprintf(stderr, "spi_open(): %s\n", spi_errmsg(spi_handle));
}
}
break;