SPI working
This commit is contained in:
parent
45df3148b0
commit
97112c03b3
|
@ -1,8 +1,8 @@
|
|||
[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.
|
||||
* Deprecated sysfs method is no longer used for GPIO thus increasing speed and stability, but you can still use sysfs for legacy kernels.
|
||||
* GPIO, I2C and SPI can be closed and unallocated.
|
||||
* Overall performance should be better.
|
||||
|
||||
## Download U8g2 project
|
||||
* `cd ~/`
|
||||
|
|
|
@ -1,85 +1,404 @@
|
|||
/*
|
||||
* 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 <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/spi/spidev.h>
|
||||
|
||||
#include "spi.h"
|
||||
|
||||
void pabort(const char *s)
|
||||
{
|
||||
perror(s);
|
||||
abort();
|
||||
struct spi_handle {
|
||||
int fd;
|
||||
|
||||
struct {
|
||||
int c_errno;
|
||||
char errmsg[96];
|
||||
} error;
|
||||
};
|
||||
|
||||
static int _spi_error(spi_t *spi, int code, int c_errno, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
|
||||
spi->error.c_errno = c_errno;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(spi->error.errmsg, sizeof(spi->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(spi->error.errmsg+strlen(spi->error.errmsg), sizeof(spi->error.errmsg)-strlen(spi->error.errmsg), ": %s [errno %d]", buf, c_errno);
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
int openSPIDevice(const char* device, uint8_t mode, uint8_t bits, uint32_t speed)
|
||||
{
|
||||
int ret;
|
||||
int fd = open(device, O_RDWR);
|
||||
if (fd < 0)
|
||||
{
|
||||
pabort("can't open device");
|
||||
}
|
||||
spi_t *spi_new(void) {
|
||||
spi_t *spi = calloc(1, sizeof(spi_t));
|
||||
if (spi == NULL)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* spi mode
|
||||
*/
|
||||
ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
|
||||
if (ret == -1)
|
||||
{
|
||||
pabort("can't set spi mode");
|
||||
}
|
||||
spi->fd = -1;
|
||||
|
||||
ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
|
||||
if (ret == -1)
|
||||
{
|
||||
pabort("can't get spi mode");
|
||||
}
|
||||
|
||||
/*
|
||||
* bits per word
|
||||
*/
|
||||
ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
|
||||
if (ret == -1)
|
||||
{
|
||||
pabort("can't set bits per word");
|
||||
}
|
||||
|
||||
ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
|
||||
if (ret == -1)
|
||||
{
|
||||
pabort("can't get bits per word");
|
||||
}
|
||||
|
||||
/*
|
||||
* max speed hz
|
||||
*/
|
||||
ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
|
||||
if (ret == -1)
|
||||
{
|
||||
pabort("can't set max speed hz");
|
||||
}
|
||||
|
||||
ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
|
||||
if (ret == -1)
|
||||
{
|
||||
pabort("can't get max speed hz");
|
||||
}
|
||||
|
||||
// printf("spi mode: %d\n", mode);
|
||||
// printf("bits per word: %d\n", bits);
|
||||
// printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000);
|
||||
|
||||
return fd;
|
||||
return spi;
|
||||
}
|
||||
|
||||
int SPITransfer(int fd, struct spi_ioc_transfer* tr)
|
||||
{
|
||||
int ret;
|
||||
ret = ioctl(fd, SPI_IOC_MESSAGE(1), tr);
|
||||
if (ret < 1)
|
||||
{
|
||||
pabort("can't send spi message");
|
||||
void spi_free(spi_t *spi) {
|
||||
free(spi);
|
||||
}
|
||||
|
||||
int spi_open(spi_t *spi, const char *path, unsigned int mode, uint32_t max_speed) {
|
||||
return spi_open_advanced(spi, path, mode, max_speed, MSB_FIRST, 8, 0);
|
||||
}
|
||||
|
||||
int spi_open_advanced(spi_t *spi, const char *path, unsigned int mode, uint32_t max_speed, spi_bit_order_t bit_order, uint8_t bits_per_word, uint8_t extra_flags) {
|
||||
return spi_open_advanced2(spi, path, mode, max_speed, bit_order, bits_per_word, extra_flags);
|
||||
}
|
||||
|
||||
int spi_open_advanced2(spi_t *spi, const char *path, unsigned int mode, uint32_t max_speed, spi_bit_order_t bit_order, uint8_t bits_per_word, uint32_t extra_flags) {
|
||||
uint32_t data32;
|
||||
uint8_t data8;
|
||||
|
||||
/* Validate arguments */
|
||||
if (mode & ~0x3)
|
||||
return _spi_error(spi, SPI_ERROR_ARG, 0, "Invalid mode (can be 0,1,2,3)");
|
||||
if (bit_order != MSB_FIRST && bit_order != LSB_FIRST)
|
||||
return _spi_error(spi, SPI_ERROR_ARG, 0, "Invalid bit order (can be MSB_FIRST,LSB_FIRST)");
|
||||
#ifndef SPI_IOC_WR_MODE32
|
||||
if (extra_flags > 0xff)
|
||||
return _spi_error(spi, SPI_ERROR_UNSUPPORTED, 0, "Kernel version does not support 32-bit SPI mode flags");
|
||||
#endif
|
||||
|
||||
memset(spi, 0, sizeof(spi_t));
|
||||
|
||||
/* Open device */
|
||||
if ((spi->fd = open(path, O_RDWR)) < 0)
|
||||
return _spi_error(spi, SPI_ERROR_OPEN, errno, "Opening SPI device \"%s\"", path);
|
||||
|
||||
/* Set mode, bit order, extra flags */
|
||||
#ifndef SPI_IOC_WR_MODE32
|
||||
(void)data32;
|
||||
|
||||
data8 = mode | ((bit_order == LSB_FIRST) ? SPI_LSB_FIRST : 0) | extra_flags;
|
||||
if (ioctl(spi->fd, SPI_IOC_WR_MODE, &data8) < 0) {
|
||||
int errsv = errno;
|
||||
close(spi->fd);
|
||||
spi->fd = -1;
|
||||
return _spi_error(spi, SPI_ERROR_CONFIGURE, errsv, "Setting SPI mode");
|
||||
}
|
||||
#else
|
||||
if (extra_flags > 0xff) {
|
||||
/* Use 32-bit mode if extra_flags is wider than 8-bits */
|
||||
data32 = mode | ((bit_order == LSB_FIRST) ? SPI_LSB_FIRST : 0) | extra_flags;
|
||||
if (ioctl(spi->fd, SPI_IOC_WR_MODE32, &data32) < 0) {
|
||||
int errsv = errno;
|
||||
close(spi->fd);
|
||||
spi->fd = -1;
|
||||
return _spi_error(spi, SPI_ERROR_CONFIGURE, errsv, "Setting SPI mode");
|
||||
}
|
||||
} else {
|
||||
/* Prefer 8-bit mode, in case this library is inadvertently used on an
|
||||
* older kernel. */
|
||||
data8 = mode | ((bit_order == LSB_FIRST) ? SPI_LSB_FIRST : 0) | extra_flags;
|
||||
if (ioctl(spi->fd, SPI_IOC_WR_MODE, &data8) < 0) {
|
||||
int errsv = errno;
|
||||
close(spi->fd);
|
||||
spi->fd = -1;
|
||||
return _spi_error(spi, SPI_ERROR_CONFIGURE, errsv, "Setting SPI mode");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Set max speed */
|
||||
if (ioctl(spi->fd, SPI_IOC_WR_MAX_SPEED_HZ, &max_speed) < 0) {
|
||||
int errsv = errno;
|
||||
close(spi->fd);
|
||||
spi->fd = -1;
|
||||
return _spi_error(spi, SPI_ERROR_CONFIGURE, errsv, "Setting SPI max speed");
|
||||
}
|
||||
|
||||
/* Set bits per word */
|
||||
if (ioctl(spi->fd, SPI_IOC_WR_BITS_PER_WORD, &bits_per_word) < 0) {
|
||||
int errsv = errno;
|
||||
close(spi->fd);
|
||||
spi->fd = -1;
|
||||
return _spi_error(spi, SPI_ERROR_CONFIGURE, errsv, "Setting SPI bits per word");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void closeSPIDevice(int fd)
|
||||
{
|
||||
close(fd);
|
||||
int spi_transfer(spi_t *spi, const uint8_t *txbuf, uint8_t *rxbuf, size_t len) {
|
||||
struct spi_ioc_transfer spi_xfer;
|
||||
|
||||
/* Prepare SPI transfer structure */
|
||||
memset(&spi_xfer, 0, sizeof(struct spi_ioc_transfer));
|
||||
spi_xfer.tx_buf = (uintptr_t)txbuf;
|
||||
spi_xfer.rx_buf = (uintptr_t)rxbuf;
|
||||
spi_xfer.len = len;
|
||||
spi_xfer.delay_usecs = 0;
|
||||
spi_xfer.speed_hz = 0;
|
||||
spi_xfer.bits_per_word = 0;
|
||||
spi_xfer.cs_change = 0;
|
||||
|
||||
/* Transfer */
|
||||
if (ioctl(spi->fd, SPI_IOC_MESSAGE(1), &spi_xfer) < 1)
|
||||
return _spi_error(spi, SPI_ERROR_TRANSFER, errno, "SPI transfer");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spi_close(spi_t *spi) {
|
||||
if (spi->fd < 0)
|
||||
return 0;
|
||||
|
||||
/* Close fd */
|
||||
if (close(spi->fd) < 0)
|
||||
return _spi_error(spi, SPI_ERROR_CLOSE, errno, "Closing SPI device");
|
||||
|
||||
spi->fd = -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spi_get_mode(spi_t *spi, unsigned int *mode) {
|
||||
uint8_t data8;
|
||||
|
||||
if (ioctl(spi->fd, SPI_IOC_RD_MODE, &data8) < 0)
|
||||
return _spi_error(spi, SPI_ERROR_QUERY, errno, "Getting SPI mode");
|
||||
|
||||
*mode = data8 & (SPI_CPHA | SPI_CPOL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spi_get_max_speed(spi_t *spi, uint32_t *max_speed) {
|
||||
uint32_t data32;
|
||||
|
||||
if (ioctl(spi->fd, SPI_IOC_RD_MAX_SPEED_HZ, &data32) < 0)
|
||||
return _spi_error(spi, SPI_ERROR_QUERY, errno, "Getting SPI max speed");
|
||||
|
||||
*max_speed = data32;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spi_get_bit_order(spi_t *spi, spi_bit_order_t *bit_order) {
|
||||
uint8_t data8;
|
||||
|
||||
if (ioctl(spi->fd, SPI_IOC_RD_LSB_FIRST, &data8) < 0)
|
||||
return _spi_error(spi, SPI_ERROR_QUERY, errno, "Getting SPI bit order");
|
||||
|
||||
if (data8)
|
||||
*bit_order = LSB_FIRST;
|
||||
else
|
||||
*bit_order = MSB_FIRST;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spi_get_bits_per_word(spi_t *spi, uint8_t *bits_per_word) {
|
||||
uint8_t data8;
|
||||
|
||||
if (ioctl(spi->fd, SPI_IOC_RD_BITS_PER_WORD, &data8) < 0)
|
||||
return _spi_error(spi, SPI_ERROR_QUERY, errno, "Getting SPI bits per word");
|
||||
|
||||
*bits_per_word = data8;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spi_get_extra_flags(spi_t *spi, uint8_t *extra_flags) {
|
||||
uint8_t data8;
|
||||
|
||||
if (ioctl(spi->fd, SPI_IOC_RD_MODE, &data8) < 0)
|
||||
return _spi_error(spi, SPI_ERROR_QUERY, errno, "Getting SPI mode flags");
|
||||
|
||||
/* Extra mode flags without mode 0-3 and bit order */
|
||||
*extra_flags = data8 & ~( SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spi_get_extra_flags32(spi_t *spi, uint32_t *extra_flags) {
|
||||
#ifdef SPI_IOC_RD_MODE32
|
||||
uint32_t mode32;
|
||||
|
||||
if (ioctl(spi->fd, SPI_IOC_RD_MODE32, &mode32) < 0)
|
||||
return _spi_error(spi, SPI_ERROR_QUERY, errno, "Getting 32-bit SPI mode flags");
|
||||
|
||||
/* Extra mode flags without mode 0-3 and bit order */
|
||||
*extra_flags = mode32 & ~(SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST);
|
||||
|
||||
return 0;
|
||||
#else
|
||||
(void)extra_flags;
|
||||
|
||||
return _spi_error(spi, SPI_ERROR_UNSUPPORTED, 0, "Kernel version does not support 32-bit SPI mode flags");
|
||||
#endif
|
||||
}
|
||||
|
||||
int spi_set_mode(spi_t *spi, unsigned int mode) {
|
||||
uint8_t data8;
|
||||
|
||||
if (mode & ~0x3)
|
||||
return _spi_error(spi, SPI_ERROR_ARG, 0, "Invalid mode (can be 0,1,2,3)");
|
||||
|
||||
if (ioctl(spi->fd, SPI_IOC_RD_MODE, &data8) < 0)
|
||||
return _spi_error(spi, SPI_ERROR_QUERY, errno, "Getting SPI mode");
|
||||
|
||||
data8 &= ~(SPI_CPOL | SPI_CPHA);
|
||||
data8 |= mode;
|
||||
|
||||
if (ioctl(spi->fd, SPI_IOC_WR_MODE, &data8) < 0)
|
||||
return _spi_error(spi, SPI_ERROR_CONFIGURE, errno, "Setting SPI mode");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spi_set_bit_order(spi_t *spi, spi_bit_order_t bit_order) {
|
||||
uint8_t data8;
|
||||
|
||||
if (bit_order != MSB_FIRST && bit_order != LSB_FIRST)
|
||||
return _spi_error(spi, SPI_ERROR_ARG, 0, "Invalid bit order (can be MSB_FIRST,LSB_FIRST)");
|
||||
|
||||
if (bit_order == LSB_FIRST)
|
||||
data8 = 1;
|
||||
else
|
||||
data8 = 0;
|
||||
|
||||
if (ioctl(spi->fd, SPI_IOC_WR_LSB_FIRST, &data8) < 0)
|
||||
return _spi_error(spi, SPI_ERROR_CONFIGURE, errno, "Setting SPI bit order");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spi_set_extra_flags(spi_t *spi, uint8_t extra_flags) {
|
||||
uint8_t data8;
|
||||
|
||||
if (ioctl(spi->fd, SPI_IOC_RD_MODE, &data8) < 0)
|
||||
return _spi_error(spi, SPI_ERROR_QUERY, errno, "Getting SPI mode flags");
|
||||
|
||||
/* Keep mode 0-3 and bit order */
|
||||
data8 &= (SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST);
|
||||
/* Set extra flags */
|
||||
data8 |= extra_flags;
|
||||
|
||||
if (ioctl(spi->fd, SPI_IOC_WR_MODE, &data8) < 0)
|
||||
return _spi_error(spi, SPI_ERROR_CONFIGURE, errno, "Setting SPI mode flags");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spi_set_extra_flags32(spi_t *spi, uint32_t extra_flags) {
|
||||
#ifdef SPI_IOC_WR_MODE32
|
||||
uint32_t mode32;
|
||||
|
||||
if (ioctl(spi->fd, SPI_IOC_RD_MODE32, &mode32) < 0)
|
||||
return _spi_error(spi, SPI_ERROR_QUERY, errno, "Getting 32-bit SPI mode flags");
|
||||
|
||||
/* Keep mode 0-3 and bit order */
|
||||
mode32 &= (SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST);
|
||||
/* Set extra flags */
|
||||
mode32 |= extra_flags;
|
||||
|
||||
if (ioctl(spi->fd, SPI_IOC_WR_MODE32, &mode32) < 0)
|
||||
return _spi_error(spi, SPI_ERROR_CONFIGURE, errno, "Setting 32-bit SPI mode flags");
|
||||
|
||||
return 0;
|
||||
#else
|
||||
(void)extra_flags;
|
||||
|
||||
return _spi_error(spi, SPI_ERROR_UNSUPPORTED, 0, "Kernel version does not support 32-bit SPI mode flags");
|
||||
#endif
|
||||
}
|
||||
|
||||
int spi_set_max_speed(spi_t *spi, uint32_t max_speed) {
|
||||
|
||||
if (ioctl(spi->fd, SPI_IOC_WR_MAX_SPEED_HZ, &max_speed) < 0)
|
||||
return _spi_error(spi, SPI_ERROR_CONFIGURE, errno, "Setting SPI max speed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spi_set_bits_per_word(spi_t *spi, uint8_t bits_per_word) {
|
||||
|
||||
if (ioctl(spi->fd, SPI_IOC_WR_BITS_PER_WORD, &bits_per_word) < 0)
|
||||
return _spi_error(spi, SPI_ERROR_CONFIGURE, errno, "Setting SPI bits per word");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spi_tostring(spi_t *spi, char *str, size_t len) {
|
||||
unsigned int mode;
|
||||
char mode_str[2];
|
||||
uint32_t max_speed;
|
||||
char max_speed_str[16];
|
||||
uint8_t bits_per_word;
|
||||
char bits_per_word_str[4];
|
||||
spi_bit_order_t bit_order;
|
||||
const char *bit_order_str;
|
||||
uint8_t extra_flags8;
|
||||
uint32_t extra_flags32;
|
||||
char extra_flags_str[11];
|
||||
|
||||
if (spi_get_mode(spi, &mode) < 0)
|
||||
strcpy(mode_str, "?");
|
||||
else
|
||||
snprintf(mode_str, sizeof(mode_str), "%u", mode);
|
||||
|
||||
if (spi_get_max_speed(spi, &max_speed) < 0)
|
||||
strcpy(max_speed_str, "?");
|
||||
else
|
||||
snprintf(max_speed_str, sizeof(max_speed_str), "%u", max_speed);
|
||||
|
||||
if (spi_get_bit_order(spi, &bit_order) < 0)
|
||||
bit_order_str = "?";
|
||||
else
|
||||
bit_order_str = (bit_order == LSB_FIRST) ? "LSB_FIRST" : "MSB_FIRST";
|
||||
|
||||
if (spi_get_bits_per_word(spi, &bits_per_word) < 0)
|
||||
strcpy(bits_per_word_str, "?");
|
||||
else
|
||||
snprintf(bits_per_word_str, sizeof(bits_per_word_str), "%u", bits_per_word);
|
||||
|
||||
if (spi_get_extra_flags32(spi, &extra_flags32) < 0) {
|
||||
if (spi_get_extra_flags(spi, &extra_flags8) < 0)
|
||||
strcpy(extra_flags_str, "?");
|
||||
else
|
||||
snprintf(extra_flags_str, sizeof(extra_flags_str), "0x%02x", extra_flags8);
|
||||
} else {
|
||||
snprintf(extra_flags_str, sizeof(extra_flags_str), "0x%08x", extra_flags32);
|
||||
}
|
||||
|
||||
return snprintf(str, len, "SPI (fd=%d, mode=%s, max_speed=%s, bit_order=%s, bits_per_word=%s, extra_flags=%s)", spi->fd, mode_str, max_speed_str, bit_order_str, bits_per_word_str, extra_flags_str);
|
||||
}
|
||||
|
||||
const char *spi_errmsg(spi_t *spi) {
|
||||
return spi->error.errmsg;
|
||||
}
|
||||
|
||||
int spi_errno(spi_t *spi) {
|
||||
return spi->error.c_errno;
|
||||
}
|
||||
|
||||
int spi_fd(spi_t *spi) {
|
||||
return spi->fd;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,20 +1,77 @@
|
|||
#ifndef SPI_H
|
||||
#define SPI_H
|
||||
/*
|
||||
* c-periphery
|
||||
* https://github.com/vsergeev/c-periphery
|
||||
* License: MIT
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#ifndef _PERIPHERY_SPI_H
|
||||
#define _PERIPHERY_SPI_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/spi/spidev.h>
|
||||
|
||||
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
|
||||
enum spi_error_code {
|
||||
SPI_ERROR_ARG = -1, /* Invalid arguments */
|
||||
SPI_ERROR_OPEN = -2, /* Opening SPI device */
|
||||
SPI_ERROR_QUERY = -3, /* Querying SPI device attributes */
|
||||
SPI_ERROR_CONFIGURE = -4, /* Configuring SPI device attributes */
|
||||
SPI_ERROR_TRANSFER = -5, /* SPI transfer */
|
||||
SPI_ERROR_CLOSE = -6, /* Closing SPI device */
|
||||
SPI_ERROR_UNSUPPORTED = -7, /* Unsupported attribute or operation */
|
||||
};
|
||||
|
||||
void pabort(const char *s);
|
||||
typedef enum spi_bit_order {
|
||||
MSB_FIRST,
|
||||
LSB_FIRST,
|
||||
} spi_bit_order_t;
|
||||
|
||||
int openSPIDevice(const char* device, uint8_t mode, uint8_t bits, uint32_t speed);
|
||||
int SPITransfer(int fd, struct spi_ioc_transfer* tr);
|
||||
void closeSPIDevice(int fd);
|
||||
typedef struct spi_handle spi_t;
|
||||
|
||||
/* Primary Functions */
|
||||
spi_t *spi_new(void);
|
||||
int spi_open(spi_t *spi, const char *path, unsigned int mode,
|
||||
uint32_t max_speed);
|
||||
int spi_open_advanced(spi_t *spi, const char *path, unsigned int mode,
|
||||
uint32_t max_speed, spi_bit_order_t bit_order,
|
||||
uint8_t bits_per_word, uint8_t extra_flags);
|
||||
int spi_open_advanced2(spi_t *spi, const char *path, unsigned int mode,
|
||||
uint32_t max_speed, spi_bit_order_t bit_order,
|
||||
uint8_t bits_per_word, uint32_t extra_flags);
|
||||
int spi_transfer(spi_t *spi, const uint8_t *txbuf, uint8_t *rxbuf, size_t len);
|
||||
int spi_close(spi_t *spi);
|
||||
void spi_free(spi_t *spi);
|
||||
|
||||
/* Getters */
|
||||
int spi_get_mode(spi_t *spi, unsigned int *mode);
|
||||
int spi_get_max_speed(spi_t *spi, uint32_t *max_speed);
|
||||
int spi_get_bit_order(spi_t *spi, spi_bit_order_t *bit_order);
|
||||
int spi_get_bits_per_word(spi_t *spi, uint8_t *bits_per_word);
|
||||
int spi_get_extra_flags(spi_t *spi, uint8_t *extra_flags);
|
||||
int spi_get_extra_flags32(spi_t *spi, uint32_t *extra_flags);
|
||||
|
||||
/* Setters */
|
||||
int spi_set_mode(spi_t *spi, unsigned int mode);
|
||||
int spi_set_max_speed(spi_t *spi, uint32_t max_speed);
|
||||
int spi_set_bit_order(spi_t *spi, spi_bit_order_t bit_order);
|
||||
int spi_set_bits_per_word(spi_t *spi, uint8_t bits_per_word);
|
||||
int spi_set_extra_flags(spi_t *spi, uint8_t extra_flags);
|
||||
int spi_set_extra_flags32(spi_t *spi, uint32_t extra_flags);
|
||||
|
||||
/* Miscellaneous */
|
||||
int spi_fd(spi_t *spi);
|
||||
int spi_tostring(spi_t *spi, char *str, size_t len);
|
||||
|
||||
/* Error Handling */
|
||||
int spi_errno(spi_t *spi);
|
||||
const char *spi_errmsg(spi_t *spi);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
#include <stdio.h>
|
||||
#include "u8g2port.h"
|
||||
|
||||
// By default, SPI bus /dev/spidev0.0 is used, as defined in port/U8g2lib.h
|
||||
|
@ -36,7 +35,10 @@ int main(void)
|
|||
printf("Initialized ...\n");
|
||||
sleep_ms(5000);
|
||||
u8g2_SetPowerSave(&u8g2, 1);
|
||||
// Deallocate GPIO pins
|
||||
// Close and deallocate SPI resources
|
||||
done_spi();
|
||||
// Close and deallocate GPIO resources
|
||||
done_pins();
|
||||
printf("Done\n");
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
#include <stdio.h>
|
||||
#include "u8g2port.h"
|
||||
|
||||
|
||||
|
@ -38,6 +37,12 @@ int main(void)
|
|||
u8g2_SendBuffer(&u8g2);
|
||||
|
||||
printf("Initialized ...\n");
|
||||
sleep_ms(5000);
|
||||
u8g2_SetPowerSave(&u8g2, 1);
|
||||
// Close and deallocate GPIO resources
|
||||
done_pins();
|
||||
printf("Done\n");
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
#include <stdio.h>
|
||||
#include <u8g2port.h>
|
||||
|
||||
int main(void)
|
||||
|
@ -25,6 +24,9 @@ int main(void)
|
|||
printf("Initialized ...\n");
|
||||
sleep_ms(5000);
|
||||
u8g2_SetPowerSave(&u8g2, 1);
|
||||
// Close and deallocate i2c_t
|
||||
done_i2c();
|
||||
printf("Done\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
#include <stdio.h>
|
||||
#include "u8g2port.h"
|
||||
|
||||
#define OLED_I2C_PIN_SCL 20
|
||||
|
@ -30,6 +29,11 @@ int main(void)
|
|||
u8g2_SendBuffer(&u8g2);
|
||||
|
||||
printf("Initialized ...\n");
|
||||
sleep_ms(5000);
|
||||
u8g2_SetPowerSave(&u8g2, 1);
|
||||
// Close and deallocate GPIO resources
|
||||
done_pins();
|
||||
printf("Done\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#include <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_DC 24
|
||||
#define OLED_SPI_PIN_RES 199
|
||||
#define OLED_SPI_PIN_DC 198
|
||||
|
||||
// CS pin is controlled by linux spi driver
|
||||
#define OLED_SPI_PIN_CS 8
|
||||
|
@ -18,10 +18,15 @@ int main()
|
|||
{
|
||||
u8g2.begin();
|
||||
u8g2.clearBuffer(); // clear the internal memory
|
||||
u8g2.setPowerSave(0);
|
||||
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
|
||||
u8g2.setFont(u8g2_font_unifont_t_symbols);
|
||||
u8g2.drawGlyph(112, 56, 0x2603 );
|
||||
u8g2.sendBuffer();
|
||||
u8g2.sleepMs(5000);
|
||||
u8g2.setPowerSave(1);
|
||||
u8g2.doneSpi();
|
||||
u8g2.donePins();
|
||||
}
|
||||
|
|
|
@ -20,10 +20,15 @@ int main()
|
|||
{
|
||||
u8g2.begin();
|
||||
u8g2.clearBuffer(); // clear the internal memory
|
||||
u8g2.setPowerSave(0);
|
||||
u8g2.setFont(u8g2_font_6x13_tr); // choose a suitable font
|
||||
u8g2.drawStr(1, 18, "U8g2 on SW SPI"); // write something to the internal memory
|
||||
u8g2.sendBuffer(); // transfer internal memory to the display
|
||||
u8g2.setFont(u8g2_font_unifont_t_symbols);
|
||||
u8g2.drawGlyph(112, 56, 0x2603 );
|
||||
u8g2.sendBuffer();
|
||||
u8g2.sleepMs(5000);
|
||||
u8g2.setPowerSave(1);
|
||||
u8g2.donePins();
|
||||
|
||||
}
|
||||
|
|
|
@ -7,10 +7,15 @@ int main(void)
|
|||
{
|
||||
u8g2.begin();
|
||||
u8g2.clearBuffer(); // clear the internal memory
|
||||
u8g2.setPowerSave(0);
|
||||
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
|
||||
u8g2.setFont(u8g2_font_unifont_t_symbols);
|
||||
u8g2.drawGlyph(112, 56, 0x2603 );
|
||||
u8g2.sendBuffer();
|
||||
u8g2.sleepMs(5000);
|
||||
u8g2.setPowerSave(1);
|
||||
u8g2.doneI2c();
|
||||
u8g2.donePins();
|
||||
}
|
||||
|
|
|
@ -14,10 +14,14 @@ int main(void)
|
|||
{
|
||||
u8g2.begin();
|
||||
u8g2.clearBuffer(); // clear the internal memory
|
||||
u8g2.setPowerSave(0);
|
||||
u8g2.setFont(u8g2_font_6x13_tr); // choose a suitable font
|
||||
u8g2.drawStr(1, 18, "U8g2 on SW I2C"); // write something to the internal memory
|
||||
u8g2.sendBuffer(); // transfer internal memory to the display
|
||||
u8g2.setFont(u8g2_font_unifont_t_symbols);
|
||||
u8g2.drawGlyph(112, 56, 0x2603 );
|
||||
u8g2.sendBuffer();
|
||||
u8g2.sleepMs(5000);
|
||||
u8g2.setPowerSave(1);
|
||||
u8g2.donePins();
|
||||
}
|
||||
|
|
|
@ -103,6 +103,13 @@ class U8G2 : public Print
|
|||
u8g2_SetMenuHomePin(&u8g2, val); }
|
||||
#endif
|
||||
|
||||
void donePins(void) { done_pins(); }
|
||||
void doneI2c(void) { done_i2c(); }
|
||||
void doneSpi(void) { done_spi(); }
|
||||
void sleepMs(unsigned long milliseconds) { sleep_ms(milliseconds); };
|
||||
void sleepUs(unsigned long microseconds) { sleep_us(microseconds); };
|
||||
void sleepNs(unsigned long nanoseconds) { sleep_ns(nanoseconds); };
|
||||
|
||||
/* return 0 for no event or U8X8_MSG_GPIO_MENU_SELECT, */
|
||||
/* U8X8_MSG_GPIO_MENU_NEXT, U8X8_MSG_GPIO_MENU_PREV, */
|
||||
/* U8X8_MSG_GPIO_MENU_HOME */
|
||||
|
|
|
@ -1,9 +1,16 @@
|
|||
/*
|
||||
* This code is not thread safe, however you should be able to use one IC2 and
|
||||
* one SPI device at the same time. This should be reworked to make multiple
|
||||
* displays work in a thread safe way.
|
||||
*/
|
||||
|
||||
#include "u8g2port.h"
|
||||
|
||||
// c-periphery i2c handle
|
||||
static i2c_t *i2c_device;
|
||||
static const char i2c_bus[] = "/dev/i2c-0";
|
||||
|
||||
static int spi_device;
|
||||
static spi_t *spi_device;
|
||||
static const char spi_bus[] = "/dev/spidev1.0";
|
||||
|
||||
#if PERIPHERY_GPIO_CDEV_SUPPORT
|
||||
|
@ -13,28 +20,25 @@ static const char gpio_device[] = "/dev/gpiochip0";
|
|||
// c-periphery GPIO pins
|
||||
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_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_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);
|
||||
void sleep_ns(unsigned long nanoseconds) {
|
||||
struct timespec ts;
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = nanoseconds;
|
||||
nanosleep(&ts, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -72,6 +76,16 @@ void done_pins() {
|
|||
}
|
||||
}
|
||||
|
||||
void done_i2c() {
|
||||
i2c_close(i2c_device);
|
||||
i2c_free(i2c_device);
|
||||
}
|
||||
|
||||
void done_spi() {
|
||||
spi_close(spi_device);
|
||||
spi_free(spi_device);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write pin if not set to U8X8_PIN_NONE.
|
||||
*/
|
||||
|
@ -114,9 +128,6 @@ uint8_t u8x8_arm_linux_gpio_and_delay(u8x8_t *u8x8, uint8_t msg,
|
|||
case U8X8_MSG_GPIO_AND_DELAY_INIT:
|
||||
// Function which implements a delay, arg_int contains the amount of ms
|
||||
|
||||
// printf("CLK:%d, DATA:%d, CS:%d, RST:%d, DC:%d\n", u8x8->pins[U8X8_PIN_SPI_CLOCK], u8x8->pins[U8X8_PIN_SPI_DATA], u8x8->pins[U8X8_PIN_CS], u8x8->pins[U8X8_PIN_RESET], u8x8->pins[U8X8_PIN_DC]);
|
||||
// printf("SDA:%d, SCL:%d\n", u8x8->pins[U8X8_PIN_I2C_DATA], u8x8->pins[U8X8_PIN_I2C_CLOCK]);
|
||||
|
||||
// SPI Pins
|
||||
init_pin(u8x8, U8X8_PIN_SPI_CLOCK);
|
||||
init_pin(u8x8, U8X8_PIN_SPI_DATA);
|
||||
|
@ -223,7 +234,6 @@ 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 */
|
||||
static uint8_t buffer[32];
|
||||
static uint8_t buf_idx;
|
||||
static uint8_t addr;
|
||||
uint8_t *data;
|
||||
struct i2c_msg msgs[1];
|
||||
|
||||
|
@ -239,10 +249,9 @@ uint8_t u8x8_byte_arm_linux_hw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int,
|
|||
|
||||
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));
|
||||
}
|
||||
addr = u8x8_GetI2CAddress(u8x8) >> 1;
|
||||
if (i2c_open(i2c_device, i2c_bus) < 0) {
|
||||
fprintf(stderr, "i2c_open(): %s\n", i2c_errmsg(i2c_device));
|
||||
}
|
||||
break;
|
||||
|
||||
case U8X8_MSG_BYTE_START_TRANSFER:
|
||||
|
@ -250,11 +259,12 @@ uint8_t u8x8_byte_arm_linux_hw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int,
|
|||
break;
|
||||
|
||||
case U8X8_MSG_BYTE_END_TRANSFER:
|
||||
msgs[0].addr = addr;
|
||||
msgs[0].flags = 0; /* Write */
|
||||
msgs[0].len = buf_idx;
|
||||
msgs[0].buf = buffer;
|
||||
i2c_transfer(i2c_device, msgs, 1);
|
||||
msgs[0].addr = u8x8_GetI2CAddress(u8x8) >> 1;
|
||||
;
|
||||
msgs[0].flags = 0; // Write
|
||||
msgs[0].len = buf_idx;
|
||||
msgs[0].buf = buffer;
|
||||
i2c_transfer(i2c_device, msgs, 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -265,58 +275,34 @@ uint8_t u8x8_byte_arm_linux_hw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int,
|
|||
|
||||
uint8_t u8x8_byte_arm_linux_hw_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int,
|
||||
void *arg_ptr) {
|
||||
// u8g2/u8x8 will never send more than 128 bytes
|
||||
static uint8_t buffer[132];
|
||||
uint8_t buf_idx;
|
||||
uint8_t *data;
|
||||
uint8_t tx[2], rx[2];
|
||||
uint8_t internal_spi_mode;
|
||||
|
||||
switch (msg) {
|
||||
case U8X8_MSG_BYTE_SEND:
|
||||
buf_idx = 0;
|
||||
data = (uint8_t*) arg_ptr;
|
||||
// printf("Buffering Data %d \n", arg_int);
|
||||
|
||||
while (arg_int > 0) {
|
||||
// printf("%.2X ", (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, };
|
||||
|
||||
SPITransfer(spi_device, &tr);
|
||||
buffer[buf_idx++] = *data;
|
||||
data++;
|
||||
arg_int--;
|
||||
}
|
||||
// printf("\n");
|
||||
spi_transfer(spi_device, 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 */
|
||||
internal_spi_mode = 0;
|
||||
switch (u8x8->display_info->spi_mode) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
internal_spi_mode |= SPI_CPHA;
|
||||
break;
|
||||
case 2:
|
||||
internal_spi_mode |= SPI_CPOL;
|
||||
break;
|
||||
case 3:
|
||||
internal_spi_mode |= SPI_CPOL;
|
||||
internal_spi_mode |= SPI_CPHA;
|
||||
break;
|
||||
}
|
||||
// printf("SPI Device Mode Set\n");
|
||||
|
||||
spi_device = openSPIDevice(spi_bus, internal_spi_mode, 8, 500000);
|
||||
if (spi_device < 0) {
|
||||
printf("Failed to open SPI Device %s\n", spi_bus);
|
||||
} else {
|
||||
printf("SPI Device Opened\n");
|
||||
if (spi_open(spi_device, spi_bus, u8x8->display_info->spi_mode, 500000)
|
||||
< 0) {
|
||||
fprintf(stderr, "spi_open(): %s\n", spi_errmsg(spi_device));
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
@ -10,12 +10,15 @@ extern "C" {
|
|||
#include "i2c.h"
|
||||
#include "spi.h"
|
||||
#include <time.h>
|
||||
#include <stdio.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 done_pins();
|
||||
void done_i2c();
|
||||
void done_spi();
|
||||
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);
|
||||
|
|
Loading…
Reference in New Issue