Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cpu/native: Allow Access to Hardware SPI Bus on Linux #11352

Merged
merged 2 commits into from
Oct 16, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions boards/native/doc.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ OS/RIOT/images/Native.jpg)
- LEDs: One red and one green LED - state changes are printed to the UART
- PWM: Dummy PWM
- QDEC: Emulated according to PWM
- SPI: Runtime configurable - `/dev/spidev*` are supported (Linux host only)
*/
3 changes: 3 additions & 0 deletions cpu/native/Makefile.dep
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
ifneq (,$(filter periph_spi,$(USEMODULE)))
USEMODULE += periph_spidev_linux
endif
5 changes: 5 additions & 0 deletions cpu/native/Makefile.features
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,8 @@ FEATURES_PROVIDED += periph_cpuid
FEATURES_PROVIDED += periph_hwrng
FEATURES_PROVIDED += periph_pm
FEATURES_PROVIDED += periph_pwm

# Access to hardware SPI bus is only supported on Linux hosts
ifeq ($(OS),Linux)
FEATURES_PROVIDED += periph_spi
endif
41 changes: 39 additions & 2 deletions cpu/native/include/periph_conf.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
#define PERIPH_CONF_H

#ifdef __cplusplus
extern "C" {
extern "C" {
#endif

/**
Expand Down Expand Up @@ -50,7 +50,6 @@

/**
* @brief xtimer configuration
* @{
*/
#define XTIMER_OVERHEAD 14

Expand Down Expand Up @@ -86,6 +85,44 @@
#define QDEC_NUMOF (8U)
#endif

/**
* @name SPI configuration (Linux host only)
* @{
*/
#if !defined(SPI_NUMOF) || defined(DOXYGEN)
/**
* @brief Amount of SPI devices
*
* Allows up to SPI_NUMOF SPI devices with each having up to SPI_MAXCS hardware
* cable select lines. Assignment to hardware devices can be configured at
* runtime using the `--spi` startup parameter.
*
* Can be overriden during compile time with a `-DSPI_NUMOF=n` flag.
*/
#define SPI_NUMOF (1U)
#endif

#if !defined(SPI_MAXCS) || defined(DOXYGEN)
/**
* @brief Maximum amount of chip select lines per bus
*
* Allows up to SPI_MAXCS hardware cable select lines per SPI device. The n-th
* hardware select line can be used with the SPI_HWCS macro.
*/
#define SPI_MAXCS (4U)
#endif

/**
* @brief Hardware chip select access macro.
*
* The amount of available hardware chip select lines depends on the SPI_MAXCS
* parameter. If the line is actually available at runtime depends of whether a
* `--spi` startup parameter with the corresponding SPI device and HWCS-line
* parameter has been given.
*/
#define SPI_HWCS(x) (x)
/** @} */

#ifdef __cplusplus
}
#endif
Expand Down
46 changes: 46 additions & 0 deletions cpu/native/include/periph_cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,52 @@ extern "C" {
#define PROVIDES_PM_SET_LOWEST
/** @} */

/* Configuration for the wrapper around the Linux SPI API (periph_spidev_linux)
*
* Needs to go here, otherwise the SPI_NEEDS_ are defined after inclusion of
* spi.h.
*/
#if defined(MODULE_PERIPH_SPIDEV_LINUX) || defined(DOXYGEN)

/**
* @name SPI Configuration
*/

/**
* @brief Use the common `transfer_byte` SPI function
*/
#define PERIPH_SPI_NEEDS_TRANSFER_BYTE
/**
* @brief Use the common `transfer_reg` SPI function
*/
#define PERIPH_SPI_NEEDS_TRANSFER_REG
/**
* @brief Use the common `transfer_regs` SPI function
*/
#define PERIPH_SPI_NEEDS_TRANSFER_REGS

/**
* @brief Use a custom clock speed type
*/
#define HAVE_SPI_CLK_T
/**
* @brief SPI clock speed values
*
* The Linux userspace driver takes values in Hertz, which values are available
* can only be determined at runtime.
* @{
*/
typedef enum {
SPI_CLK_100KHZ = (100000U),
SPI_CLK_400KHZ = (400000U),
SPI_CLK_1MHZ = (1000000U),
SPI_CLK_5MHZ = (5000000U),
SPI_CLK_10MHZ = (10000000U)
} spi_clk_t;
/** @} */

#endif /* MODULE_PERIPH_SPI | DOXYGEN */

#ifdef __cplusplus
}
#endif
Expand Down
134 changes: 134 additions & 0 deletions cpu/native/include/spidev_linux.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
/*
* Copyright (C) 2019 Frank Hessel <frank@fhessel.de>
*
* 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 drivers_spidev_linux Linux User Mode SPI Driver
* @ingroup cpu_native
* @brief Implementation of SPI access from Linux User Space
*
* This module allows to connect a RIOT application that runs on a Linux host to
* the physical SPI bus(ses) of that host. To do so, the application has to be
* compiled for the native board in a Linux environment.
*
* SPI support is automatically included if either a module requiring the
* `PERIPH_SPI` feature is added to the application or if it is explicitly
* listed as `FEATURES_REQUIRED` in the application's Makefile.
*
* At runtime, the process has to be connected to a specific bus on the host
* machine. SPI busses are exposed as `/dev/spidevB.D` character files, where B
* is the Bus ID (MISO, MOSI and SCLK lines) and D denotes the connected device
* or hardware chip select line. Ideally, this structure should be reflected
* when mapping the device files to RIOT SPI busses.
*
* Example:
*
* ```
* $ ./riot_native_app --spi=0:0:/dev/spidev0.0 --spi=0:1:/dev/spidev0.1
* ```
*
* This will add `/dev/spidev0.0` and `/dev/spidev0.1` as SPI_DEV(0) in RIOT.
* The first device can be used with SPI_HWCS(0) as CS parameter, the second one
* with SPI_HWCS(1) as CS parameter.
*
* Multiple SPI busses can be added by increasing SPI_NUMOF in the Makefile:
* ```
* CFLAGS += -DSPI_NUMOF=n
* ```
*
* The sames goes for the SPI_MAXCS parameter that defines the maximum number of
* SPI_HWCS values per bus.
*
* Busses that aren't assigned during startup will return either SPI_NODEV or
* SPI_NOCS when accessed.
*
* If the SPI API is called with SPI_CS_UNDEF as CS parameter, the driver will
* select the file descriptor with the lowest HWCS id for that bus, but the
* actual CS line will not be pulled low (if the hardware supports this). This
* would (in principle) allow to control CS manually.
*
* @{
*
* @file
* @brief Implementation of SPI access from Linux User Space
*
* @author Frank Hessel <frank@fhessel.de>
*/

#ifndef SPIDEV_LINUX_H
#define SPIDEV_LINUX_H

#if defined(__linux__) || defined(DOXYGEN) /* Linux-only */

#include "periph/spi.h"

#include "mutex.h"
#include "periph_conf.h"

#ifdef __cplusplus
extern "C" {
#endif

/**
* @brief Status codes for SPI device setup
*/
enum {
SPI_SETUP_OK = 0, /**< parameters are sound */
SPI_SETUP_INVALID = -1, /**< invalid params or duplicate definition */
};

/**
* @brief Static runtime configuration for SPI port + CS line
*
* Contains the information that is passed by command line on startup
*/
typedef struct spidev_linux_conf {
/** Filename for a specific SPI device + CS line (like /dev/spidev0.0) */
char *device_filename[SPI_MAXCS];
} spidev_linux_conf_t;

/**
* @brief Dynamic runtime state for SPI port + CS line
*
* Contains state of the line (whether if it's opened, in use, available, ...)
*/
typedef struct spidev_linux_state {
/** Mutex for the whole bus (all CS lines) */
mutex_t lock;
/** File descriptors for each CS line on the bus */
int fd[SPI_MAXCS];
} spidev_linux_state_t;

/**
* @brief register `/dev/spidev*` device to be used for SPI
*
* @param[in] bus SPI bus id of the device
* @param[in] cs CS line to configure
* @param[in] name path name for `/dev/spidev*` device
* @return SPI_SETUP_OK On success
* @return SPI_SETUP_INVALID On invalid parameters
*/
int spidev_linux_setup(spi_t bus, spi_cs_t cs, const char *name);

/**
* @brief Close open SPI file descriptors
*/
void spidev_linux_teardown(void);

kaspar030 marked this conversation as resolved.
Show resolved Hide resolved
#ifdef __cplusplus
}
#endif

#else
/* Create the error in the header file as spi.c will be compiled to late to show it */
#ifdef MODULE_PERIPH_SPIDEV_LINUX
#error "MODULE periph_spidev_linux is only available on Linux"
#endif
#endif /* defined(__linux__) || defined(DOXYGEN) */

#endif /* SPIDEV_LINUX_H */
/** @} */
11 changes: 11 additions & 0 deletions cpu/native/periph/pm.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@
#include "async_read.h"
#include "tty_uart.h"

#ifdef MODULE_PERIPH_SPIDEV_LINUX
/* Only manage SPI if it is part of the build */
#include "spidev_linux.h"
#endif

#define ENABLE_DEBUG (0)
#include "debug.h"

Expand All @@ -44,6 +49,9 @@ void pm_set_lowest(void)
void pm_off(void)
{
puts("\nnative: exiting");
#ifdef MODULE_PERIPH_SPIDEV_LINUX
spidev_linux_teardown();
#endif
real_exit(EXIT_SUCCESS);
}

Expand All @@ -52,6 +60,9 @@ void pm_reboot(void)
printf("\n\n\t\t!! REBOOT !!\n\n");

native_async_read_cleanup();
#ifdef MODULE_PERIPH_SPIDEV_LINUX
spidev_linux_teardown();
#endif

if (real_execve(_native_argv[0], _native_argv, NULL) == -1) {
err(EXIT_FAILURE, "reboot: execve");
Expand Down
Loading