I2C refactored to c-periphery

This commit is contained in:
servadmin 2021-11-02 19:50:04 -04:00
parent a7b8883bc3
commit 45df3148b0
7 changed files with 244 additions and 77 deletions

View File

@ -1,5 +1,3 @@
![Title](images/title.png)
[U8g2 for arm-linux](https://github.com/wuhanstudio/u8g2-arm-linux) has been modified to use [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. [c-periphery](https://github.com/vsergeev/c-periphery) userspace library.
* Deprecated sysfs method is no longer used for GPIO thus increasing speed and stability. * Deprecated sysfs method is no longer used for GPIO thus increasing speed and stability.

View File

@ -1,58 +1,136 @@
/*
* c-periphery
* https://github.com/vsergeev/c-periphery
* License: MIT
*/
#include <stddef.h>
#include <stdint.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include "i2c.h" #include "i2c.h"
int openI2CDevice(const char* device) struct i2c_handle {
{ int fd;
int i2c_fd;
char filename[40]; struct {
sprintf(filename, device); int c_errno;
if ((i2c_fd = open(filename,O_RDWR)) < 0) char errmsg[96];
{ } error;
printf("Failed to open the bus."); };
/* ERROR HANDLING; you can check errno to see what went wrong */
return -1; static int _i2c_error(i2c_t *i2c, int code, int c_errno, const char *fmt, ...) {
} va_list ap;
return i2c_fd;
i2c->error.c_errno = c_errno;
va_start(ap, fmt);
vsnprintf(i2c->error.errmsg, sizeof(i2c->error.errmsg), fmt, ap);
va_end(ap);
/* Tack on strerror() and errno */
if (c_errno) {
char buf[64];
strerror_r(c_errno, buf, sizeof(buf));
snprintf(i2c->error.errmsg+strlen(i2c->error.errmsg), sizeof(i2c->error.errmsg)-strlen(i2c->error.errmsg), ": %s [errno %d]", buf, c_errno);
} }
void setI2CSlave(int i2c_fd,int addr) return code;
{
if (ioctl(i2c_fd, I2C_SLAVE, addr) < 0)
{
printf("Failed to acquire bus access and/or talk to slave.\n");
/* ERROR HANDLING; you can check errno to see what went wrong */
// exit(1);
}
} }
void I2CWriteBytes(int i2c_fd, uint8_t* data, uint8_t length) i2c_t *i2c_new(void) {
{ i2c_t *i2c = calloc(1, sizeof(i2c_t));
if (write(i2c_fd, data, length) != length) if (i2c == NULL)
{ return NULL;
/* ERROR HANDLING: i2c transaction failed */
printf("Failed to write to the i2c bus.\n"); i2c->fd = -1;
}
return i2c;
} }
void sleep_ms(unsigned long milliseconds) void i2c_free(i2c_t *i2c) {
{ free(i2c);
struct timespec ts;
ts.tv_sec = milliseconds / 1000;
ts.tv_nsec = (milliseconds % 1000) * 1000000;
nanosleep(&ts, NULL);
} }
void sleep_us(unsigned long microseconds) int i2c_open(i2c_t *i2c, const char *path) {
{ unsigned long supported_funcs;
struct timespec ts;
ts.tv_sec = microseconds / 1000 / 1000; memset(i2c, 0, sizeof(i2c_t));
ts.tv_nsec = (microseconds % 1000000) * 1000;
nanosleep(&ts, NULL); /* Open device */
if ((i2c->fd = open(path, O_RDWR)) < 0)
return _i2c_error(i2c, I2C_ERROR_OPEN, errno, "Opening I2C device \"%s\"", path);
/* Query supported functions */
if (ioctl(i2c->fd, I2C_FUNCS, &supported_funcs) < 0) {
int errsv = errno;
close(i2c->fd);
i2c->fd = -1;
return _i2c_error(i2c, I2C_ERROR_QUERY, errsv, "Querying I2C functions");
} }
void sleep_ns(unsigned long nanoseconds) if (!(supported_funcs & I2C_FUNC_I2C)) {
{ close(i2c->fd);
struct timespec ts; i2c->fd = -1;
ts.tv_sec = 0; return _i2c_error(i2c, I2C_ERROR_NOT_SUPPORTED, 0, "I2C not supported on %s", path);
ts.tv_nsec = nanoseconds;
nanosleep(&ts, NULL);
} }
return 0;
}
int i2c_transfer(i2c_t *i2c, struct i2c_msg *msgs, size_t count) {
struct i2c_rdwr_ioctl_data i2c_rdwr_data;
/* Prepare I2C transfer structure */
memset(&i2c_rdwr_data, 0, sizeof(struct i2c_rdwr_ioctl_data));
i2c_rdwr_data.msgs = msgs;
i2c_rdwr_data.nmsgs = count;
/* Transfer */
if (ioctl(i2c->fd, I2C_RDWR, &i2c_rdwr_data) < 0)
return _i2c_error(i2c, I2C_ERROR_TRANSFER, errno, "I2C transfer");
return 0;
}
int i2c_close(i2c_t *i2c) {
if (i2c->fd < 0)
return 0;
/* Close fd */
if (close(i2c->fd) < 0)
return _i2c_error(i2c, I2C_ERROR_CLOSE, errno, "Closing I2C device");
i2c->fd = -1;
return 0;
}
int i2c_tostring(i2c_t *i2c, char *str, size_t len) {
return snprintf(str, len, "I2C (fd=%d)", i2c->fd);
}
const char *i2c_errmsg(i2c_t *i2c) {
return i2c->error.errmsg;
}
int i2c_errno(i2c_t *i2c) {
return i2c->error.c_errno;
}
int i2c_fd(i2c_t *i2c) {
return i2c->fd;
}

View File

@ -1,21 +1,70 @@
#ifndef I2C_H /*
#define I2C_H * c-periphery
* https://github.com/vsergeev/c-periphery
* License: MIT
*/
#include <linux/i2c-dev.h> #ifndef _PERIPHERY_I2C_H
#include <stdio.h> #define _PERIPHERY_I2C_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <unistd.h> #include <limits.h>
#include <time.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <fcntl.h>
int openI2CDevice(const char* device); #include <linux/i2c.h>
void setI2CSlave(int i2c_fd,int addr); #include <linux/i2c-dev.h>
void I2CWriteBytes(int i2c_fd, uint8_t* data, uint8_t length);
void sleep_ms(unsigned long milliseconds); enum i2c_error_code {
void sleep_us(unsigned long microseconds); I2C_ERROR_ARG = -1, /* Invalid arguments */
void sleep_ns(unsigned long nanoseconds); I2C_ERROR_OPEN = -2, /* Opening I2C device */
I2C_ERROR_QUERY = -3, /* Querying I2C device attributes */
I2C_ERROR_NOT_SUPPORTED = -4, /* I2C not supported on this device */
I2C_ERROR_TRANSFER = -5, /* I2C transfer */
I2C_ERROR_CLOSE = -6, /* Closing I2C device */
};
typedef struct i2c_handle i2c_t;
/* Primary Functions */
i2c_t *i2c_new(void);
int i2c_open(i2c_t *i2c, const char *path);
int i2c_transfer(i2c_t *i2c, struct i2c_msg *msgs, size_t count);
int i2c_close(i2c_t *i2c);
void i2c_free(i2c_t *i2c);
/* Miscellaneous */
int i2c_fd(i2c_t *i2c);
int i2c_tostring(i2c_t *i2c, char *str, size_t len);
/* Error Handling */
int i2c_errno(i2c_t *i2c);
const char *i2c_errmsg(i2c_t *i2c);
/* struct i2c_msg from <linux/i2c.h>:
struct i2c_msg {
__u16 addr;
__u16 flags;
#define I2C_M_TEN 0x0010
#define I2C_M_RD 0x0001
#define I2C_M_STOP 0x8000
#define I2C_M_NOSTART 0x4000
#define I2C_M_REV_DIR_ADDR 0x2000
#define I2C_M_IGNORE_NAK 0x1000
#define I2C_M_NO_RD_ACK 0x0800
#define I2C_M_RECV_LEN 0x0400
__u16 len;
__u8 *buf;
};
*/
#ifdef __cplusplus
}
#endif
#endif #endif

