mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
driver/soft_spi: initial implementation
This commit is contained in:
parent
00d5484fcd
commit
fbba6c3851
@ -214,6 +214,11 @@ ifneq (,$(filter sdcard_spi,$(USEMODULE)))
|
||||
USEMODULE += xtimer
|
||||
endif
|
||||
|
||||
ifneq (,$(filter soft_spi,$(USEMODULE)))
|
||||
FEATURES_REQUIRED += periph_gpio
|
||||
USEMODULE += xtimer
|
||||
endif
|
||||
|
||||
ifneq (,$(filter sht11,$(USEMODULE)))
|
||||
USEMODULE += xtimer
|
||||
endif
|
||||
|
@ -115,6 +115,9 @@ endif
|
||||
ifneq (,$(filter sdcard_spi,$(USEMODULE)))
|
||||
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/sdcard_spi/include
|
||||
endif
|
||||
ifneq (,$(filter soft_spi,$(USEMODULE)))
|
||||
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/soft_spi/include
|
||||
endif
|
||||
ifneq (,$(filter veml6070,$(USEMODULE)))
|
||||
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/veml6070/include
|
||||
endif
|
||||
|
265
drivers/include/soft_spi.h
Normal file
265
drivers/include/soft_spi.h
Normal file
@ -0,0 +1,265 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Hamburg University of Applied Sciences
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup driver_soft_spi Soft SPI
|
||||
* @ingroup drivers
|
||||
* @brief Software implemented Serial Peripheral Interface bus
|
||||
* This module provides a software implemented Serial Peripheral Interface bus.
|
||||
* It is intended to be used in situation where hardware spi is not available.
|
||||
* The signatures of the functions are similar to the functions declared in spi.h
|
||||
* The clock speed is approximated by using xtimer_nanosleep.
|
||||
* Currently only the use of MOSI in master mode is implemented. Therefore receiving
|
||||
* data from a slave is currently not possible.
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Software SPI port descriptor definition
|
||||
*
|
||||
* @author Markus Blechschmidt <Markus.Blechschmidt@haw-hamburg.de>
|
||||
*/
|
||||
|
||||
#ifndef SOFT_SPI_H
|
||||
#define SOFT_SPI_H
|
||||
|
||||
#include "periph/gpio.h"
|
||||
#include "periph/spi.h"
|
||||
#include "mutex.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Default SPI device access macro
|
||||
*/
|
||||
#ifndef SOFT_SPI_DEV
|
||||
#define SOFT_SPI_DEV(x) (x)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Define global value for undefined SPI device
|
||||
*/
|
||||
#ifndef SOFT_SPI_UNDEF
|
||||
#define SOFT_SPI_UNDEF (UINT_MAX)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Define value for unused CS line
|
||||
*/
|
||||
#ifndef SOFT_SPI_CS_UNDEF
|
||||
#define SOFT_SPI_CS_UNDEF (GPIO_UNDEF)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Default type for SPI devices
|
||||
*/
|
||||
typedef unsigned int soft_spi_t;
|
||||
|
||||
/**
|
||||
* @brief Chip select pin type overlaps with gpio_t so it can be casted to
|
||||
* this
|
||||
*/
|
||||
typedef gpio_t soft_spi_cs_t;
|
||||
|
||||
/**
|
||||
* @brief Status codes used by the SPI driver interface
|
||||
*/
|
||||
enum {
|
||||
SOFT_SPI_OK = 0, /**< everything went as planned */
|
||||
SOFT_SPI_NODEV = -1, /**< invalid SPI bus specified */
|
||||
SOFT_SPI_NOCS = -2, /**< invalid chip select line specified */
|
||||
SOFT_SPI_NOMODE = -3, /**< selected mode is not supported */
|
||||
SOFT_SPI_NOCLK = -4 /**< selected clock value is not supported */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Available SPI modes, defining the configuration of clock polarity
|
||||
* and clock phase
|
||||
*
|
||||
* RIOT is using the mode numbers as commonly defined by most vendors
|
||||
* (https://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus#Mode_numbers):
|
||||
*
|
||||
* - MODE_0: CPOL=0, CPHA=0 - The first data bit is sampled by the receiver on
|
||||
* the first SCK rising SCK edge (this mode is used most often).
|
||||
* - MODE_1: CPOL=0, CPHA=1 - The first data bit is sampled by the receiver on
|
||||
* the second rising SCK edge.
|
||||
* - MODE_2: CPOL=1, CPHA=0 - The first data bit is sampled by the receiver on
|
||||
* the first falling SCK edge.
|
||||
* - MODE_3: CPOL=1, CPHA=1 - The first data bit is sampled by the receiver on
|
||||
* the second falling SCK edge.
|
||||
*/
|
||||
typedef enum {
|
||||
SOFT_SPI_MODE_0 = 0, /**< CPOL=0, CPHA=0 */
|
||||
SOFT_SPI_MODE_1, /**< CPOL=0, CPHA=1 */
|
||||
SOFT_SPI_MODE_2, /**< CPOL=1, CPHA=0 */
|
||||
SOFT_SPI_MODE_3 /**< CPOL=1, CPHA=1 */
|
||||
} soft_spi_mode_t;
|
||||
|
||||
/**
|
||||
* @brief Available SPI clock speeds
|
||||
*
|
||||
* The actual speed of the bus varies between CPUs and depends on the speed
|
||||
* of the processing. The values of the enum entries represent the approximate
|
||||
* delay between two clock edges.
|
||||
*/
|
||||
typedef enum {
|
||||
SOFT_SPI_CLK_100KHZ = 5000, /**< drive the SPI bus with less than 100kHz */
|
||||
SOFT_SPI_CLK_400KHZ = 1250, /**< drive the SPI bus with less than 400kHz */
|
||||
SOFT_SPI_CLK_DEFAULT = 0, /**< drive the SPI bus with maximum speed possible */
|
||||
} soft_spi_clk_t;
|
||||
|
||||
/**
|
||||
* @brief Software SPI port descriptor
|
||||
*/
|
||||
typedef struct {
|
||||
gpio_t miso_pin; /**< MOSI pin */
|
||||
gpio_t mosi_pin; /**< MOSI pin */
|
||||
gpio_t clk_pin; /**< CLK pin */
|
||||
soft_spi_mode_t soft_spi_mode; /**< data and clock polarity */
|
||||
soft_spi_clk_t soft_spi_clk; /**< clock speed */
|
||||
} soft_spi_conf_t;
|
||||
|
||||
/**
|
||||
* @brief Basic initialization of the given SPI bus
|
||||
*
|
||||
* This function does the basic initialization including pin configuration for
|
||||
* MISO, MOSI, and CLK pins.
|
||||
*
|
||||
* Errors (e.g. invalid @p bus parameter) are not signaled through a return
|
||||
* value, but should be signaled using the assert() function internally.
|
||||
*
|
||||
* @note This function MUST not be called more than once per bus!
|
||||
*
|
||||
* @param[in] bus SPI device to initialize
|
||||
*/
|
||||
void soft_spi_init(soft_spi_t bus);
|
||||
|
||||
/**
|
||||
* @brief Initialize the used SPI bus pins, i.e. MISO, MOSI, and CLK
|
||||
*
|
||||
* After calling soft_spi_init, the pins must be initialized. In normal cases,
|
||||
* this function will not be used.
|
||||
*
|
||||
* The pins used are configured in the board's periph_conf.h.
|
||||
*
|
||||
* @param[in] bus SPI device the pins are configure for
|
||||
*/
|
||||
void soft_spi_init_pins(soft_spi_t bus);
|
||||
|
||||
/**
|
||||
* @brief Initialize the given chip select pin
|
||||
*
|
||||
* The chip select must be any generic GPIO pin (e.g. GPIO_PIN(x,y)). It must be
|
||||
* called once before the use of the chip select pin in transaction.
|
||||
*
|
||||
* @param[in] bus SPI device that is used with the given CS line
|
||||
* @param[in] cs chip select pin to initialize
|
||||
*
|
||||
* @return SOFT_SPI_OK on success
|
||||
* @return SOFT_SPI_NODEV on invalid device
|
||||
* @return SOFT_SPI_NOCS on invalid CS pin/line
|
||||
*/
|
||||
int soft_spi_init_cs(soft_spi_t bus, soft_spi_cs_t cs);
|
||||
|
||||
/**
|
||||
* @brief Start a new SPI transaction
|
||||
*
|
||||
* Starting a new SPI transaction will get exclusive access to the SPI bus
|
||||
* and configure it according to the given values. If another SPI transaction
|
||||
* is active when this function is called, this function will block until the
|
||||
* other transaction is complete (soft_spi_relase was called).
|
||||
*
|
||||
* @note This function expects the @p bus and the @p cs parameters to be
|
||||
* valid (they are checked in soft_spi_init and soft_spi_init_cs before)
|
||||
*
|
||||
* @param[in] bus SPI device to access
|
||||
* @param[in] cs chip select pin/line to use
|
||||
* @param[in] mode mode to use for the new transaction
|
||||
* @param[in] clk bus clock speed to use for the transaction
|
||||
*
|
||||
* @return SOFT_SPI_OK on success
|
||||
* @return SOFT_SPI_NOMODE if given mode is not supported
|
||||
* @return SOFT_SPI_NOCLK if given clock speed is not supported
|
||||
*/
|
||||
int soft_spi_acquire(soft_spi_t bus, soft_spi_cs_t cs, soft_spi_mode_t mode, soft_spi_clk_t clk);
|
||||
|
||||
/**
|
||||
* @brief Finish an ongoing SPI transaction by releasing the given SPI bus
|
||||
*
|
||||
* After release, the given SPI bus should be fully powered down until acquired
|
||||
* again.
|
||||
*
|
||||
* @param[in] bus SPI device to release
|
||||
*/
|
||||
void soft_spi_release(soft_spi_t bus);
|
||||
|
||||
/**
|
||||
* @brief Transfer one byte on the given SPI bus
|
||||
* Currently only the use of MOSI in master mode is implemented. Therefore receiving
|
||||
* data from a slave is currently not possible.
|
||||
*
|
||||
* @param[in] bus SPI device to use
|
||||
* @param[in] cs chip select pin/line to use
|
||||
* @param[in] cont if true, keep device selected after transfer
|
||||
* @param[in] out byte to send out, set NULL if only receiving
|
||||
*
|
||||
* @return the received byte
|
||||
*/
|
||||
uint8_t soft_spi_transfer_byte(soft_spi_t bus, soft_spi_cs_t cs, bool cont, uint8_t out);
|
||||
|
||||
/**
|
||||
* @brief Transfer a number bytes using the given SPI bus
|
||||
*
|
||||
* @param[in] bus SPI device to use
|
||||
* @param[in] cs chip select pin/line to use
|
||||
* @param[in] cont if true, keep device selected after transfer
|
||||
* @param[in] out buffer to send data from, set NULL if only receiving
|
||||
* @param[out] in buffer to read into, set NULL if only sending
|
||||
* @param[in] len number of bytes to transfer
|
||||
*/
|
||||
void soft_spi_transfer_bytes(soft_spi_t bus, soft_spi_cs_t cs, bool cont,
|
||||
const void *out, void *in, size_t len);
|
||||
|
||||
/**
|
||||
* @brief Transfer one byte to/from a given register address
|
||||
*
|
||||
* This function is a shortcut function for easier handling of SPI devices that
|
||||
* implement a register based access scheme.
|
||||
*
|
||||
* @param[in] bus SPI device to use
|
||||
* @param[in] cs chip select pin/line to use
|
||||
* @param[in] reg register address to transfer data to/from
|
||||
* @param[in] out byte to send, set NULL if only receiving data
|
||||
*
|
||||
* @return value that was read from the given register address
|
||||
*/
|
||||
uint8_t soft_spi_transfer_reg(soft_spi_t bus, soft_spi_cs_t cs, uint8_t reg, uint8_t out);
|
||||
|
||||
/**
|
||||
* @brief Transfer a number of bytes to/from a given register address
|
||||
*
|
||||
* This function is a shortcut function for easier handling of SPI devices that
|
||||
* implement a register based access scheme.
|
||||
*
|
||||
* @param[in] bus SPI device to use
|
||||
* @param[in] cs chip select pin/line to use
|
||||
* @param[in] reg register address to transfer data to/from
|
||||
* @param[in] out buffer to send data from, set NULL if only receiving
|
||||
* @param[out] in buffer to read into, set NULL if only sending
|
||||
* @param[in] len number of bytes to transfer
|
||||
*/
|
||||
void soft_spi_transfer_regs(soft_spi_t bus, soft_spi_cs_t cs, uint8_t reg,
|
||||
const void *out, void *in, size_t len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SOFT_SPI_H */
|
||||
/** @} */
|
1
drivers/soft_spi/Makefile
Normal file
1
drivers/soft_spi/Makefile
Normal file
@ -0,0 +1 @@
|
||||
include $(RIOTBASE)/Makefile.base
|
60
drivers/soft_spi/include/soft_spi_params.h
Normal file
60
drivers/soft_spi/include/soft_spi_params.h
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Hamburg University of Applied Sciences
|
||||
*
|
||||
* 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 driver_soft_spi
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Software SPI configuration
|
||||
*
|
||||
* @author Markus Blechschmidt <Markus.Blechschmidt@haw-hamburg.de>
|
||||
*/
|
||||
|
||||
#ifndef SOFT_SPI_PARAMS_H
|
||||
#define SOFT_SPI_PARAMS_H
|
||||
|
||||
#include "soft_spi.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef SOFT_SPI_PARAM_MISO
|
||||
#define SOFT_SPI_PARAM_MISO (GPIO_UNDEF)
|
||||
#endif
|
||||
#ifndef SOFT_SPI_PARAM_MOSI
|
||||
#define SOFT_SPI_PARAM_MOSI (GPIO_PIN(0, 0))
|
||||
#endif
|
||||
#ifndef SOFT_SPI_PARAM_CLK
|
||||
#define SOFT_SPI_PARAM_CLK (GPIO_PIN(0, 1))
|
||||
#endif
|
||||
|
||||
#define SOFT_SPI_PARAMS_DEFAULT {\
|
||||
.miso_pin = SOFT_SPI_PARAM_MISO,\
|
||||
.mosi_pin = SOFT_SPI_PARAM_MOSI,\
|
||||
.clk_pin = SOFT_SPI_PARAM_CLK,\
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sotware SPI port descriptor array
|
||||
*/
|
||||
static soft_spi_conf_t soft_spi_config[] = {
|
||||
#ifdef SOFT_SPI_PARAMS_CUSTOM
|
||||
SOFT_SPI_PARAMS_CUSTOM,
|
||||
#else
|
||||
SOFT_SPI_PARAMS_DEFAULT,
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SOFT_SPI_PARAMS_H */
|
||||
/** @} */
|
211
drivers/soft_spi/soft_spi.c
Normal file
211
drivers/soft_spi/soft_spi.c
Normal file
@ -0,0 +1,211 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Hamburg University of Applied Sciences
|
||||
*
|
||||
* 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 driver_soft_spi
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Software SPI implementation
|
||||
*
|
||||
* @author Markus Blechschmidt <Markus.Blechschmidt@haw-hamburg.de>
|
||||
* @author Peter Kietzmann <peter.kietzmann@haw-hamburg.de>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "mutex.h"
|
||||
#include "periph/gpio.h"
|
||||
#include "xtimer.h"
|
||||
|
||||
#include "soft_spi.h"
|
||||
#include "soft_spi_params.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
/**
|
||||
* @brief Allocate one lock per SPI device
|
||||
*/
|
||||
static mutex_t locks[sizeof soft_spi_config];
|
||||
|
||||
static inline bool soft_spi_bus_is_valid(soft_spi_t bus)
|
||||
{
|
||||
unsigned int soft_spi_num = (unsigned int) bus;
|
||||
|
||||
if (sizeof(soft_spi_config) / sizeof(soft_spi_config[0]) < soft_spi_num) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void soft_spi_init(soft_spi_t bus)
|
||||
{
|
||||
DEBUG("Soft SPI init\n");
|
||||
|
||||
assert(soft_spi_bus_is_valid(bus));
|
||||
|
||||
/* initialize device lock */
|
||||
mutex_init(&locks[bus]);
|
||||
soft_spi_init_pins(bus);
|
||||
}
|
||||
|
||||
void soft_spi_init_pins(soft_spi_t bus)
|
||||
{
|
||||
DEBUG("Soft SPI soft_spi_init_pins\n");
|
||||
|
||||
assert(soft_spi_bus_is_valid(bus));
|
||||
|
||||
/* check that miso is not mosi is not clk*/
|
||||
assert(soft_spi_config[bus].mosi_pin != soft_spi_config[bus].miso_pin);
|
||||
assert(soft_spi_config[bus].mosi_pin != soft_spi_config[bus].clk_pin);
|
||||
assert(soft_spi_config[bus].miso_pin != soft_spi_config[bus].clk_pin);
|
||||
/* mandatory pins */
|
||||
assert((GPIO_UNDEF != soft_spi_config[bus].mosi_pin) || (GPIO_UNDEF != soft_spi_config[bus].miso_pin));
|
||||
assert(GPIO_UNDEF != soft_spi_config[bus].clk_pin);
|
||||
|
||||
/* initialize clock pin */
|
||||
gpio_init(soft_spi_config[bus].clk_pin, GPIO_OUT);
|
||||
/* initialize optional pins */
|
||||
if (GPIO_UNDEF != soft_spi_config[bus].mosi_pin) {
|
||||
gpio_init(soft_spi_config[bus].mosi_pin, GPIO_OUT);
|
||||
gpio_clear(soft_spi_config[bus].mosi_pin);
|
||||
}
|
||||
if (GPIO_UNDEF != soft_spi_config[bus].miso_pin) {
|
||||
gpio_init(soft_spi_config[bus].mosi_pin, GPIO_IN);
|
||||
}
|
||||
}
|
||||
|
||||
int soft_spi_init_cs(soft_spi_t bus, soft_spi_cs_t cs)
|
||||
{
|
||||
DEBUG("Soft SPI init CS\n");
|
||||
if (!soft_spi_bus_is_valid(bus)) {
|
||||
DEBUG("Soft SPI bus not valid\n");
|
||||
return SOFT_SPI_NODEV;
|
||||
}
|
||||
|
||||
if ((cs != GPIO_UNDEF) && (cs != SOFT_SPI_CS_UNDEF)) {
|
||||
DEBUG("Soft SPI set user CS line\n");
|
||||
gpio_init(cs, GPIO_OUT);
|
||||
gpio_set(cs);
|
||||
}
|
||||
|
||||
return SOFT_SPI_OK;
|
||||
}
|
||||
|
||||
int soft_spi_acquire(soft_spi_t bus, soft_spi_cs_t cs, soft_spi_mode_t mode, soft_spi_clk_t clk)
|
||||
{
|
||||
(void) cs;
|
||||
assert(soft_spi_bus_is_valid(bus));
|
||||
|
||||
/* lock bus */
|
||||
mutex_lock(&locks[bus]);
|
||||
|
||||
if ((mode != SOFT_SPI_MODE_0) && (mode != SOFT_SPI_MODE_1) &&
|
||||
(mode != SOFT_SPI_MODE_2) && (mode != SOFT_SPI_MODE_3)) {
|
||||
return SOFT_SPI_NOMODE;
|
||||
}
|
||||
soft_spi_config[bus].soft_spi_mode = mode;
|
||||
switch (mode) {
|
||||
case SOFT_SPI_MODE_0:
|
||||
case SOFT_SPI_MODE_1:
|
||||
/* CPOL=0 */
|
||||
gpio_clear(soft_spi_config[bus].clk_pin);
|
||||
break;
|
||||
case SOFT_SPI_MODE_2:
|
||||
case SOFT_SPI_MODE_3:
|
||||
/* CPOL=1 */
|
||||
gpio_set(soft_spi_config[bus].clk_pin);
|
||||
break;
|
||||
}
|
||||
soft_spi_config[bus].soft_spi_clk = clk;
|
||||
return SOFT_SPI_OK;
|
||||
}
|
||||
|
||||
void soft_spi_release(soft_spi_t bus)
|
||||
{
|
||||
assert(soft_spi_bus_is_valid(bus));
|
||||
mutex_unlock(&locks[bus]);
|
||||
}
|
||||
|
||||
static inline uint8_t _transfer_one_byte(soft_spi_t bus, uint8_t out)
|
||||
{
|
||||
int8_t bit = 0, i = 0;
|
||||
if (SOFT_SPI_MODE_1 == soft_spi_config[bus].soft_spi_mode ||
|
||||
SOFT_SPI_MODE_3 == soft_spi_config[bus].soft_spi_mode) {
|
||||
/* CPHA = 1*/
|
||||
gpio_toggle(soft_spi_config[bus].clk_pin);
|
||||
}
|
||||
|
||||
bit = (out & (1 << 7)) >> 7;
|
||||
gpio_write(soft_spi_config[bus].mosi_pin, bit);
|
||||
for (i = 6; i >= 0; i--) {
|
||||
xtimer_nanosleep(soft_spi_config[bus].soft_spi_clk);
|
||||
gpio_toggle(soft_spi_config[bus].clk_pin);
|
||||
xtimer_nanosleep(soft_spi_config[bus].soft_spi_clk);
|
||||
gpio_toggle(soft_spi_config[bus].clk_pin);
|
||||
bit = (out & (1 << i)) >> i;
|
||||
gpio_write(soft_spi_config[bus].mosi_pin, bit);
|
||||
}
|
||||
xtimer_nanosleep(soft_spi_config[bus].soft_spi_clk);
|
||||
gpio_toggle(soft_spi_config[bus].clk_pin);
|
||||
|
||||
if (SOFT_SPI_MODE_0 == soft_spi_config[bus].soft_spi_mode ||
|
||||
SOFT_SPI_MODE_2 == soft_spi_config[bus].soft_spi_mode) {
|
||||
/* CPHASE = 1 */
|
||||
xtimer_nanosleep(soft_spi_config[bus].soft_spi_clk);
|
||||
gpio_toggle(soft_spi_config[bus].clk_pin);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
uint8_t soft_spi_transfer_byte(soft_spi_t bus, soft_spi_cs_t cs, bool cont, uint8_t out)
|
||||
{
|
||||
DEBUG("Soft SPI soft_spi_transfer_bytes\n");
|
||||
assert(soft_spi_bus_is_valid(bus));
|
||||
|
||||
uint8_t retval = 0;
|
||||
|
||||
/* activate the given chip select line */
|
||||
if ((cs != GPIO_UNDEF) && (cs != SOFT_SPI_CS_UNDEF)) {
|
||||
gpio_clear((gpio_t)cs);
|
||||
}
|
||||
|
||||
retval = _transfer_one_byte(bus, out);
|
||||
|
||||
if (!cont) {
|
||||
if ((cs != GPIO_UNDEF) && (cs != SOFT_SPI_CS_UNDEF)) {
|
||||
gpio_set((gpio_t)cs);
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void soft_spi_transfer_bytes(soft_spi_t bus, soft_spi_cs_t cs, bool cont,
|
||||
const void *out, void *in, size_t len)
|
||||
{
|
||||
DEBUG("Soft SPI soft_spi_transfer_bytes\n");
|
||||
|
||||
assert(soft_spi_bus_is_valid(bus));
|
||||
|
||||
uint8_t tmp = 0;
|
||||
|
||||
for (size_t i = 0; i < len-1; i++) {
|
||||
tmp = (NULL != out) ? ((uint8_t *)out)[i] : 0;
|
||||
uint8_t retval = soft_spi_transfer_byte(bus, cs, true, tmp);
|
||||
if (NULL != in) {
|
||||
((uint8_t *)in)[0] = retval;
|
||||
}
|
||||
}
|
||||
|
||||
tmp = (NULL != out) ? ((uint8_t *)out)[len-1] : 0;
|
||||
soft_spi_transfer_byte(bus, cs, cont, tmp);
|
||||
}
|
16
tests/driver_soft_spi/Makefile
Normal file
16
tests/driver_soft_spi/Makefile
Normal file
@ -0,0 +1,16 @@
|
||||
APPLICATION = driver_soft_spi
|
||||
include ../Makefile.tests_common
|
||||
|
||||
BOARD ?= native
|
||||
|
||||
USEMODULE += soft_spi
|
||||
|
||||
# set Soft SPI bus and pins to default values
|
||||
TEST_SOFT_SPI_DEV ?= SOFT_SPI_DEV\(0\)
|
||||
TEST_CS_PIN ?= GPIO_PIN\(0,2\)
|
||||
|
||||
# export SPI and pins
|
||||
CFLAGS += -DTEST_SOFT_SPI_DEV=$(TEST_SOFT_SPI_DEV)
|
||||
CFLAGS += -DTEST_CS_PIN=$(TEST_CS_PIN)
|
||||
|
||||
include $(RIOTBASE)/Makefile.include
|
12
tests/driver_soft_spi/README.md
Normal file
12
tests/driver_soft_spi/README.md
Normal file
@ -0,0 +1,12 @@
|
||||
Expected result
|
||||
===============
|
||||
The test code transmits one byte with each SPI mode and a string over the
|
||||
software SPI MOSI line. This can be verified with a Logic Analyzer connected to
|
||||
the corresponding pins. When you see 0xa5 in all four SPI modes and the string
|
||||
"Soft SPI Test String" in SPI mode 0 being transmitted via the CLK and MOSI pin,
|
||||
the test is successful.
|
||||
|
||||
Notes
|
||||
==========
|
||||
- Because the module does not cover MISO inputs, neither does the test.
|
||||
- The definition of SOFT SPI devices is done via the CFLAGS in the Makefile
|
71
tests/driver_soft_spi/main.c
Normal file
71
tests/driver_soft_spi/main.c
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Hamburg University of Applied Sciences
|
||||
*
|
||||
* 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 tests
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Application for testing the software SPI driver implementations
|
||||
*
|
||||
*
|
||||
* @author Markus Blechschmidt <Markus.Blechschmidt@haw-hamburg.de>
|
||||
* @author Peter Kietzmann <peter.kietzmann@haw-hamburg.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "soft_spi.h"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
puts("Minimal test application for the software SPI driver");
|
||||
|
||||
char string[] = "Soft SPI Test String";
|
||||
|
||||
soft_spi_t soft_spi = TEST_SOFT_SPI_DEV;
|
||||
soft_spi_cs_t cs = TEST_CS_PIN;
|
||||
|
||||
/* Initialize software SPI device */
|
||||
soft_spi_init(soft_spi);
|
||||
|
||||
/* Initialize CS pin */
|
||||
int tmp = soft_spi_init_cs(soft_spi, cs);
|
||||
if (tmp != SOFT_SPI_OK) {
|
||||
printf("error: unable to initialize the given chip select line %i\n", tmp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
puts("Send 0xa5 in all four modes");
|
||||
soft_spi_acquire(soft_spi, cs, SOFT_SPI_MODE_0, SOFT_SPI_CLK_100KHZ);
|
||||
soft_spi_transfer_byte(soft_spi, cs, false, 0xa5);
|
||||
soft_spi_release(soft_spi);
|
||||
|
||||
soft_spi_acquire(soft_spi, cs, SOFT_SPI_MODE_1, SOFT_SPI_CLK_100KHZ);
|
||||
soft_spi_transfer_byte(soft_spi, cs, false, 0xa5);
|
||||
soft_spi_release(soft_spi);
|
||||
|
||||
soft_spi_acquire(soft_spi, cs, SOFT_SPI_MODE_2, SOFT_SPI_CLK_100KHZ);
|
||||
soft_spi_transfer_byte(soft_spi, cs, false, 0xa5);
|
||||
soft_spi_release(soft_spi);
|
||||
|
||||
soft_spi_acquire(soft_spi, cs, SOFT_SPI_MODE_3, SOFT_SPI_CLK_100KHZ);
|
||||
soft_spi_transfer_byte(soft_spi, cs, false, 0xa5);
|
||||
soft_spi_release(soft_spi);
|
||||
|
||||
printf("Send %s\n",string);
|
||||
soft_spi_acquire(soft_spi, cs, SOFT_SPI_MODE_0, SOFT_SPI_CLK_100KHZ);
|
||||
soft_spi_transfer_bytes(soft_spi, cs, false, string, NULL, sizeof string);
|
||||
soft_spi_release(soft_spi);
|
||||
|
||||
puts("Soft SPI Test End");
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user