1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/sys/arduino/SPI.cpp
2022-01-05 15:41:39 +01:00

149 lines
3.2 KiB
C++

/*
* Copyright (C) 2019 Otto-von-Guericke-Universität Magdeburg
*
* This file is subject to the terms and conditions of the GNU Lesser General
* Public License v2.1. See the file LICENSE in the top level directory for more
* details.
*/
/**
* @ingroup sys_arduino_api
* @{
*
* @file
* @brief Implementation of the Arduino 'SPI' interface
*
* @author Marian Buschsieweke <marian.buschsieweke@ovgu.de>
*
* @}
*/
#ifdef MODULE_PERIPH_SPI
extern "C" {
#include "assert.h"
}
#include "SPI.h"
SPISettings::SPISettings(uint32_t clock_hz, uint8_t bitOrder, uint8_t dataMode)
{
(void)bitOrder;
static const spi_clk_t clocks[] = {
SPI_CLK_10MHZ, SPI_CLK_5MHZ, SPI_CLK_1MHZ, SPI_CLK_400KHZ
};
static const uint32_t steps [] = {
10000000, 5000000, 1000000, 400000
};
assert(bitOrder == MSBFIRST);
switch(dataMode) {
default:
case SPI_MODE0:
mode = SPI_MODE_0;
break;
case SPI_MODE1:
mode = SPI_MODE_1;
break;
case SPI_MODE2:
mode = SPI_MODE_2;
break;
case SPI_MODE3:
mode = SPI_MODE_3;
break;
}
for (uint8_t i = 0; i < ARRAY_SIZE(steps); i++) {
if (clock_hz >= steps[i]) {
clock = clocks[i];
return;
}
}
clock = SPI_CLK_100KHZ;
}
SPIClass::SPIClass(spi_t spi_dev)
{
/* Check if default SPI interface is valid. Casting to int to avoid
* bogus type-limits warning here. */
static_assert((int)ARDUINO_SPI_INTERFACE <= (int)SPI_NUMOF,
"spi_dev out of bounds");
this->spi_dev = spi_dev;
this->settings = SPISettings();
this->is_transaction = false;
rmutex_init(&this->mut);
}
void SPIClass::beginTransaction(SPISettings settings)
{
rmutex_lock(&mut);
/* Call spi_acquire first to prevent data races */
spi_acquire(spi_dev, SPI_CS_UNDEF, settings.mode, settings.clock);
is_transaction = true;
}
void SPIClass::endTransaction()
{
is_transaction = false;
spi_release(spi_dev);
rmutex_unlock(&mut);
}
void SPIClass::transfer(void *buf, size_t count)
{
rmutex_lock(&mut);
if (!is_transaction) {
spi_acquire(spi_dev, SPI_CS_UNDEF, settings.mode, settings.clock);
}
spi_transfer_bytes(spi_dev, SPI_CS_UNDEF, false, buf, buf, count);
if (!is_transaction) {
spi_release(spi_dev);
}
rmutex_unlock(&mut);
}
void SPIClass::setBitOrder(uint8_t order)
{
(void)order;
assert(order == MSBFIRST);
}
void SPIClass::setDataMode(uint8_t dataMode)
{
switch(dataMode) {
default:
case SPI_MODE0:
settings.mode = SPI_MODE_0;
break;
case SPI_MODE1:
settings.mode = SPI_MODE_1;
break;
case SPI_MODE2:
settings.mode = SPI_MODE_2;
break;
case SPI_MODE3:
settings.mode = SPI_MODE_3;
break;
}
}
void SPIClass::setClockDivider(uint8_t divider)
{
static const spi_clk_t clocks[] = {
SPI_CLK_5MHZ, SPI_CLK_1MHZ, SPI_CLK_400KHZ, SPI_CLK_100KHZ
};
assert(divider < ARRAY_SIZE(clocks));
settings.clock = clocks[divider];
}
SPIClass SPI(SPI_DEV(ARDUINO_SPI_INTERFACE));
#else /* MODULE_PERIPH_SPI */
typedef int dont_be_pedantic;
#endif /* MODULE_PERIPH_SPI */