HAL: implement I2C and SPI directly instead of using i2clib and spilib.

This reduces library dependencies, improves error handling, and makes
future enhancements easier.
This commit is contained in:
Peter Johnson
2017-07-16 01:47:16 -07:00
parent f56ec10bcf
commit 6accc31ee7
2 changed files with 181 additions and 82 deletions

View File

@@ -7,11 +7,16 @@
#include "HAL/SPI.h"
#include <fcntl.h>
#include <linux/spi/spidev.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <array>
#include <atomic>
#include <cstring>
#include <llvm/raw_ostream.h>
#include <spilib/spi-lib.h>
#include <support/mutex.h>
#include "DigitalInternal.h"
@@ -111,13 +116,21 @@ void HAL_InitializeSPI(HAL_SPIPort port, int32_t* status) {
return;
}
int handle;
if (HAL_GetSPIHandle(port) != 0) return;
switch (port) {
case 0:
CommonSPIPortInit(status);
if (*status != 0) return;
// CS0 is not a DIO port, so nothing to allocate
HAL_SetSPIHandle(HAL_SPI_kOnboardCS0, spilib_open("/dev/spidev0.0"));
handle = open("/dev/spidev0.0", O_RDWR);
if (handle < 0) {
std::printf("Failed to open SPI port %d: %s\n", port,
std::strerror(errno));
CommonSPIPortFree();
return;
}
HAL_SetSPIHandle(HAL_SPI_kOnboardCS0, handle);
break;
case 1:
CommonSPIPortInit(status);
@@ -130,7 +143,15 @@ void HAL_InitializeSPI(HAL_SPIPort port, int32_t* status) {
CommonSPIPortFree();
return;
}
HAL_SetSPIHandle(HAL_SPI_kOnboardCS1, spilib_open("/dev/spidev0.1"));
handle = open("/dev/spidev0.1", O_RDWR);
if (handle < 0) {
std::printf("Failed to open SPI port %d: %s\n", port,
std::strerror(errno));
CommonSPIPortFree();
HAL_FreeDIOPort(digitalHandles[0]);
return;
}
HAL_SetSPIHandle(HAL_SPI_kOnboardCS1, handle);
break;
case 2:
CommonSPIPortInit(status);
@@ -143,7 +164,15 @@ void HAL_InitializeSPI(HAL_SPIPort port, int32_t* status) {
CommonSPIPortFree();
return;
}
HAL_SetSPIHandle(HAL_SPI_kOnboardCS2, spilib_open("/dev/spidev0.2"));
handle = open("/dev/spidev0.2", O_RDWR);
if (handle < 0) {
std::printf("Failed to open SPI port %d: %s\n", port,
std::strerror(errno));
CommonSPIPortFree();
HAL_FreeDIOPort(digitalHandles[1]);
return;
}
HAL_SetSPIHandle(HAL_SPI_kOnboardCS2, handle);
break;
case 3:
CommonSPIPortInit(status);
@@ -156,7 +185,15 @@ void HAL_InitializeSPI(HAL_SPIPort port, int32_t* status) {
CommonSPIPortFree();
return;
}
HAL_SetSPIHandle(HAL_SPI_kOnboardCS3, spilib_open("/dev/spidev0.3"));
handle = open("/dev/spidev0.3", O_RDWR);
if (handle < 0) {
std::printf("Failed to open SPI port %d: %s\n", port,
std::strerror(errno));
CommonSPIPortFree();
HAL_FreeDIOPort(digitalHandles[2]);
return;
}
HAL_SetSPIHandle(HAL_SPI_kOnboardCS3, handle);
break;
case 4:
initializeDigital(status);
@@ -193,13 +230,22 @@ void HAL_InitializeSPI(HAL_SPIPort port, int32_t* status) {
}
digitalSystem->writeEnableMXPSpecialFunction(
digitalSystem->readEnableMXPSpecialFunction(status) | 0x00F0, status);
HAL_SetSPIHandle(HAL_SPI_kMXP, spilib_open("/dev/spidev1.0"));
handle = open("/dev/spidev1.0", O_RDWR);
if (handle < 0) {
std::printf("Failed to open SPI port %d: %s\n", port,
std::strerror(errno));
HAL_FreeDIOPort(digitalHandles[5]); // free the first port allocated
HAL_FreeDIOPort(digitalHandles[6]); // free the second port allocated
HAL_FreeDIOPort(digitalHandles[7]); // free the third port allocated
HAL_FreeDIOPort(digitalHandles[8]); // free the fourth port allocated
return;
}
HAL_SetSPIHandle(HAL_SPI_kMXP, handle);
break;
default:
*status = PARAMETER_OUT_OF_RANGE;
break;
}
return;
}
/**
@@ -220,10 +266,14 @@ int32_t HAL_TransactionSPI(HAL_SPIPort port, uint8_t* dataToSend,
return -1;
}
struct spi_ioc_transfer xfer;
std::memset(&xfer, 0, sizeof(xfer));
xfer.tx_buf = (__u64)dataToSend;
xfer.rx_buf = (__u64)dataReceived;
xfer.len = size;
std::lock_guard<wpi::mutex> sync(spiApiMutexes[port]);
return spilib_writeread(
HAL_GetSPIHandle(port), reinterpret_cast<const char*>(dataToSend),
reinterpret_cast<char*>(dataReceived), static_cast<int32_t>(size));
return ioctl(HAL_GetSPIHandle(port), SPI_IOC_MESSAGE(1), &xfer);
}
/**
@@ -241,10 +291,13 @@ int32_t HAL_WriteSPI(HAL_SPIPort port, uint8_t* dataToSend, int32_t sendSize) {
return -1;
}
struct spi_ioc_transfer xfer;
std::memset(&xfer, 0, sizeof(xfer));
xfer.tx_buf = (__u64)dataToSend;
xfer.len = sendSize;
std::lock_guard<wpi::mutex> sync(spiApiMutexes[port]);
return spilib_write(HAL_GetSPIHandle(port),
reinterpret_cast<const char*>(dataToSend),
static_cast<int32_t>(sendSize));
return ioctl(HAL_GetSPIHandle(port), SPI_IOC_MESSAGE(1), &xfer);
}
/**
@@ -265,9 +318,13 @@ int32_t HAL_ReadSPI(HAL_SPIPort port, uint8_t* buffer, int32_t count) {
return -1;
}
struct spi_ioc_transfer xfer;
std::memset(&xfer, 0, sizeof(xfer));
xfer.rx_buf = (__u64)buffer;
xfer.len = count;
std::lock_guard<wpi::mutex> sync(spiApiMutexes[port]);
return spilib_read(HAL_GetSPIHandle(port), reinterpret_cast<char*>(buffer),
static_cast<int32_t>(count));
return ioctl(HAL_GetSPIHandle(port), SPI_IOC_MESSAGE(1), &xfer);
}
/**
@@ -285,7 +342,7 @@ void HAL_CloseSPI(HAL_SPIPort port) {
{
std::lock_guard<wpi::mutex> sync(spiApiMutexes[port]);
spilib_close(HAL_GetSPIHandle(port));
close(HAL_GetSPIHandle(port));
}
HAL_SetSPIHandle(port, 0);
@@ -327,7 +384,7 @@ void HAL_SetSPISpeed(HAL_SPIPort port, int32_t speed) {
}
std::lock_guard<wpi::mutex> sync(spiApiMutexes[port]);
spilib_setspeed(HAL_GetSPIHandle(port), speed);
ioctl(HAL_GetSPIHandle(port), SPI_IOC_WR_MAX_SPEED_HZ, &speed);
}
/**
@@ -346,9 +403,13 @@ void HAL_SetSPIOpts(HAL_SPIPort port, HAL_Bool msbFirst,
return;
}
uint8_t mode = 0;
mode |= (!msbFirst ? 8 : 0);
mode |= (clkIdleHigh ? 2 : 0);
mode |= (sampleOnTrailing ? 1 : 0);
std::lock_guard<wpi::mutex> sync(spiApiMutexes[port]);
spilib_setopts(HAL_GetSPIHandle(port), msbFirst, sampleOnTrailing,
clkIdleHigh);
ioctl(HAL_GetSPIHandle(port), SPI_IOC_WR_MODE, &mode);
}
/**
@@ -462,13 +523,7 @@ static void spiAccumulatorProcess(uint64_t currentTime,
// perform SPI transaction
uint8_t resp_b[4];
{
std::lock_guard<wpi::mutex> sync(spiApiMutexes[accum->port]);
spilib_writeread(HAL_GetSPIHandle(accum->port),
reinterpret_cast<const char*>(accum->cmd),
reinterpret_cast<char*>(resp_b),
static_cast<int32_t>(accum->xferSize));
}
HAL_TransactionSPI(accum->port, accum->cmd, resp_b, accum->xferSize);
// convert from bytes
uint32_t resp = 0;