1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/sys/arduino/include/spiport.hpp
2022-09-16 14:00:35 +02:00

237 lines
7.3 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 Definition of the Arduino 'SPI' interface
*
* @author Marian Buschsieweke <marian.buschsieweke@ovgu.de>
*/
#ifndef SPIPORT_H
#define SPIPORT_H
#include "arduino_board.h"
#include "byteorder.h"
#include "periph/spi.h"
#include "rmutex.h"
/**
* @name Arduino compatible SPI modes
* @{
*/
#define SPI_MODE0 (0) /**< CPOL=0, CPHA=0 */
#define SPI_MODE1 (1) /**< CPOL=0, CPHA=1 */
#define SPI_MODE2 (2) /**< CPOL=1, CPHA=0 */
#define SPI_MODE3 (3) /**< CPOL=1, CPHA=1 */
/** @} */
/**
* @name Arduino compatible SPI frequency selection via clock divider
*
* This API assumes the library was targeting a 16 MHz Arduino. It will choose
* the SPI clock frequency matching the requested frequency best, but never
* a frequency greater than the one it would have on Arduinos.
* @{
*/
#define SPI_CLOCK_DIV2 (0) /**< Best match for 8 MHz: 5 MHz */
#define SPI_CLOCK_DIV4 (1) /**< Best match for 4 MHz: 1 MHz */
#define SPI_CLOCK_DIV8 (1) /**< Best match for 2 MHz: 1 MHz */
#define SPI_CLOCK_DIV16 (1) /**< Best match for 1 MHz: 1 MHz */
#define SPI_CLOCK_DIV32 (2) /**< Best match for 500 kHz: 400 kHz */
#define SPI_CLOCK_DIV64 (3) /**< Best match for 250 kHZ: 100 kHz */
#define SPI_CLOCK_DIV128 (3) /**< Best match for 125 kHz: 100 kHz */
/** @} */
/**
* @name Arduino compatible bit order values for SPI
* @{
*/
#define MSBFIRST (1) /**< most significant bit first */
/** @} */
/**
* @brief Arduino SPI configuration interface
*/
class SPISettings {
private:
spi_mode_t mode;
spi_clk_t clock;
public:
/**
* @brief Create a new SPI settings instance
*
* @param clock_hz SPI clock in Hz to use
* @param bitOrder Has to be `MSBFIST`, for compatibility only
* @param dataMode SPI mode to use
*
* The RIOT SPI clock frequency best matching @p clock will be chosen,
* but the frequency will never by greater than what is given in @p clock,
* unless @p clock_hz is is lower than 100kHz, which is the lowest clock
* frequency that will be used.
*/
SPISettings(uint32_t clock_hz, uint8_t bitOrder, uint8_t dataMode);
/**
* @brief Create a new SPI settings instance with default settings
*/
SPISettings() : SPISettings(4000000, MSBFIRST, SPI_MODE0) { }
friend class SPIClass;
};
/**
* @brief Arduino SPI interface
*
* @warning Wrap all SPI transfers in `SPI.beginTransaction()` and `SPI.endTransaction()`
*
* The official Arduino SPI-API allows to use SPI transfers without having to
* call `SPI.beginTransaction()`, but discourages to do so. The RIOT API does
* not provide this feature, instead a call to `SPI.beginTransaction()` is
* mandatory. However, most Arduino code already does this and the remaining
* code should be fixed anyway.
*/
class SPIClass {
private:
spi_t spi_dev;
SPISettings settings;
bool is_transaction;
rmutex_t mut;
public:
/**
* @brief Create a new SPI interface instance
* @param spi_dev The RIOT SPI device to use under the hood
*/
explicit SPIClass(spi_t spi_dev);
/**
* @brief Create a new SPI interface instance for SPI device 0
* @param uc_pinMISO Ignored, for compatibility only
* @param uc_pinSCK Ignored, for compatibility only
* @param uc_pinMOSI Ignored, for compatibility only
* @param uc_pinSS Ignored, for compatibility only
* @param uc_mux Ignored, for compatibility only
*/
SPIClass(uint8_t uc_pinMISO, uint8_t uc_pinSCK, uint8_t uc_pinMOSI,
uint8_t uc_pinSS, uint8_t uc_mux) : SPIClass(SPI_DEV(0))
{
(void)uc_pinMISO;
(void)uc_pinSCK;
(void)uc_pinMOSI;
(void)uc_pinSS;
(void)uc_mux;
}
/**
* @brief Transfer a single byte of data
* @param[in] data Byte to send
* @return The received byte
*/
uint8_t transfer(uint8_t data)
{
transfer(&data, sizeof(data));
return data;
}
/**
* @brief Transfer two bytes of data
* @param[in] data The two bytes to send
* @return The received two bytes
*
* Arduino is sending the most significant byte first, if the SPI interface
* is configured to send the most significant bit first. If the least
* significant bit is send first, Arduino will also send the least
* significant byte first.
*
* This wrapper currently only supports sending the most significant bit
* first over the wire, so this function will also always send the most
* significant byte first.
*/
uint16_t transfer16(uint16_t data)
{
data = htons(data);
transfer(&data, sizeof(data));
return ntohs(data);
}
/**
* @brief Transfer data
* @param[inout] buf Buffer containing the data to send, received
* data will be written here
* @param[in] count Number of bytes to send
*/
void transfer(void *buf, size_t count);
/**
* @brief Doesn't do anything, for compatibility only
*/
void begin() { }
/**
* @brief Doesn't do anything, for compatibility only
*/
void end() { }
/**
* @brief Acquires the SPI interface and applies the given settings
* @param[in] settings Settings to apply
*/
void beginTransaction(SPISettings settings);
/**
* @brief Releases the SPI interface
*/
void endTransaction();
/**
* @brief Sets the bit order to the given value
*
* @details Currently only most significant bit first is supported, as
* practically no hardware exists using lsbfirst. An assertion
* is triggered if lsbfirst is requested.
* @deprecated This function is deprecated in the official Arduino API,
* so it is a good idea to not use it. In RIOT, this function
* is not yet scheduled for removal to allow using Arduino
* libraries using it.
*/
void setBitOrder(uint8_t order);
/**
* @brief Sets the SPI mode (clock phase and polarity)
*
* @deprecated This function is deprecated in the official Arduino API,
* so it is a good idea to not use it. In RIOT, this function
* is not yet scheduled for removal to allow using Arduino
* libraries using it.
*/
void setDataMode(uint8_t mode);
/**
* @brief Sets the SPI clock in an archaic manner
*
* @deprecated This function is deprecated in the official Arduino API,
* so it is a good idea to not use it. In RIOT, this function
* is not yet scheduled for removal to allow using Arduino
* libraries using it.
*/
void setClockDivider(uint8_t divider);
};
/**
* @brief: Instance of the SPI interface as required by the Arduino API
*/
extern SPIClass SPI;
#endif /* SPIPORT_H */
/** @} */