SPI working

This commit is contained in:
servadmin 2021-11-03 12:35:17 -04:00
parent 45df3148b0
commit 97112c03b3
14 changed files with 564 additions and 160 deletions

View File

@ -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 ~/`

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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 */

View File

@ -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;

View File

@ -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);