View File

@ -2,8 +2,8 @@
#include "u8g2port.h" #include "u8g2port.h"
// By default, SPI bus /dev/spidev0.0 is used, as defined in port/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_RES 199
#define OLED_SPI_PIN_DC 24 #define OLED_SPI_PIN_DC 198
// CS pin is controlled by linux spi driver, thus not defined here, but need to be wired // CS pin is controlled by linux spi driver, thus not defined here, but need to be wired
// #define OLED_SPI_PIN_CS 8 // #define OLED_SPI_PIN_CS 8

View File

@ -23,6 +23,8 @@ int main(void)
u8g2_SendBuffer(&u8g2); u8g2_SendBuffer(&u8g2);
printf("Initialized ...\n"); printf("Initialized ...\n");
sleep_ms(5000);
u8g2_SetPowerSave(&u8g2, 1);
return 0; return 0;
} }

View File

@ -1,16 +1,42 @@
#include "u8g2port.h" #include "u8g2port.h"
static int i2c_device; static i2c_t *i2c_device;
static const char i2c_bus[] = "/dev/i2c-1"; static const char i2c_bus[] = "/dev/i2c-0";
static int spi_device; static int spi_device;
static const char spi_bus[] = "/dev/spidev0.0"; static const char spi_bus[] = "/dev/spidev1.0";
#if PERIPHERY_GPIO_CDEV_SUPPORT
static const char gpio_device[] = "/dev/gpiochip0"; static const char gpio_device[] = "/dev/gpiochip0";
#endif
// c-periphery GPIO pins // c-periphery GPIO pins
gpio_t *pins[U8X8_PIN_CNT] = { }; gpio_t *pins[U8X8_PIN_CNT] = { };
void sleep_ms(unsigned long milliseconds)
{
struct timespec ts;
ts.tv_sec = milliseconds / 1000;
ts.tv_nsec = (milliseconds % 1000) * 1000000;
nanosleep(&ts, NULL);
}
void sleep_us(unsigned long microseconds)
{
struct timespec ts;
ts.tv_sec = microseconds / 1000 / 1000;
ts.tv_nsec = (microseconds % 1000000) * 1000;
nanosleep(&ts, NULL);
}
void sleep_ns(unsigned long nanoseconds)
{
struct timespec ts;
ts.tv_sec = 0;
ts.tv_nsec = nanoseconds;
nanosleep(&ts, NULL);
}
/** /**
* Initialize pin if not set to U8X8_PIN_NONE. * Initialize pin if not set to U8X8_PIN_NONE.
*/ */
@ -21,13 +47,13 @@ void init_pin(u8x8_t *u8x8, int pin) {
#if PERIPHERY_GPIO_CDEV_SUPPORT #if PERIPHERY_GPIO_CDEV_SUPPORT
if (gpio_open(pins[pin], gpio_device, u8x8->pins[pin], GPIO_DIR_OUT_HIGH) if (gpio_open(pins[pin], gpio_device, u8x8->pins[pin], GPIO_DIR_OUT_HIGH)
< 0) { < 0) {
fprintf(stderr, "gpio_open(): pin %d, %s\n", pin, gpio_errmsg(pins[pin])); fprintf(stderr, "gpio_open(): pin %d, %s\n", u8x8->pins[pin], gpio_errmsg(pins[pin]));
} }
// Support deprecated sysfs // Support deprecated sysfs
#else #else
if (gpio_open_sysfs(pins[pin], u8x8->pins[pin], GPIO_DIR_OUT_HIGH) if (gpio_open_sysfs(pins[pin], u8x8->pins[pin], GPIO_DIR_OUT_HIGH)
< 0) { < 0) {
fprintf(stderr, "gpio_open_sysfs(): pin %d, %s\n", pin, fprintf(stderr, "gpio_open_sysfs(): pin %d, %s\n", u8x8->pins[pin],
gpio_errmsg(pins[pin])); gpio_errmsg(pins[pin]));
} }
#endif #endif
@ -197,7 +223,9 @@ uint8_t u8x8_byte_arm_linux_hw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int,
/* u8g2/u8x8 will never send more than 32 bytes between START_TRANSFER and END_TRANSFER */ /* u8g2/u8x8 will never send more than 32 bytes between START_TRANSFER and END_TRANSFER */
static uint8_t buffer[32]; static uint8_t buffer[32];
static uint8_t buf_idx; static uint8_t buf_idx;
static uint8_t addr;
uint8_t *data; uint8_t *data;
struct i2c_msg msgs[1];
switch (msg) { switch (msg) {
case U8X8_MSG_BYTE_SEND: case U8X8_MSG_BYTE_SEND:
@ -210,18 +238,23 @@ uint8_t u8x8_byte_arm_linux_hw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int,
break; break;
case U8X8_MSG_BYTE_INIT: case U8X8_MSG_BYTE_INIT:
i2c_device = openI2CDevice(i2c_bus); i2c_device = i2c_new();
// printf("I2C File Descriptor: %d\n", fd); if (i2c_open(i2c_device, i2c_bus) < 0) {
fprintf(stderr, "i2c_open(): %s\n", i2c_errmsg(i2c_device));
}
addr = u8x8_GetI2CAddress(u8x8) >> 1;
break; break;
case U8X8_MSG_BYTE_START_TRANSFER: case U8X8_MSG_BYTE_START_TRANSFER:
setI2CSlave(i2c_device, u8x8_GetI2CAddress(u8x8) >> 1);
buf_idx = 0; buf_idx = 0;
// printf("I2C Address: %02x\n", u8x8_GetI2CAddress(u8x8)>>1);
break; break;
case U8X8_MSG_BYTE_END_TRANSFER: case U8X8_MSG_BYTE_END_TRANSFER:
I2CWriteBytes(i2c_device, buffer, buf_idx); msgs[0].addr = addr;
msgs[0].flags = 0; /* Write */
msgs[0].len = buf_idx;
msgs[0].buf = buffer;
i2c_transfer(i2c_device, msgs, 1);
break; break;
default: default:

View File

@ -9,13 +9,20 @@
#include "gpio.h" #include "gpio.h"
#include "i2c.h" #include "i2c.h"
#include "spi.h" #include "spi.h"
#include <time.h>
void sleep_ms(unsigned long milliseconds);
void sleep_us(unsigned long microseconds);
void sleep_ns(unsigned long nanoseconds);
void init_pin(u8x8_t *u8x8, int pin); void init_pin(u8x8_t *u8x8, int pin);
void done_pins(); void done_pins();
void write_pin(u8x8_t *u8x8, int pin, int value); 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_arm_linux_gpio_and_delay(u8x8_t *u8x8, uint8_t msg,
uint8_t u8x8_byte_arm_linux_hw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr); 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); 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);
#ifdef __cplusplus #ifdef __cplusplus
} }