mirror of
https://git.intern.spaceteamaachen.de/ALPAKA/sta-core.git
synced 2025-09-29 05:17:33 +00:00
Added I2C support for raspi & first rework of debugging
This commit is contained in:
129
src/devices/raspi/bus/i2c/i2c.cpp
Normal file
129
src/devices/raspi/bus/i2c/i2c.cpp
Normal file
@@ -0,0 +1,129 @@
|
||||
#include <sta/devices/raspi/bus/i2c.hpp>
|
||||
|
||||
#ifdef STA_PLATFORM_RASPI
|
||||
|
||||
#include <sta/assert.hpp>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <string.h>
|
||||
#include <iostream>
|
||||
|
||||
#include <linux/i2c-dev.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
namespace sta
|
||||
{
|
||||
RaspiI2c::RaspiI2c(I2cNode node, Mutex * mutex, bool persistent_open)
|
||||
: I2c{mutex}, persistent_open_{persistent_open}
|
||||
{
|
||||
// Safer version of malloc + strcpy
|
||||
i2cdev_ = strdup(node == I2cNode::DEV_1 ? "/dev/i2c-1" : "/dev/i2c-2");
|
||||
|
||||
STA_ASSERT(i2cdev_ != nullptr);
|
||||
}
|
||||
|
||||
RaspiI2c::~RaspiI2c()
|
||||
{
|
||||
if (i2cdev_ != NULL ) {
|
||||
free(i2cdev_);
|
||||
i2cdev_ = NULL;
|
||||
}
|
||||
|
||||
if (open_) {
|
||||
close(i2cfd_);
|
||||
}
|
||||
}
|
||||
|
||||
void RaspiI2c::transfer(uint8_t value)
|
||||
{
|
||||
STA_ASSERT(open_);
|
||||
|
||||
write(i2cfd_, &value, 1);
|
||||
}
|
||||
|
||||
void RaspiI2c::transfer16(uint16_t value)
|
||||
{
|
||||
STA_ASSERT(open_);
|
||||
|
||||
write(i2cfd_, &value, 2);
|
||||
}
|
||||
|
||||
void RaspiI2c::transfer(const uint8_t * buffer, size_t size)
|
||||
{
|
||||
STA_ASSERT(open_);
|
||||
|
||||
write(i2cfd_, buffer, size);
|
||||
}
|
||||
|
||||
void RaspiI2c::transfer(const uint8_t * txBuffer, uint8_t * rxBuffer, size_t size)
|
||||
{
|
||||
STA_ASSERT(open_);
|
||||
|
||||
// TODO: Is this even possible in i2c?
|
||||
}
|
||||
|
||||
void RaspiI2c::receive(uint8_t * buffer, size_t size)
|
||||
{
|
||||
STA_ASSERT(open_);
|
||||
|
||||
if (read(i2cfd_, buffer, size) <= 0)
|
||||
{
|
||||
printf("Error while reading i2c bus.");
|
||||
}
|
||||
}
|
||||
|
||||
void RaspiI2c::fill(uint8_t value, size_t count)
|
||||
{
|
||||
STA_ASSERT(open_);
|
||||
|
||||
// Initialize a buffer of size count and fill it with the value.
|
||||
uint8_t *buffer = new uint8_t[count];
|
||||
memset(buffer, value, count);
|
||||
|
||||
write(i2cfd_, buffer, count);
|
||||
|
||||
delete [] buffer;
|
||||
}
|
||||
|
||||
void RaspiI2c::selectAddress(uint16_t address)
|
||||
{
|
||||
if (ioctl(i2cfd_, I2C_SLAVE, address) < 0)
|
||||
{
|
||||
printf("Failed to send the slave address.");
|
||||
}
|
||||
}
|
||||
|
||||
void RaspiI2c::acquire()
|
||||
{
|
||||
I2c::acquire();
|
||||
|
||||
if (open_) {
|
||||
return;
|
||||
}
|
||||
|
||||
i2cfd_ = open(i2cdev_, O_RDWR);
|
||||
open_ = true;
|
||||
|
||||
STA_ASSERT(i2cfd_ >= 0);
|
||||
}
|
||||
|
||||
void RaspiI2c::release()
|
||||
{
|
||||
if (!persistent_open_ && open_) {
|
||||
close(i2cfd_);
|
||||
}
|
||||
|
||||
I2c::release();
|
||||
}
|
||||
|
||||
RaspiI2cDevice::RaspiI2cDevice(I2c * intf, uint16_t address_10bit, Mutex* mutex, bool master, bool blocking)
|
||||
: I2cDevice { intf, address_10bit }
|
||||
{
|
||||
|
||||
}
|
||||
} // namespace sta
|
||||
|
||||
#endif // STA_PLATFORM_RASPI
|
314
src/devices/raspi/bus/spi/spi.cpp
Normal file
314
src/devices/raspi/bus/spi/spi.cpp
Normal file
@@ -0,0 +1,314 @@
|
||||
#include <sta/devices/raspi/bus/spi.hpp>
|
||||
|
||||
#ifdef STA_PLATFORM_RASPI
|
||||
|
||||
#include <sta/devices/raspi/gpio_pin.hpp>
|
||||
#include <sta/bus/spi/settings.hpp>
|
||||
#include <sta/assert.hpp>
|
||||
#include <sta/endian.hpp>
|
||||
#include <sta/lang.hpp>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <string.h>
|
||||
#include <cstdio>
|
||||
|
||||
// Imports needed for SPI handling on Linux.
|
||||
#include <linux/spi/spidev.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define STA_DEBUG_IOCTL_WRITE(result) STA_ASSERT_MSG(result >= 0, "ioctl writing failed!")
|
||||
#define STA_DEBUG_IOCTL_READ(result) STA_ASSERT_MSG(result >= 0, "ioctl reading failed!")
|
||||
#define STA_DEBUG_IOCTL_SEND(result) STA_ASSERT_MSG(result >= 0, "ioctl sending spi message failed!")
|
||||
|
||||
#define STA_DEBUG_FD_OPEN() STA_ASSERT_MSG(open_, "File descriptor wasn't opened!")
|
||||
#define STA_DEBUG_NULLPTR(ptr) STA_ASSERT_MSG(ptr != nullptr, "Pointer is nullptr!")
|
||||
|
||||
|
||||
namespace sta
|
||||
{
|
||||
|
||||
RaspiSPI::RaspiSPI(SPINode node, const SPISettings & settings, Mutex * mutex, bool persistent_open)
|
||||
: SPI(settings, mutex), open_{ false }, persistent_open_{ persistent_open }, settings_{ settings }
|
||||
{
|
||||
// Check validity of parameters.
|
||||
STA_DEBUG_NULLPTR(mutex);
|
||||
|
||||
open_ = false;
|
||||
|
||||
// Safer version of malloc + strcpy
|
||||
spidev_ = strdup(node == SPINode::DEV_0_0 ? "/dev/spidev0.0" : "/dev/spidev0.1");
|
||||
|
||||
// Check if memory allocation was successful.
|
||||
STA_DEBUG_NULLPTR(spidev_);
|
||||
}
|
||||
|
||||
RaspiSPI::~RaspiSPI()
|
||||
{
|
||||
if (spidev_ != NULL ) {
|
||||
free(spidev_);
|
||||
spidev_ = NULL;
|
||||
}
|
||||
|
||||
if (open_) {
|
||||
close(spifd_);
|
||||
}
|
||||
}
|
||||
|
||||
void RaspiSPI::transfer(uint8_t value)
|
||||
{
|
||||
STA_DEBUG_FD_OPEN();
|
||||
|
||||
struct spi_ioc_transfer spi_message[1];
|
||||
|
||||
// According to the documentation, spi_message should be zero intialized.
|
||||
memset(spi_message, 0, sizeof(spi_message));
|
||||
spi_message[0].tx_buf = (unsigned long)&value;
|
||||
spi_message[0].len = 1;
|
||||
|
||||
// For some reasons, this line makes the SPI interface work for the BMP388.
|
||||
spi_message[0].cs_change = 1;
|
||||
|
||||
int result = ioctl(spifd_, SPI_IOC_MESSAGE(1), spi_message);
|
||||
|
||||
if (result < 0) {
|
||||
printf("Sending failed with error '%s'! \n", strerror(errno));
|
||||
}
|
||||
|
||||
STA_DEBUG_IOCTL_SEND(result);
|
||||
}
|
||||
|
||||
void RaspiSPI::transfer16(uint16_t value)
|
||||
{
|
||||
STA_DEBUG_FD_OPEN();
|
||||
|
||||
struct spi_ioc_transfer spi_message[1];
|
||||
|
||||
// According to the documentation, spi_message should be zero intialized.
|
||||
memset(spi_message, 0, sizeof(spi_message));
|
||||
spi_message[0].tx_buf = (unsigned long)&value;
|
||||
spi_message[0].len = 1;
|
||||
spi_message[0].cs_change = 1;
|
||||
|
||||
int result = ioctl(spifd_, SPI_IOC_MESSAGE(1), spi_message);
|
||||
|
||||
if (result < 0) {
|
||||
printf("Sending failed with error '%s'! \n", strerror(errno));
|
||||
}
|
||||
|
||||
STA_DEBUG_IOCTL_SEND(result);
|
||||
}
|
||||
|
||||
void RaspiSPI::transfer(const uint8_t * buffer, size_t size)
|
||||
{
|
||||
STA_DEBUG_FD_OPEN();
|
||||
STA_DEBUG_NULLPTR(buffer);
|
||||
STA_ASSERT_MSG(size != 0, "Buffer size cannot be 0!");
|
||||
|
||||
struct spi_ioc_transfer spi_message[1];
|
||||
|
||||
// According to the documentation, spi_message should be zero intialized.
|
||||
memset(spi_message, 0, sizeof(spi_message));
|
||||
spi_message[0].tx_buf = (unsigned long)buffer;
|
||||
spi_message[0].len = size;
|
||||
|
||||
int result = ioctl(spifd_, SPI_IOC_MESSAGE(1), spi_message);
|
||||
|
||||
if (result < 0) {
|
||||
printf("Sending failed with error '%s'! \n", strerror(errno));
|
||||
}
|
||||
|
||||
STA_DEBUG_IOCTL_SEND(result);
|
||||
}
|
||||
|
||||
void RaspiSPI::transfer(const uint8_t * txBuffer, uint8_t * rxBuffer, size_t size)
|
||||
{
|
||||
STA_DEBUG_FD_OPEN();
|
||||
STA_DEBUG_NULLPTR(txBuffer);
|
||||
STA_DEBUG_NULLPTR(rxBuffer);
|
||||
STA_ASSERT_MSG(size != 0, "Buffer size cannot be 0!");
|
||||
|
||||
struct spi_ioc_transfer spi_message[1];
|
||||
|
||||
// According to the documentation, spi_message should be zero intialized.
|
||||
memset(spi_message, 0, sizeof(spi_message));
|
||||
|
||||
spi_message[0].rx_buf = (unsigned long)rxBuffer;
|
||||
spi_message[0].tx_buf = (unsigned long)txBuffer;
|
||||
spi_message[0].len = size;
|
||||
|
||||
int result = ioctl(spifd_, SPI_IOC_MESSAGE(1), spi_message);
|
||||
|
||||
if (result < 0) {
|
||||
printf("Sending failed with error '%s'! \n", strerror(errno));
|
||||
}
|
||||
|
||||
STA_DEBUG_IOCTL_SEND(result);
|
||||
}
|
||||
|
||||
void RaspiSPI::receive(uint8_t * buffer, size_t size)
|
||||
{
|
||||
STA_DEBUG_FD_OPEN();
|
||||
STA_DEBUG_NULLPTR(buffer);
|
||||
STA_ASSERT_MSG(size != 0, "Buffer size cannot be 0!");
|
||||
|
||||
struct spi_ioc_transfer spi_message[1];
|
||||
|
||||
// According to the documentation, spi_message should be zero intialized.
|
||||
memset(spi_message, 0, sizeof(spi_message));
|
||||
|
||||
spi_message[0].rx_buf = (unsigned long)buffer;
|
||||
spi_message[0].len = size;
|
||||
|
||||
int result = ioctl(spifd_, SPI_IOC_MESSAGE(1), spi_message);
|
||||
|
||||
STA_DEBUG_IOCTL_SEND(result);
|
||||
}
|
||||
|
||||
void RaspiSPI::fill(uint8_t value, size_t count)
|
||||
{
|
||||
STA_DEBUG_FD_OPEN();
|
||||
STA_ASSERT_MSG(count != 0, "Buffer size cannot be 0!");
|
||||
|
||||
uint8_t * buffer = new uint8_t[count];
|
||||
memset(buffer, value, count);
|
||||
|
||||
struct spi_ioc_transfer spi_message[1];
|
||||
memset(spi_message, 0, sizeof(spi_message));
|
||||
spi_message[0].tx_buf = (unsigned long)buffer;
|
||||
spi_message[0].len = count;
|
||||
|
||||
int result = ioctl(spifd_, SPI_IOC_MESSAGE(1), spi_message);
|
||||
|
||||
STA_DEBUG_IOCTL_SEND(result);
|
||||
|
||||
delete[] buffer;
|
||||
}
|
||||
|
||||
void RaspiSPI::update_setting(int setting, int value)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void RaspiSPI::get_setting(int setting, void * rslt_ptr)
|
||||
{
|
||||
STA_DEBUG_FD_OPEN();
|
||||
int result = ioctl(spifd_, setting, rslt_ptr);
|
||||
STA_DEBUG_IOCTL_READ(result);
|
||||
}
|
||||
|
||||
void RaspiSPI::update_settings()
|
||||
{
|
||||
STA_DEBUG_FD_OPEN();
|
||||
|
||||
switch (settings_.mode)
|
||||
{
|
||||
case SPIMode::MODE_0:
|
||||
mode_ = SPI_MODE_0;
|
||||
break;
|
||||
case SPIMode::MODE_1:
|
||||
mode_ = SPI_MODE_1;
|
||||
break;
|
||||
case SPIMode::MODE_2:
|
||||
mode_ = SPI_MODE_2;
|
||||
break;
|
||||
case SPIMode::MODE_3:
|
||||
mode_ = SPI_MODE_3;
|
||||
break;
|
||||
default:
|
||||
STA_ASSERT_MSG(false, "Case for SPIMode enum not handled");
|
||||
STA_UNREACHABLE();
|
||||
}
|
||||
|
||||
dataSize_ = settings_.dataSize == SPIDataSize::SIZE_8 ? 0 : 16;
|
||||
bitOrder_ = settings_.bitOrder == SPIBitOrder::MSB ? 0 : 1;
|
||||
clkSpeed_ = settings_.clkSpeed;
|
||||
|
||||
// Set the spi mode.
|
||||
int result = ioctl(spifd_, SPI_IOC_WR_MODE, &mode_);
|
||||
STA_DEBUG_IOCTL_WRITE(result);
|
||||
|
||||
if (result < 0) {
|
||||
printf("Update mode failed with error '%s'! \n", strerror(errno));
|
||||
}
|
||||
|
||||
// Set the word size. According to the documentation "the value zero signifies eight bits".
|
||||
result = ioctl(spifd_, SPI_IOC_WR_BITS_PER_WORD, &dataSize_);
|
||||
STA_DEBUG_IOCTL_WRITE(result);
|
||||
|
||||
if (result < 0) {
|
||||
printf("Update dataSize failed with error '%s'! \n", strerror(errno));
|
||||
}
|
||||
|
||||
// Set the bit order. According to the documentation zero means MSB first, everything else means LSB first.
|
||||
result = ioctl(spifd_, SPI_IOC_WR_LSB_FIRST, &bitOrder_);
|
||||
STA_DEBUG_IOCTL_WRITE(result);
|
||||
|
||||
if (result < 0) {
|
||||
printf("Update endianness failed with error '%s'! \n", strerror(errno));
|
||||
}
|
||||
|
||||
// Set the maximum clock speed.
|
||||
result = ioctl(spifd_, SPI_IOC_WR_MAX_SPEED_HZ, &clkSpeed_);
|
||||
STA_DEBUG_IOCTL_WRITE(result);
|
||||
|
||||
if (result < 0) {
|
||||
printf("Update clock speed failed with error '%s'! \n", strerror(errno));
|
||||
}
|
||||
|
||||
#if defined(DEBUG)
|
||||
uint8_t r_mode = 0;
|
||||
get_setting(SPI_IOC_RD_MODE, &r_mode);
|
||||
STA_ASSERT_MSG(r_mode == mode_, "The mode wasn't set correctly!");
|
||||
|
||||
uint8_t r_dataSize = 0;
|
||||
get_setting(SPI_IOC_WR_BITS_PER_WORD, &r_dataSize);
|
||||
STA_ASSERT_MSG(r_dataSize == (settings_.dataSize == SPIDataSize::SIZE_8 ? 8 : 16), "The data size wasn't set correctly!");
|
||||
|
||||
uint8_t r_bitOrder = 0;
|
||||
get_setting(SPI_IOC_RD_LSB_FIRST, &r_bitOrder);
|
||||
STA_ASSERT_MSG(r_bitOrder == (settings_.bitOrder == SPIBitOrder::MSB ? 0 : 1), "The data size wasn't set correctly!");
|
||||
|
||||
uint32_t r_clk_Speed;
|
||||
get_setting(SPI_IOC_RD_MAX_SPEED_HZ, &r_clk_Speed);
|
||||
STA_ASSERT_MSG(r_clk_Speed == settings_.clkSpeed, "The clock speed wasn't set correctly!");
|
||||
#endif // STA_DEBUG
|
||||
}
|
||||
|
||||
void RaspiSPI::acquire()
|
||||
{
|
||||
SPI::acquire();
|
||||
|
||||
STA_ASSERT(spidev_ != nullptr);
|
||||
|
||||
/* open spidev device */
|
||||
if (open_ == true)
|
||||
return;
|
||||
|
||||
spifd_ = open(spidev_, O_RDWR);
|
||||
open_ = true;
|
||||
|
||||
STA_ASSERT(spifd_ >= 0);
|
||||
|
||||
update_settings();
|
||||
}
|
||||
|
||||
void RaspiSPI::release()
|
||||
{
|
||||
if (!persistent_open_ && open_) {
|
||||
close(spifd_);
|
||||
}
|
||||
|
||||
SPI::release();
|
||||
}
|
||||
|
||||
RaspiSPIDevice::RaspiSPIDevice(RaspiSPI * intf) : SPIDevice { intf, RaspiGpioPin::DUMMY_GPIO }
|
||||
{
|
||||
|
||||
}
|
||||
} // namespace sta
|
||||
|
||||
|
||||
#endif // STA_PlATFORM_RASPI
|
23
src/devices/raspi/delay.cpp
Normal file
23
src/devices/raspi/delay.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
#include <sta/devices/raspi/delay.hpp>
|
||||
#ifdef STA_PLATFORM_RASPI
|
||||
|
||||
#include <sta/devices/raspi/hal.hpp>
|
||||
|
||||
#include <sta/assert.hpp>
|
||||
#include <sta/lang.hpp>
|
||||
|
||||
|
||||
namespace sta
|
||||
{
|
||||
void delayMs(uint32_t ms)
|
||||
{
|
||||
delay(ms);
|
||||
}
|
||||
|
||||
void delayUs(uint32_t us)
|
||||
{
|
||||
delayMicroseconds(us);
|
||||
}
|
||||
} // namespace sta
|
||||
|
||||
#endif // STA_PLATFORM_RASPI
|
43
src/devices/raspi/gpio_pin.cpp
Normal file
43
src/devices/raspi/gpio_pin.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
#include <sta/raspi/gpio_pin.hpp>
|
||||
#ifdef STA_RASPI_GPIO_ENABLED
|
||||
|
||||
#include <sta/assert.hpp>
|
||||
#include <sta/lang.hpp>
|
||||
|
||||
namespace sta
|
||||
{
|
||||
RaspiGpioPin::RaspiGpioPin(uint8_t pin, GpioMode mode) : pin_{ pin }, mode_{ mode }
|
||||
{
|
||||
pinMode(pin, mode == GpioMode::GPIO_INPUT ? INPUT : OUTPUT);
|
||||
}
|
||||
|
||||
void RaspiGpioPin::setState(GpioPinState state)
|
||||
{
|
||||
digitalWrite(pin_, state == GpioPinState::GPIO_LOW ? LOW : HIGH);
|
||||
}
|
||||
|
||||
GpioPinState RaspiGpioPin::getState()
|
||||
{
|
||||
return digitalRead(pin_) == LOW ? GpioPinState::GPIO_LOW : GpioPinState::GPIO_HIGH;
|
||||
}
|
||||
|
||||
class DummyGpioPin : public RaspiGpioPin
|
||||
{
|
||||
public:
|
||||
DummyGpioPin() : RaspiGpioPin { 0, GpioMode::GPIO_INPUT } {}
|
||||
|
||||
void setState(GpioPinState state) override {}
|
||||
|
||||
GpioPinState getState() override {
|
||||
// This should really never be called since the code might rely on the returned value to be accurate.
|
||||
STA_UNREACHABLE();
|
||||
}
|
||||
};
|
||||
|
||||
static DummyGpioPin dummyGpio;
|
||||
|
||||
RaspiGpioPin * RaspiGpioPin::DUMMY_GPIO = &dummyGpio;
|
||||
} // namespace sta
|
||||
|
||||
|
||||
#endif // STA_ARDUINO_GPIO_ENABLED
|
Reference in New Issue
Block a user