nes-proj/os/dev/spi.h

351 lines
12 KiB
C

/*
* Copyright (c) 2016-2017, Yanzi Networks.
* Copyright (c) 2017, University of Bristol - http://www.bristol.ac.uk/
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*---------------------------------------------------------------------------*/
/**
* \addtogroup dev
* @{
*
* \defgroup spi-hal SPI Hardware Abstraction Layer
*
* The SPI HAL provides a set of common functions that can be used in a
* platform-independent fashion.
*
*
* @{
*
* \file
* Header file for the SPI HAL
*/
/*---------------------------------------------------------------------------*/
#ifndef SPI_H_
#define SPI_H_
/*---------------------------------------------------------------------------*/
#include "contiki.h"
#include "gpio-hal.h"
#include <stdint.h>
#include <stdbool.h>
/*---------------------------------------------------------------------------*/
/* Include Arch-Specific conf */
#ifdef SPI_HAL_CONF_ARCH_HDR_PATH
#include SPI_HAL_CONF_ARCH_HDR_PATH
#endif /* SPI_HAL_CONF_ARCH_HDR_PATH */
/*---------------------------------------------------------------------------*/
#ifdef SPI_CONF_CONTROLLER_COUNT
/**
* \brief Number of SPI module instances on a chip
*/
#define SPI_CONTROLLER_COUNT SPI_CONF_CONTROLLER_COUNT
#else
#define SPI_CONTROLLER_COUNT 0
#endif
/*---------------------------------------------------------------------------*/
/* Convenience macros to enumerate SPI module instances on a chip */
#define SPI_CONTROLLER_SPI0 0
#define SPI_CONTROLLER_SPI1 1
/*---------------------------------------------------------------------------*/
/**
* \brief SPI return codes
*
* @{
*/
typedef enum {
SPI_DEV_STATUS_OK, /* Everything OK */
SPI_DEV_STATUS_EINVAL, /* Erroneous input value */
SPI_DEV_STATUS_TRANSFER_ERR, /* Error during SPI transfer */
SPI_DEV_STATUS_BUS_LOCKED, /* SPI bus is already locked */
SPI_DEV_STATUS_BUS_NOT_OWNED, /* SPI bus is locked by someone else */
SPI_DEV_STATUS_CLOSED /* SPI bus has not opened properly */
} spi_status_t;
/** @} */
/*---------------------------------------------------------------------------*/
/**
* \brief SPI Device Configuration
*
* This is a structure to an architecture-independent SPI configuration.
*
* @{
*/
typedef struct spi_device {
gpio_hal_pin_t pin_spi_sck; /* SPI SCK pin */
gpio_hal_pin_t pin_spi_miso; /* SPI MISO pin */
gpio_hal_pin_t pin_spi_mosi; /* SPI MOSI pin */
gpio_hal_pin_t pin_spi_cs; /* SPI Chip Select pin */
uint32_t spi_bit_rate; /* SPI bit rate */
uint8_t spi_pha; /* SPI mode phase */
uint8_t spi_pol; /* SPI mode polarity */
uint8_t spi_controller; /* ID of SPI controller to use */
} spi_device_t;
/** @} */
/*---------------------------------------------------------------------------*/
/* These are architecture-independent functions to be used by SPI devices. */
/*---------------------------------------------------------------------------*/
/**
* \brief Locks and then opens an SPI controller
* \param dev An SPI device configuration which defines the controller
* to be locked and the opening configuration.
* \return SPI return code
*/
spi_status_t spi_acquire(const spi_device_t *dev);
/**
* \brief Closes and then unlocks an SPI controller
* \param dev An SPI device configuration which defines the controller
* to be closed and unlocked.
* \return SPI return code
*
* Releasing an SPI controller should put it in low-power mode.
* This should work only if the device has already locked the SPI
* controller.
*/
spi_status_t spi_release(const spi_device_t *dev);
/**
* \brief Selects the SPI peripheral
* \param dev An SPI device configuration which defines the CS pin.
* \return SPI return code
*
* Clears the CS pin. This should work only if the device has
* already locked the SPI controller.
*/
spi_status_t spi_select(const spi_device_t *dev);
/**
* \brief Deselects the SPI peripheral
* \param dev An SPI device configuration which defines the CS pin.
* \return SPI return code
*
* Sets the CS pin. Lock is not required.
*/
spi_status_t spi_deselect(const spi_device_t *dev);
/**
* \brief Checks if a device has locked an SPI controller
* \param dev An SPI device configuration which defines the controller.
* \return true if the device has the lock, false otherwise.
*/
bool spi_has_bus(const spi_device_t *dev);
/**
* \brief Writes a single byte to an SPI device
* \param dev An SPI device configuration.
* \param data A byte of data
* \return SPI return code
*
* It should work only if the device has already locked the SPI controller.
*/
spi_status_t spi_write_byte(const spi_device_t *dev, uint8_t data);
/**
* \brief Reads a single byte from an SPI device
* \param dev An SPI device configuration.
* \param data A pointer to a byte of data
* \return SPI return code
*
* It should work only if the device has already locked the SPI controller.
*/
spi_status_t spi_read_byte(const spi_device_t *dev, uint8_t *data);
/**
* \brief Writes a buffer to an SPI device
* \param dev An SPI device configuration.
* \param data A pointer to the data
* \param size Size of the data to write
* \return SPI return code
*
* It should work only if the device has already locked the SPI controller.
*/
spi_status_t spi_write(const spi_device_t *dev,
const uint8_t *data, int size);
/**
* \brief Reads a buffer from an SPI device
* \param dev An SPI device configuration.
* \param data A pointer to the data
* \param size Size of the data to read
* \return SPI return code
*
* It should work only if the device has already locked the SPI controller.
*/
spi_status_t spi_read(const spi_device_t *dev, uint8_t *data, int size);
/**
* \brief Reads and ignores data from an SPI device
* \param dev An SPI device configuration.
* \param size Size of the data to read and ignore
* \return SPI return code
*
* Reads size bytes from the SPI and throws them away.
* It should work only if the device has already locked the SPI controller.
*/
spi_status_t spi_read_skip(const spi_device_t *dev, int size);
/**
* \brief Performs a generic SPI transfer
* \param dev An SPI device configuration.
* \param data A pointer to the data to be written. Set it to NULL to
* skip writing.
* \param wsize Size of data to write.
* \param buf A pointer to buffer to copy the data read. Set to NULL
* to skip reading.
* \param rsize Size of data to read.
* \param ignore Size of data to read and ignore.
* \return SPI return code
*
* It should work only if the device has already locked the SPI controller.
* A total of rlen+ignore_len bytes will be read. The first rlen bytes will
* be copied to buf. The remaining ignore_len bytes won't be copied to the
* buffer. The maximum of wlen and rlen+ignore_len of bytes will be transfered.
*/
spi_status_t spi_transfer(const spi_device_t *dev,
const uint8_t *data, int wsize,
uint8_t *buf, int rsize, int ignore);
/**
* \brief Reads and Writes one byte from/to an SPI device
* \param dev An SPI device configuration.
* \param strobe Byte to write
* \param status Pointer to byte to read
* \return SPI return code
*
* It should work only if the device has already locked the SPI controller.
*/
spi_status_t spi_strobe(const spi_device_t *dev, uint8_t strobe,
uint8_t *status);
/**
* \brief Reads a buffer of bytes from a register of an SPI device
* \param dev An SPI device configuration.
* \param reg Register
* \param data A pointer to the data
* \param size Size of the data to read
* \return SPI return code
*
* It should work only if the device has already locked the SPI controller.
*/
spi_status_t spi_read_register(const spi_device_t *dev, uint8_t reg,
uint8_t *data, int size);
/*---------------------------------------------------------------------------*/
/* These are architecture-specific functions to be implemented by each CPU. */
/*---------------------------------------------------------------------------*/
/**
* \brief Checks if a device has locked an SPI controller
* \param dev An SPI device configuration which defines the controller
* to be checked if it is locked and the respective device.
* \return 1 if the device has the lock, 0 otherwise.
*
*/
bool spi_arch_has_lock(const spi_device_t *dev);
/**
* \brief Checks if an SPI controller is locked by any device
* \param dev An SPI device configuration which defines the controller
* to be checked.
* \return 1 if the controller is locked, 0 otherwise.
*
*/
bool spi_arch_is_bus_locked(const spi_device_t *dev);
/**
* \brief Locks and opens an SPI controller to the configuration specified.
* \param dev An SPI device configuration.
* \return SPI return code
*
* This should work only if the device has already locked the SPI
* controller.
*
*/
spi_status_t spi_arch_lock_and_open(const spi_device_t *dev);
/**
* \brief Closes and unlocks an SPI controller
* \param dev An SPI device configuration that specifies the controller.
* \return SPI return code
*
* This should turn off the SPI controller to put it in low power mode
* and unlock it.
* It should work only if the device has already locked the SPI
* controller.
*
*/
spi_status_t spi_arch_close_and_unlock(const spi_device_t *dev);
/**
* \brief Performs an SPI transfer
* \param dev An SPI device configuration that specifies the controller.
* \param data A pointer to the data to be written. Set it to NULL to
* skip writing.
* \param wlen Length of data to write.
* \param buf A pointer to buffer to copy the data read. Set to NULL
* to skip reading.
* \param rlen Length of data to read.
* \param ignore_len Length of data to read and ignore.
* \return SPI return code
*
* It should work only if the device has already locked the SPI controller.
* A total of rlen+ignore_len bytes will be read. The first rlen bytes will
* be copied to buf. The remaining ignore_len bytes won't be copied to the
* buffer. The maximum of wlen and rlen+ignore_len of bytes will be transfered.
*/
spi_status_t spi_arch_transfer(const spi_device_t *dev,
const uint8_t *data, int wlen,
uint8_t *buf, int rlen,
int ignore_len);
/**
* \brief Selects an SPI device
* \param dev An SPI device configuration that specifies the CS pin.
* \return SPI return code
*
* Clears the CS pin. It should work only if the device has already
* locked the SPI controller.
*/
spi_status_t spi_arch_select(const spi_device_t *dev);
/**
* \brief Deselects an SPI device
* \param dev An SPI device configuration that specifies the CS pin.
* \return SPI return code
*
* Set the CS pin. Locking the SPI controller is not needed.
*/
spi_status_t spi_arch_deselect(const spi_device_t *dev);
#endif /* SPI_H_ */
/*---------------------------------------------------------------------------*/
/**
* @}
* @}
*/