I'm currently developing on a embedded Linux chip with a couple of spi devices attached. I wrapped the code to do SPI transfers in a C++ class. A Class represents a single SPI Connection to a single external chip. My C++ is quit rusty and I'm not sure about my code style here. The class itself works well.
SPIConnection.hpp
#ifndef SPIVERBINDUNGHPP3456 #define SPIVERBINDUNGHPP3456 #include <linux/spi/spidev.h> // spi_ioc_transfer u.a #include <string> #include <stdint.h> // for uint8_t, uint16_t etc class SPIConnection { private: int fd; struct spi_ioc_transfer spi; int frequency; std::string name; uint8_t bits; public: SPIConnection(); virtual ~SPIConnection(); /** * Init's the SPI Connection * @method init * -------------------- * @param device the Path to the SPI file * @param mode spi mode * @param bits bits per word * @param LSB lsb or msb * @param speed speed in herz * @param nameParam human readable name of spi conn * @return file descriptor if successfull */ int init(std::string device, uint8_t mode, uint8_t bits, uint8_t LSB, uint32_t speed, std::string nameParam); /** * Transfers data * @method transfer * -------------------- * @param data pointer to send buffer, will be overwritten with received data * @param length number of bytes to be sned * @return 0 if successfull */ int transfer(uint8_t *data, int length); }; #endif /* end of include guard: SPIVERBINDUNGHPP3456 */
SPIConnection.cpp
#include "SPIConnection.hpp" #include <fcntl.h> // Needed for SPI port #include <sys/ioctl.h> // Needed for SPI port #include <errno.h> // linux errors #include <unistd.h> // sleep() #include <stdio.h> #include <sys/time.h> #include <stdint.h> // for uint8_t, uint16_t etc #include <linux/spi/spidev.h> #include <cstring> #include <iostream> using namespace std; SPIConnection::SPIConnection() {} SPIConnection::~SPIConnection() { if (fd > 0) { close(fd); } } int SPIConnection::init(const std::string device, const uint8_t mode, const uint8_t bitsParam, const uint8_t LSB, const uint32_t speed, const std::string nameParam) { name = nameParam; frequency = speed; bits = bitsParam; // filedecriptor which will be given back int ret; /* open device */ if ((fd = open(device.c_str(), O_RDWR)) < 0) { perror("Error Open Device"); return -1; } /* set mode */ ret = ioctl(fd, SPI_IOC_WR_MODE, &mode); if (ret < 0) { perror("Error Set SPI-Mode"); return -2; } // /* check mode */ ret = ioctl(fd, SPI_IOC_RD_MODE, &mode); if (ret < 0) { perror("Error Get SPI-Mode"); return -3; } ret = ioctl(fd, SPI_IOC_WR_LSB_FIRST, &LSB); if (ret < 0) { perror("Error Set LSB-Mode"); return -2; } /* set word length*/ ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits); if (ret < 0) { perror("Error Set wordlength"); return -4; } // /* check word length */ ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits); if (ret < 0) { perror("Error Get wordlength"); return -5; } /* set datarate */ ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed); if (ret < 0) { perror("Error Set Speed"); return -6; } // /* check datarate */ ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed); if (ret < 0) { perror("Error Get Speed"); return -7; } /* Print */ printf("SPI-Connection.: %s\n", name.c_str()); printf("SPI-Device.....: %s\n", device.c_str()); printf("SPI-Mode.......: %d\n", mode); printf("Wordlength.....: %d\n", bits); printf("Speed..........: %d Hz (%d kHz)\n", speed, speed / 1000); printf("Filehandle.....: %d\n", fd); return 0; } int SPIConnection::transfer(uint8_t *data, int length) { int ret; uint8_t rx[length]; //clear memory memset(rx, 0, sizeof(uint8_t) * length); memset(&spi, 0, sizeof(spi)); spi.tx_buf = (unsigned long)data; spi.rx_buf = (unsigned long)rx; spi.len = length; spi.delay_usecs = 0; spi.speed_hz = frequency; spi.bits_per_word = bits; spi.cs_change = 0; // lets go ret = ioctl(fd, SPI_IOC_MESSAGE(1), &spi); if (ret < 0) { if (errno == EBADF) { std::cout << "ERROR: fd is not a valid file descriptor." << std::endl; } else if (errno == EFAULT) { std::cout << "ERROR: argp references an inaccessible memory area" << std::endl; } else if (errno == EINVAL) { std::cout << "ERROR: request or argp is not valid" << std::endl; } else if (errno == ENOTTY) { std::cout << "ERROR: fd is not associated with a character special device" << std::endl; } else if (errno == ENOTTY) { std::cout << "ERROR: The specified request does not apply to the kind of object that the file descriptor fd references." << std::endl; } perror("Error on I/O - ioctl"); return -1; } //copy to output memcpy(data, rx, sizeof(uint8_t) * length); return 0; }
main.cpp
#include "SPIConnection.hpp" int main(int argc, char const *argv[]) { /** * Example usage */ SPIConnection spi_conn; spi_conn.init("/dev/spidev32766.0", SPI_CPOL | !SPI_CPHA, 8, 0, 16000, "MX11060"); uint8_t data[10] = "Hello SPI"; spi_conn.transfer(data, 10); return 0; }