I2C refactored to c-periphery
This commit is contained in:
parent
a7b8883bc3
commit
45df3148b0
|
@ -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.
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue