Orange Pi Zero のI2C/SPIを使ったことがなかったので試してみた。
I2C/SPIを有効にするには、armbian-configのSystem->Hardware内の[i2c0/i2c1/spi-spidev]にチェックを付けて保存し再起動するだけ。
或いは、/boot/armbianEnv.txtを直接編集しても良い...
有効化されたI2C/SPIは、/dev内にデバイス名として見えるようになる。対応する信号線のピン位置は下記を参照。
“/dev/i2c-0”–>TWI0_XXX
“/dev/i2c-1”–>TWI1_XXX
“/dev/spidev1.0”–>SPI1_XXX
I2C/SPI用のライブラリも簡単に出来そうだったので勉強がてら作ってみた。
【I2Cサンプル】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
/* * i2c test program * * Sasapea's Lab. * 2019-09-02 */ #include <stdio.h> #include <unistd.h> #include "libi2cdev.h" #include "kbhit.h" #define I2C_ADDR 0x20 int main (void) { int value; int fd; if ((fd = i2cdev_open("/dev/i2c-0")) == -1) perror("i2cdev_open()"); else { char tx[] = {0x12}; char rx[2]; while (!kbhit()) { int i; switch (2) { case 0: for (i = 0; i < 128; ++i) { if (i2cdev_write(fd, i, tx, 0) != -1) printf("found [0x%02X]\n", i); } break; case 1: i = i2cdev_read(fd, I2C_ADDR, rx, sizeof(rx)); printf("%d = [0x%02X][0x%02X]\n", i, rx[0], rx[1]); break; case 2: i = i2cdev_write_and_read(fd, I2C_ADDR, tx, sizeof(tx), rx, sizeof(rx)); printf("%d = [0x%02X][0x%02X]\n", i, rx[0], rx[1]); break; } sleep(1); } i2cdev_close(fd); } return 0; } |
【I2Cライブラリ】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
/* * i2cdev library * * Sasapea's Lab. * 2019-09-02 */ #ifndef _LIBI2CDEV_H #define _LIBI2CDEV_H #ifdef __cplusplus extern "C" { #endif int i2cdev_open(const char *name); int i2cdev_close(int fd); int i2cdev_write(int fd, unsigned short addr, const char *buf, int len); int i2cdev_read(int fd, unsigned short addr, char *buf, int len); int i2cdev_write_and_read(int fd, unsigned short addr, const char *txbuf, int txlen, char *rxbuf, int rxlen); #ifdef __cplusplus } #endif #endif // _LIBI2CDEV_H |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
/* * i2cdev library * * Sasapea's Lab. * 2019-09-02 */ #include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <sys/ioctl.h> #include <linux/i2c-dev.h> #include <linux/i2c.h> #include "libi2cdev.h" #define LENGTHOF(a) (sizeof(a)/sizeof(a[0])) int i2cdev_open(const char *name) { return open(name, O_RDWR); } int i2cdev_close(int fd) { return close(fd); } int i2cdev_write(int fd, unsigned short addr, const char *buf, int len) { struct i2c_msg msg[1]; struct i2c_rdwr_ioctl_data ctl; ctl.msgs = msg; ctl.nmsgs = LENGTHOF(msg); msg[0].addr = addr; msg[0].flags = 0; msg[0].len = len; msg[0].buf = (char *)buf; return ioctl(fd, I2C_RDWR, &ctl) == -1 ? -1 : msg[0].len; } int i2cdev_read(int fd, unsigned short addr, char *buf, int len) { struct i2c_msg msg[1]; struct i2c_rdwr_ioctl_data ctl; ctl.msgs = msg; ctl.nmsgs = LENGTHOF(msg); msg[0].addr = addr; msg[0].flags = I2C_M_RD; msg[0].len = len; msg[0].buf = buf; return ioctl(fd, I2C_RDWR, &ctl) == -1 ? -1 : msg[0].len; } int i2cdev_write_and_read(int fd, unsigned short addr, const char *txbuf, int txlen, char *rxbuf, int rxlen) { struct i2c_msg msg[2]; struct i2c_rdwr_ioctl_data ctl; ctl.msgs = msg; ctl.nmsgs = LENGTHOF(msg); msg[0].addr = addr; msg[0].flags = 0; msg[0].len = txlen; msg[0].buf = (char *)txbuf; msg[1].addr = addr; msg[1].flags = I2C_M_RD; msg[1].len = rxlen; msg[1].buf = rxbuf; return ioctl(fd, I2C_RDWR, &ctl) == -1 ? -1 : msg[1].len; } |
【SPIサンプル】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
/* * spi test program * * Sasapea's Lab. * 2019-09-02 */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <ctype.h> #include "libspidev.h" #include "kbhit.h" int main(int argc, char **argv) { unsigned long speed_hz = 1000000; unsigned short delay_usecs = 0; unsigned char bits_per_word = 8; unsigned char cs_change = 0; spidev_t spi; int loopbak = 1; int help = 0; int i; for (i = 1; i < argc; ) { char *p = argv[i++]; if (strcmp(p, "-speed") == 0) { if (i < argc) speed_hz = strtoul(argv[i++], NULL, 10); } else if (strcmp(p, "-delay") == 0) { if (i < argc) delay_usecs = atoi(argv[i++]); } else if (strcmp(p, "-bits_per_word") == 0) { if (i < argc) bits_per_word = atoi(argv[i++]); } else if (strcmp(p, "-cs_change") == 0) { if (i < argc) cs_change = atoi(argv[i++]); } else if (strcmp(p, "-loopbak") == 0) { if (i < argc) loopbak = atoi(argv[i++]); } else { help = 1; } } if (help) { printf("usage: %s [-speed Hz] [-delay us] [-bits_per_word n] [-cs_change n] [-loopbak n]\n", argv[0]); return 1; } printf("speed=%u, delay=%u, bits_per_word=%u, cs_change=%d, loopbak=%d\n", speed_hz, delay_usecs, bits_per_word, cs_change, loopbak); spidev_init(&spi, speed_hz, delay_usecs, bits_per_word, cs_change); if (spidev_open(&spi, "/dev/spidev1.0", 0) == -1) { perror("spidev_open()"); } else { char tx[8] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}; char rx[sizeof(tx)]; do { memset(rx, 0, sizeof(rx)); if (spidev_transfer(&spi, tx, rx, sizeof(tx)) == -1) { perror("spidev_transfer()"); break; } if (loopbak) { if (memcmp(tx, rx, sizeof(tx)) != 0) { fprintf(stderr, "data mismatched\n"); break; } } } while (!kbhit()); if (spidev_close(&spi) == -1) perror("spidev_close()"); } return 0; } |
【SPIライブラリ】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
/* * spidev library * * Sasapea's Lab. * 2019-09-02 */ #ifndef _LIBSPIDEV_H #define _LIBSPIDEV_H #include <linux/spi/spidev.h> typedef struct { int fd; struct spi_ioc_transfer tr[2]; } spidev_t; #ifdef __cplusplus extern "C" { #endif void spidev_init(spidev_t *spi, unsigned long speed_hz, unsigned short delay_usecs, unsigned char bits_per_word, unsigned char cs_change); int spidev_open(spidev_t *spi, const char *name, int mode); int spidev_close(spidev_t *spi); int spidev_transfer(spidev_t *spi, const char *txbuf, char *rxbuf, int len); int spidev_write_and_read(spidev_t *spi, const char *txbuf, int txlen, char *rxbuf, int rxlen); #ifdef __cplusplus } #endif #endif // _LIBSPIDEV_H |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
/* * spidev library * * Sasapea's Lab. * 2019-09-02 */ #include <stdio.h> #include <string.h> #include <stdint.h> #include <unistd.h> #include <fcntl.h> #include <sys/ioctl.h> #include <linux/types.h> #include "libspidev.h" /* * exsample: * * spidev_t spi; * * spidev_init(&spi, 10000000, 0, 8, 1); * if (spidev_open(&spi, "/dev/spidev1.0", 0) != -1) * { * spidev_transfer(&spi, txbuf, rxbuf, len); * spidev_close(&spi); * } */ #define LENGTHOF(a) (sizeof(a)/sizeof(a[0])) void spidev_init(spidev_t *spi, unsigned long speed_hz, unsigned short delay_usecs, unsigned char bits_per_word, unsigned char cs_change) { int i; memset(spi, 0, sizeof(*spi)); for (i = 0; i < LENGTHOF(spi->tr); ++i) { spi->tr[i].speed_hz = speed_hz; spi->tr[i].delay_usecs = delay_usecs; spi->tr[i].bits_per_word = bits_per_word; spi->tr[i].cs_change = cs_change; } } int spidev_open(spidev_t *spi, const char *name, int mode) { const uint8_t MODE[] = {SPI_MODE_0, SPI_MODE_1, SPI_MODE_2, SPI_MODE_3}; if ((spi->fd = open(name, O_RDWR)) != -1) { if ((mode < 0) || (mode >= sizeof(MODE))) mode = 0; if (ioctl(spi->fd, SPI_IOC_WR_MODE, &MODE[mode]) == -1) fprintf(stderr, "can't set spi mode\n"); } return spi->fd; } int spidev_close(spidev_t *spi) { return close(spi->fd); } int spidev_transfer(spidev_t *spi, const char *txbuf, char *rxbuf, int len) { spi->tr[0].tx_buf = (int)txbuf; spi->tr[0].rx_buf = (int)rxbuf; spi->tr[0].len = len; return ioctl(spi->fd, SPI_IOC_MESSAGE(1), spi->tr); } int spidev_write_and_read(spidev_t *spi, const char *txbuf, int txlen, char *rxbuf, int rxlen) { spi->tr[0].tx_buf = (int)txbuf; spi->tr[0].rx_buf = 0; spi->tr[0].len = txlen; spi->tr[1].tx_buf = 0; spi->tr[1].rx_buf = (int)rxbuf; spi->tr[1].len = rxlen; return ioctl(spi->fd, SPI_IOC_MESSAGE(LENGTHOF(spi->tr)), spi->tr); } |