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