mirror of
https://github.com/thelsing/knx.git
synced 2025-10-12 11:15:54 +02:00
git-subtree-dir: examples/knx-cc1310/coresdk_cc13xx_cc26xx git-subtree-split: 0d78d3280357416a5c0388148cda13717c9ffaa5
922 lines
35 KiB
C
922 lines
35 KiB
C
/*
|
|
* Copyright (c) 2015-2019, Texas Instruments Incorporated
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
*
|
|
* * 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.
|
|
*
|
|
* * Neither the name of Texas Instruments Incorporated 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 HOLDERS 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 OWNER 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.
|
|
*/
|
|
/*!*****************************************************************************
|
|
* @file SPI.h
|
|
*
|
|
* @brief Serial Peripheral Interface (SPI) Driver Interface
|
|
*
|
|
* @anchor ti_drivers_SPI_Overview
|
|
* # Overview
|
|
* The Serial Peripheral Interface (SPI) driver is a generic, full-duplex
|
|
* driver that transmits and receives data on a SPI bus. SPI is sometimes
|
|
* called SSI (Synchronous Serial Interface).
|
|
* The SPI protocol defines the format of a data transfer over the SPI bus,
|
|
* but it leaves flow control, data formatting, and handshaking mechanisms
|
|
* to higher-level software layers.
|
|
*
|
|
* The SPI driver operates on some key definitions and assumptions:
|
|
* - The driver operates transparently from the chip select. Some SPI
|
|
* controllers feature a hardware chip select to assert SPI slave
|
|
* peripherals. See the specific device implementations on chip
|
|
* select requirements.
|
|
*
|
|
* - The SPI protocol does not account for a built-in handshaking mechanism
|
|
* and neither does this SPI driver. Therefore, when operating in
|
|
* #SPI_SLAVE mode, the application must provide such a mechanism to
|
|
* ensure that the SPI slave is ready for the SPI master. The SPI slave
|
|
* must call #SPI_transfer() *before* the SPI master starts transmitting.
|
|
* Some example application mechanisms could include:
|
|
* - Timed delays on the SPI master to guarantee the SPI slave is ready
|
|
* for a SPI transaction.
|
|
* - A form of GPIO flow control from the slave to the SPI master to notify
|
|
* the master when ready.
|
|
*
|
|
* <hr>
|
|
* @anchor ti_drivers_SPI_Usage
|
|
* # Usage
|
|
*
|
|
* To use the SPI driver to send data over the SPI bus, the application
|
|
* calls the following APIs:
|
|
* - SPI_init(): Initialize the SPI driver.
|
|
* - SPI_Params_init(): Initialize a #SPI_Params structure with default
|
|
* values. Then change the parameters from non-default values as
|
|
* needed.
|
|
* - SPI_open(): Open an instance of the SPI driver, passing the
|
|
* initialized parameters, or NULL, and an index to the configuration to
|
|
* open (detailed later).
|
|
* - SPI_transfer(): Transmit/receive data. This function takes a
|
|
* #SPI_Transaction argument that describes the transfer that is requested.
|
|
* - SPI_close(): De-initialize the SPI instance.
|
|
*
|
|
* @anchor ti_drivers_SPI_Synopsis
|
|
* ## Synopsis
|
|
* The following code example opens a SPI instance as a master SPI,
|
|
* and issues a transaction.
|
|
*
|
|
* @code
|
|
* SPI_Handle spi;
|
|
* SPI_Params spiParams;
|
|
* SPI_Transaction spiTransaction;
|
|
* uint8_t transmitBuffer[MSGSIZE];
|
|
* uint8_t receiveBuffer[MSGSIZE];
|
|
* bool transferOK;
|
|
*
|
|
* SPI_init(); // Initialize the SPI driver
|
|
*
|
|
* SPI_Params_init(&spiParams); // Initialize SPI parameters
|
|
* spiParams.dataSize = 8; // 8-bit data size
|
|
*
|
|
* spi = SPI_open(Board_SPI0, &spiParams);
|
|
* if (spi == NULL) {
|
|
* while (1); // SPI_open() failed
|
|
* }
|
|
*
|
|
* // Fill in transmitBuffer
|
|
* spiTransaction.count = MSGSIZE;
|
|
* spiTransaction.txBuf = (void *)transmitBuffer;
|
|
* spiTransaction.rxBuf = (void *)receiveBuffer;
|
|
*
|
|
* transferOK = SPI_transfer(spi, &spiTransaction);
|
|
* if (!transferOK) {
|
|
* // Error in SPI or transfer already in progress.
|
|
* while (1);
|
|
* }
|
|
* @endcode
|
|
*
|
|
* More details on usage are provided in the following subsections.
|
|
*
|
|
* @anchor ti_drivers_SPI_Examples
|
|
* ## Examples #
|
|
* * @ref ti_drivers_SPI_Synopsis "Usage Synopsis"
|
|
* * @ref ti_drivers_SPI_Example_openblocking "Open in blocking mode"
|
|
* * @ref ti_drivers_SPI_Example_opencallback "Open in callback mode"
|
|
* * @ref ti_drivers_SPI_Example_6bitframes "Sending 6 bit frames"
|
|
* * @ref ti_drivers_SPI_Example_12bitframes "Sending 12 bit frames"
|
|
* * @ref ti_drivers_SPI_Example_callbackarg "Callback function using arg"
|
|
*
|
|
* ## Initializing the SPI Driver
|
|
*
|
|
* SPI_init() must be called before any other SPI APIs. This function
|
|
* iterates through the elements of the @p SPI_config[] array, calling
|
|
* the element's device implementation SPI initialization function.
|
|
*
|
|
* ## Opening the SPI Driver
|
|
* After initializing the SPI driver by calling SPI_init(), the application
|
|
* can open a SPI instance by calling SPI_open(). This function
|
|
* takes an index into the @p SPI_config[] array, and a SPI parameters data
|
|
* structure. The SPI instance is specified by the index of the SPI in
|
|
* @p SPI_config[]. Calling SPI_open() a second time with the same index
|
|
* previously passed to SPI_open() will result in an error. You can,
|
|
* though, re-use the index if the instance is closed via SPI_close().
|
|
*
|
|
* If no #SPI_Params structure is passed to SPI_open(), default values are
|
|
* used. If the open call is successful, it returns a non-NULL value.
|
|
*
|
|
* @anchor ti_drivers_SPI_Example_openblocking
|
|
* Example opening a SPI driver instance in blocking mode:
|
|
* @code
|
|
* SPI_Handle spi;
|
|
* SPI_Params spiParams;
|
|
*
|
|
* SPI_Params_init(&spiParams);
|
|
* spiParams.transferMode = SPI_MODE_BLOCKING;
|
|
* spi = SPI_open(Board_SPI0, &spiParams);
|
|
*
|
|
* if (spi == NULL) {
|
|
* // Error opening SPI
|
|
* while(1);
|
|
* }
|
|
* @endcode
|
|
*
|
|
* @anchor ti_drivers_SPI_Example_opencallback
|
|
* Example opening a SPI driver instance in callback mode:
|
|
* @code
|
|
* SPI_Handle spi;
|
|
* SPI_Params spiParams;
|
|
*
|
|
* SPI_Params_init(&spiParams);
|
|
* spiParams.transferMode = SPI_MODE_CALLBACK;
|
|
* spiParams.transferCallbackFxn = UserCallbackFxn;
|
|
*
|
|
* spi = SPI_open(Board_SPI0, &spiParams);
|
|
* if (spi == NULL) {
|
|
* // Error opening SPI
|
|
* while (1);
|
|
* }
|
|
* @endcode
|
|
*
|
|
* ## SPI Parameters
|
|
*
|
|
* The #SPI_Params structure is passed to the SPI_open() call. If NULL
|
|
* is passed for the parameters, SPI_open() uses default parameters.
|
|
* A #SPI_Params structure is initialized with default values by passing
|
|
* it to SPI_Params_init().
|
|
* Some of the SPI parameters are described below. To see brief descriptions
|
|
* of all the parameters, see #SPI_Params.
|
|
*
|
|
* ### SPI Mode
|
|
* The SPI driver operates in both SPI master and SPI slave modes.
|
|
* Logically, the implementation is identical, however the difference
|
|
* between these two modes is driven by hardware. The default mode is
|
|
* #SPI_MASTER, but can be set to slave mode by setting #SPI_Params.mode
|
|
* to #SPI_SLAVE in the parameters passed to SPI_open(). See
|
|
* @ref ti_drivers_SPI_MasterSlaveModes "Master/Slave Modes" for further
|
|
* details.
|
|
*
|
|
* ### SPI Transfer Mode
|
|
* The SPI driver supports two transfer modes of operation: blocking and
|
|
* callback. The transfer mode is determined by the transferMode parameter
|
|
* in the #SPI_Params data structure. The SPI driver
|
|
* defaults to blocking mode, if the application does not set it.
|
|
* Once a SPI driver is opened, the only way to change the operation mode
|
|
* is to close and re-open the SPI instance with the new transfer mode.
|
|
*
|
|
* In blocking mode, a task's code execution is blocked until a SPI
|
|
* transaction has completed or a timeout has occurred. This ensures
|
|
* that only one SPI transfer operates at a given time. Other tasks requesting
|
|
* SPI transfers while a transfer is currently taking place will receive
|
|
* a FALSE return value. If a timeout occurs the transfer is canceled, the
|
|
* task is unblocked & will receive a FALSE return value. The transaction
|
|
* count field will have the amount of frames which were transferred
|
|
* successfully before the timeout. In blocking mode, transfers cannot be
|
|
* performed in software or hardware ISR context.
|
|
*
|
|
* In callback mode, a SPI transaction functions asynchronously, which
|
|
* means that it does not block code execution. After a SPI transaction
|
|
* has been completed, the SPI driver calls a user-provided hook function.
|
|
* Callback mode is supported in the execution context of tasks and
|
|
* hardware interrupt routines.
|
|
*
|
|
* ### SPI Frame Formats and Data Size
|
|
* The SPI driver can configure the device's SPI peripheral to transfer
|
|
* data in several SPI format options: SPI (with various polarity and phase
|
|
* settings), TI, and Micro-wire. The frame format is set with
|
|
* #SPI_Params.frameFormat. Some SPI implementations may not support all frame
|
|
* formats & the SPI driver will fail to opened. Refer to the device specific
|
|
* implementation documentation for details on which frame formats are
|
|
* supported.
|
|
*
|
|
* The smallest single unit of data transmitted onto the SPI bus is called
|
|
* a SPI frame and is of size #SPI_Params.dataSize. A series of SPI frames
|
|
* transmitted/received on a SPI bus is referred to as a SPI transaction.
|
|
*
|
|
* ## SPI Transactions
|
|
*
|
|
* A SPI transaction consists of a series of SPI frames
|
|
* transmitted/received on a SPI bus. A SPI transaction is performed
|
|
* using SPI_transfer(). SPI_transfer() accepts a pointer to a
|
|
* #SPI_Transaction structure that dictates the quantity of data to be
|
|
* sent and received.
|
|
* The #SPI_Transaction.txBuf and #SPI_Transaction.rxBuf are both pointers
|
|
* to data buffers. If txBuf is NULL, the driver sends SPI frames with all
|
|
* data set to the default value specified in the hardware attributes. If
|
|
* rxBuf is NULL, the driver discards all SPI frames received. SPI_transfer()
|
|
* of a SPI transaction is performed atomically.
|
|
*
|
|
* @warning The use of NULL as a sentinel txBuf or rxBuf value to determine
|
|
* whether the SPI transaction includes a tx or rx component implies
|
|
* that it is not possible to perform a transmit or receive transfer
|
|
* directly from/to a buffer with a base address of 0x00000000. To support
|
|
* this rare use-case, the application will have to manually copy the
|
|
* contents of location 0x00000000 to/from a temporary buffer before/after
|
|
* the tx/rx SPI transaction.
|
|
*
|
|
* When the SPI is opened, the dataSize value determines the element types
|
|
* of txBuf and rxBuf. If the dataSize is from 4 to 8 bits, the driver
|
|
* assumes the data buffers are of type uint8_t (unsigned char). If the
|
|
* dataSize is from 8 to 16 bits, the driver assumes the data buffers are
|
|
* of type uint16_t (unsigned short). If the dataSize is greater than
|
|
* 16 bits, the driver assumes the data buffers are uint32_t (unsigned long).
|
|
* Some SPI driver implementations may not support all data sizes; refer
|
|
* to device specific SPI implementation documentation for details on
|
|
* what data sizes are supported.
|
|
*
|
|
* The optional #SPI_Transaction.arg variable can only be used when the
|
|
* SPI driver has been opened in callback mode. This variable is used to
|
|
* pass a user-defined value into the user-defined callback function.
|
|
*
|
|
* SPI_transfer() always performs full-duplex SPI transactions. This means
|
|
* the SPI simultaneously receives data as it transmits data. The application
|
|
* is responsible for formatting the data to be transmitted as well as
|
|
* determining whether the data received is meaningful.
|
|
* Specifics about SPI frame formatting and data sizes are provided in
|
|
* device-specific data sheets and technical reference manuals.
|
|
*
|
|
* The following code snippets perform SPI transactions.
|
|
*
|
|
* @anchor ti_drivers_SPI_Example_6bitframes
|
|
* Example transferring 6-bit SPI frames. The transmit and receive
|
|
* buffers are of type uint8_t.
|
|
* @code
|
|
* SPI_Transaction spiTransaction;
|
|
* uint8_t transmitBuffer[BUFSIZE];
|
|
* uint8_t receiveBuffer[BUFSIZE];
|
|
* bool transferOK;
|
|
*
|
|
* SPI_Params_init(&spiParams);
|
|
* spiParams.dataSize = 6;
|
|
* spi = SPI_open(Board_SPI0, &spiParams);
|
|
* ...
|
|
* spiTransaction.count = someIntegerValue;
|
|
* spiTransaction.txBuf = transmitBuffer;
|
|
* spiTransaction.rxBuf = receiveBuffer;
|
|
*
|
|
* transferOK = SPI_transfer(spi, &spiTransaction);
|
|
* if (!transferOK) {
|
|
* // Error in SPI or transfer already in progress.
|
|
* }
|
|
* @endcode
|
|
*
|
|
* @anchor ti_drivers_SPI_Example_12bitframes
|
|
* Example transferring 12-bit SPI frames. The transmit and receive
|
|
* buffers are of type uint16_t.
|
|
* @code
|
|
* SPI_Transaction spiTransaction;
|
|
* uint16_t transmitBuffer[BUFSIZE];
|
|
* uint16_t receiveBuffer[BUFSIZE];
|
|
* bool transferOK;
|
|
*
|
|
* SPI_Params_init(&spiParams);
|
|
* spiParams.dataSize = 12;
|
|
* spi = SPI_open(Board_SPI0, &spiParams);
|
|
* ...
|
|
* spiTransaction.count = someIntegerValue;
|
|
* spiTransaction.txBuf = transmitBuffer;
|
|
* spiTransaction.rxBuf = receiveBuffer;
|
|
*
|
|
* transferOK = SPI_transfer(spi, &spiTransaction);
|
|
* if (!transferOK) {
|
|
* // Error in SPI or transfer already in progress.
|
|
* }
|
|
* @endcode
|
|
*
|
|
* The following example shows an example of a callback function that
|
|
* utilizes the arg parameter.
|
|
* @anchor ti_drivers_SPI_Example_callbackarg
|
|
* @code
|
|
* // SPI is opened with callback function as seen in other examples
|
|
* // Our goal is to post a semaphore when transfer with sufficient size
|
|
* // completes.
|
|
* ...
|
|
* // Pass pointer to an initialized semaphore to callback via arg
|
|
* spiTransaction.count = someIntegerValue;
|
|
* spiTransaction.txBuf = transmitBuffer;
|
|
* spiTransaction.rxBuf = receiveBuffer;
|
|
* spiTransaction.arg = &mySemaphore;
|
|
*
|
|
* ...
|
|
*
|
|
* // Our callback function is defined here
|
|
* void spiCallbackFxn(SPI_Handle spi, SPI_Transaction *tran)
|
|
* {
|
|
* sem_t *semPtr = (sem_t *)(tran->arg);
|
|
*
|
|
* // Post the semaphore if our transaction was more than LIMIT
|
|
* if (tran->status == SPI_STATUS_SUCCESS &&
|
|
* tran->count > LIMIT) {
|
|
* sem_post(semPtr);
|
|
* }
|
|
* }
|
|
* @endcode
|
|
*
|
|
* ## Canceling a transaction
|
|
* SPI_transferCancel() is used to cancel a SPI transaction when the driver is
|
|
* used in #SPI_MODE_CALLBACK mode.
|
|
*
|
|
* Calling this API while no transfer is in progress has no effect. If a
|
|
* transfer is in progress, it is canceled and the callback functions is
|
|
* called.
|
|
* The #SPI_Status status field in the #SPI_Transaction structure
|
|
* can be examined within the callback to determine if the transaction
|
|
* succeeded.
|
|
*
|
|
* Example:
|
|
* @code
|
|
* SPI_transferCancel(spi);
|
|
* @endcode
|
|
*
|
|
* @anchor ti_drivers_SPI_MasterSlaveModes
|
|
* ## Master/Slave Modes
|
|
* This SPI driver functions in both SPI master and SPI slave modes.
|
|
* Logically, the implementation is identical, however the difference between
|
|
* these two modes is driven by hardware. As a SPI master, the peripheral is
|
|
* in control of the clock signal and therefore will commence communications
|
|
* to the SPI slave immediately. As a SPI slave, the SPI driver prepares
|
|
* the peripheral to transmit and receive data in a way such that the
|
|
* peripheral is ready to transfer data when the SPI master initiates a
|
|
* transaction.
|
|
*
|
|
* ## Asserting on Chip Select
|
|
* The SPI protocol requires that the SPI master asserts a SPI slave's chip
|
|
* select pin prior to starting a SPI transaction. While this protocol is
|
|
* generally followed, various types of SPI peripherals have different
|
|
* timing requirements as to when and for how long the chip select pin must
|
|
* remain asserted for a SPI transaction.
|
|
*
|
|
* Commonly, the SPI master uses a hardware chip select to assert and
|
|
* de-assert the SPI slave for every data frame. In other cases, a SPI slave
|
|
* imposes the requirement of asserting the chip select over several SPI
|
|
* data frames. This is generally accomplished by using a regular,
|
|
* general-purpose output pin. Due to the complexity of such SPI peripheral
|
|
* implementations, this SPI driver has been designed to operate
|
|
* transparently to the SPI chip select. When the hardware chip
|
|
* select is used, the peripheral automatically selects/enables the
|
|
* peripheral. When using a software chip select, the application needs to
|
|
* handle the proper chip select and pin configuration. Chip select support
|
|
* will vary per SPI peripheral, refer to the device specific implementation
|
|
* documentation for details on chip select support.
|
|
*
|
|
* - _Hardware chip select_ No additional action by the application is
|
|
* required.
|
|
* - _Software chip select_ The application needs to handle the chip select
|
|
* assertion and de-assertion for the proper SPI peripheral.
|
|
*
|
|
* <hr>
|
|
* @anchor ti_drivers_SPI_Configuration
|
|
* # Configuration
|
|
*
|
|
* In order to use the SPI APIs, the application is required
|
|
* to provide device-specific SPI configuration in the Board.c file.
|
|
* The SPI driver interface defines a configuration data structure:
|
|
*
|
|
* @code
|
|
* typedef struct {
|
|
* SPI_FxnTable const *fxnTablePtr;
|
|
* void *object;
|
|
* void const *hwAttrs;
|
|
* } SPI_Config;
|
|
* @endcode
|
|
*
|
|
* The application must declare an array of #SPI_Config elements, named
|
|
* @p SPI_config[]. Each element of @p SPI_config[] must be populated with
|
|
* pointers to a device specific SPI driver implementation's function
|
|
* table, driver object, and hardware attributes. The hardware attributes
|
|
* define properties such as the SPI peripheral's base address, and
|
|
* the MOSI and MISO pins. Each element in @p SPI_config[] corresponds to
|
|
* a SPI instance, and none of the elements should have NULL pointers.
|
|
* There is no correlation between the index and the
|
|
* peripheral designation (such as SPI0 or SPI1). For example, it is
|
|
* possible to use SPI_config[0] for SPI1.
|
|
*
|
|
* Because the SPI configuration is very device dependent, you will need to
|
|
* check the doxygen for the device specific SPI implementation. There you
|
|
* will find a description of the SPI hardware attributes. Please also
|
|
* refer to the Board.c file of any of your examples to see the SPI
|
|
* configuration.
|
|
*
|
|
*******************************************************************************
|
|
*/
|
|
|
|
#ifndef ti_drivers_SPI__include
|
|
#define ti_drivers_SPI__include
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
#include <stdbool.h>
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
|
|
/**
|
|
* @defgroup SPI_CONTROL SPI_control command and status codes
|
|
* These SPI macros are reservations for SPI.h
|
|
* @{
|
|
*/
|
|
|
|
/*!
|
|
* Common SPI_control() command code reservation offset.
|
|
* SPI driver implementations should offset command codes with #SPI_CMD_RESERVED
|
|
* growing positively
|
|
*
|
|
* Example implementation specific command codes:
|
|
* @code
|
|
* #define SPIXYZ_CMD_COMMAND0 SPI_CMD_RESERVED + 0
|
|
* #define SPIXYZ_CMD_COMMAND1 SPI_CMD_RESERVED + 1
|
|
* @endcode
|
|
*/
|
|
#define SPI_CMD_RESERVED (32)
|
|
|
|
/*!
|
|
* Common SPI_control status code reservation offset.
|
|
* SPI driver implementations should offset status codes with
|
|
* #SPI_STATUS_RESERVED growing negatively.
|
|
*
|
|
* Example implementation specific status codes:
|
|
* @code
|
|
* #define SPIXYZ_STATUS_ERROR0 SPI_STATUS_RESERVED - 0
|
|
* #define SPIXYZ_STATUS_ERROR1 SPI_STATUS_RESERVED - 1
|
|
* #define SPIXYZ_STATUS_ERROR2 SPI_STATUS_RESERVED - 2
|
|
* @endcode
|
|
*/
|
|
#define SPI_STATUS_RESERVED (-32)
|
|
|
|
/**
|
|
* @defgroup SPI_STATUS Status Codes
|
|
* SPI_STATUS_* macros are general status codes returned by SPI_control()
|
|
* @{
|
|
* @ingroup SPI_CONTROL
|
|
*/
|
|
|
|
/*!
|
|
* @brief Successful status code returned by SPI_control().
|
|
*
|
|
* This value is returned from SPI_control() if the control code was executed
|
|
* successfully.
|
|
*/
|
|
#define SPI_STATUS_SUCCESS (0)
|
|
|
|
/*!
|
|
* @brief Generic error status code returned by SPI_control().
|
|
*
|
|
* This value is returned from SPI_control() if the control code was not
|
|
* executed successfully.
|
|
*/
|
|
#define SPI_STATUS_ERROR (-1)
|
|
|
|
/*!
|
|
* @brief An error status code returned by SPI_control() for undefined
|
|
* command codes.
|
|
*
|
|
* This value is returned from SPI_control() if the control code is not
|
|
* recognized by the driver implementation.
|
|
*/
|
|
#define SPI_STATUS_UNDEFINEDCMD (-2)
|
|
/** @}*/
|
|
|
|
/**
|
|
* @defgroup SPI_CMD Command Codes
|
|
* SPI_CMD_* macros are general command codes for SPI_control(). Not all SPI
|
|
* driver implementations support these command codes.
|
|
* @{
|
|
* @ingroup SPI_CONTROL
|
|
*/
|
|
|
|
/* Add SPI_CMD_<commands> here */
|
|
|
|
/** @}*/
|
|
|
|
/** @}*/
|
|
|
|
/*!
|
|
* @brief Wait forever define used to specify timeouts.
|
|
*/
|
|
#define SPI_WAIT_FOREVER (~(0U))
|
|
|
|
/*!
|
|
* @brief A handle that is returned from a SPI_open() call.
|
|
*/
|
|
typedef struct SPI_Config_ *SPI_Handle;
|
|
|
|
/*!
|
|
* @brief Status codes that are set by the SPI driver.
|
|
*/
|
|
typedef enum {
|
|
SPI_TRANSFER_COMPLETED = 0, /*!< SPI transfer completed */
|
|
SPI_TRANSFER_STARTED, /*!< SPI transfer started and in progress */
|
|
SPI_TRANSFER_CANCELED, /*!< SPI transfer was canceled */
|
|
SPI_TRANSFER_FAILED, /*!< SPI transfer failed */
|
|
SPI_TRANSFER_CSN_DEASSERT, /*!< SPI chip select was de-asserted (only
|
|
applicable in return partial mode) */
|
|
SPI_TRANSFER_PEND_CSN_ASSERT, /*!< SPI transfer is pending until the chip
|
|
select is asserted */
|
|
SPI_TRANSFER_QUEUED /*!< SPI transfer added to transaction queue */
|
|
} SPI_Status;
|
|
|
|
/*!
|
|
* @brief
|
|
* A #SPI_Transaction data structure is used with SPI_transfer(). It indicates
|
|
* how many #SPI_FrameFormat frames are sent and received from the buffers
|
|
* pointed to txBuf and rxBuf.
|
|
* The arg variable is an user-definable argument which gets passed to the
|
|
* #SPI_CallbackFxn when the SPI driver is in #SPI_MODE_CALLBACK.
|
|
*/
|
|
typedef struct {
|
|
/* User input (write-only) fields */
|
|
size_t count; /*!< Number of frames for this transaction */
|
|
void *txBuf; /*!< void * to a buffer with data to be transmitted */
|
|
void *rxBuf; /*!< void * to a buffer to receive data */
|
|
void *arg; /*!< Argument to be passed to the callback function */
|
|
|
|
/* User output (read-only) fields */
|
|
SPI_Status status; /*!< #SPI_Status code set by SPI_transfer */
|
|
|
|
void *nextPtr; /*!< Field used internally by the driver and must
|
|
never be accessed by the application. */
|
|
} SPI_Transaction;
|
|
|
|
/*!
|
|
* @brief The definition of a callback function used by the SPI driver
|
|
* when used in #SPI_MODE_CALLBACK
|
|
*
|
|
* @param SPI_Handle A #SPI_Handle
|
|
* @param SPI_Transaction* Pointer to a #SPI_Transaction
|
|
*/
|
|
typedef void (*SPI_CallbackFxn) (SPI_Handle handle,
|
|
SPI_Transaction *transaction);
|
|
/*!
|
|
* @brief
|
|
* Definitions for various SPI modes of operation.
|
|
*/
|
|
typedef enum {
|
|
SPI_MASTER = 0, /*!< SPI in master mode */
|
|
SPI_SLAVE = 1 /*!< SPI in slave mode */
|
|
} SPI_Mode;
|
|
|
|
/*!
|
|
* @brief
|
|
* Definitions for various SPI data frame formats.
|
|
*/
|
|
typedef enum {
|
|
SPI_POL0_PHA0 = 0, /*!< SPI mode Polarity 0 Phase 0 */
|
|
SPI_POL0_PHA1 = 1, /*!< SPI mode Polarity 0 Phase 1 */
|
|
SPI_POL1_PHA0 = 2, /*!< SPI mode Polarity 1 Phase 0 */
|
|
SPI_POL1_PHA1 = 3, /*!< SPI mode Polarity 1 Phase 1 */
|
|
SPI_TI = 4, /*!< TI mode (not supported on all
|
|
implementations) */
|
|
SPI_MW = 5 /*!< Micro-wire mode (not supported on all
|
|
implementations) */
|
|
} SPI_FrameFormat;
|
|
|
|
/*!
|
|
* @brief
|
|
*
|
|
* SPI transfer mode determines the whether the SPI controller operates
|
|
* synchronously or asynchronously. In #SPI_MODE_BLOCKING mode SPI_transfer()
|
|
* blocks code execution until the SPI transaction has completed. In
|
|
* #SPI_MODE_CALLBACK SPI_transfer() does not block code execution and instead
|
|
* calls a #SPI_CallbackFxn callback function when the transaction has
|
|
* completed (successfully or not).
|
|
*/
|
|
typedef enum {
|
|
/*!
|
|
* SPI_transfer() blocks execution. This mode can only be used when called
|
|
* within a Task context
|
|
*/
|
|
SPI_MODE_BLOCKING,
|
|
/*!
|
|
* SPI_transfer() does not block code execution and will call a
|
|
* #SPI_CallbackFxn. This mode can be used in a Task, software or hardware
|
|
* interrupt context.
|
|
*/
|
|
SPI_MODE_CALLBACK
|
|
} SPI_TransferMode;
|
|
|
|
/*!
|
|
* @brief SPI Parameters
|
|
*
|
|
* SPI Parameters are used to with the SPI_open() call. Default values for
|
|
* these parameters are set using SPI_Params_init().
|
|
*
|
|
* @sa SPI_Params_init()
|
|
*/
|
|
typedef struct {
|
|
SPI_TransferMode transferMode; /*!< Blocking or Callback mode */
|
|
uint32_t transferTimeout; /*!< Transfer timeout in system
|
|
ticks */
|
|
SPI_CallbackFxn transferCallbackFxn;/*!< Callback function pointer */
|
|
SPI_Mode mode; /*!< Master or Slave mode */
|
|
/*! @brief SPI bit rate in Hz
|
|
*
|
|
* Maximum bit rates supported by hardware:
|
|
* Device Family | Slave Max (MHz) | Master Max (MHz) |
|
|
* ------------- | ------------------ | ---------------- |
|
|
* MSP432P4 | 16 MHz | 24 MHz |
|
|
* MSP432E4 | 10 MHz | 60 MHz |
|
|
* CC13XX/CC26XX | 4 MHz | 12 MHz |
|
|
* CC32XX | 20 MHz | 20 MHz |
|
|
*
|
|
* Please note that depending on the specific use case, the driver may not
|
|
* support the hardware's maximum bit rate.
|
|
*/
|
|
uint32_t bitRate;
|
|
uint32_t dataSize; /*!< SPI data frame size in bits */
|
|
SPI_FrameFormat frameFormat; /*!< SPI frame format */
|
|
void *custom; /*!< Custom argument used by driver
|
|
implementation */
|
|
} SPI_Params;
|
|
|
|
/*!
|
|
* @brief A function pointer to a driver specific implementation of
|
|
* SPI_close().
|
|
*/
|
|
typedef void (*SPI_CloseFxn) (SPI_Handle handle);
|
|
|
|
/*!
|
|
* @brief A function pointer to a driver specific implementation of
|
|
* SPI_control().
|
|
*/
|
|
typedef int_fast16_t (*SPI_ControlFxn) (SPI_Handle handle, uint_fast16_t cmd,
|
|
void *arg);
|
|
|
|
/*!
|
|
* @brief A function pointer to a driver specific implementation of
|
|
* SPI_init().
|
|
*/
|
|
typedef void (*SPI_InitFxn) (SPI_Handle handle);
|
|
|
|
/*!
|
|
* @brief A function pointer to a driver specific implementation of
|
|
* SPI_open().
|
|
*/
|
|
typedef SPI_Handle (*SPI_OpenFxn) (SPI_Handle handle, SPI_Params *params);
|
|
|
|
/*!
|
|
* @brief A function pointer to a driver specific implementation of
|
|
* SPI_transfer().
|
|
*/
|
|
typedef bool (*SPI_TransferFxn) (SPI_Handle handle,
|
|
SPI_Transaction *transaction);
|
|
|
|
/*!
|
|
* @brief A function pointer to a driver specific implementation of
|
|
* SPI_transferCancel().
|
|
*/
|
|
typedef void (*SPI_TransferCancelFxn) (SPI_Handle handle);
|
|
|
|
/*!
|
|
* @brief The definition of a SPI function table that contains the
|
|
* required set of functions to control a specific SPI driver
|
|
* implementation.
|
|
*/
|
|
typedef struct {
|
|
/*! Function to close the specified peripheral */
|
|
SPI_CloseFxn closeFxn;
|
|
|
|
/*! Function to implementation specific control function */
|
|
SPI_ControlFxn controlFxn;
|
|
|
|
/*! Function to initialize the given data object */
|
|
SPI_InitFxn initFxn;
|
|
|
|
/*! Function to open the specified peripheral */
|
|
SPI_OpenFxn openFxn;
|
|
|
|
/*! Function to initiate a SPI data transfer */
|
|
SPI_TransferFxn transferFxn;
|
|
|
|
/*! Function to cancel SPI data transfer */
|
|
SPI_TransferCancelFxn transferCancelFxn;
|
|
} SPI_FxnTable;
|
|
|
|
/*!
|
|
* @brief SPI Global configuration
|
|
*
|
|
* The #SPI_Config structure contains a set of pointers used to characterize
|
|
* the SPI driver implementation.
|
|
*
|
|
* This structure needs to be defined before calling SPI_init() and it must
|
|
* not be changed thereafter.
|
|
*
|
|
* @sa SPI_init()
|
|
*/
|
|
typedef struct SPI_Config_{
|
|
/*! Pointer to a table of driver-specific implementations of SPI APIs */
|
|
SPI_FxnTable const *fxnTablePtr;
|
|
|
|
/*! Pointer to a driver specific data object */
|
|
void *object;
|
|
|
|
/*! Pointer to a driver specific hardware attributes structure */
|
|
void const *hwAttrs;
|
|
} SPI_Config;
|
|
|
|
/*!
|
|
* @brief Function to close a SPI peripheral specified by the SPI handle
|
|
*
|
|
* @pre SPI_open() has to be called first.
|
|
*
|
|
* @param handle A #SPI_Handle returned from SPI_open()
|
|
*
|
|
* @sa SPI_open()
|
|
*/
|
|
extern void SPI_close(SPI_Handle handle);
|
|
|
|
/*!
|
|
* @brief Function performs implementation specific features on a given
|
|
* #SPI_Handle.
|
|
*
|
|
* Commands for SPI_control can originate from SPI.h or from implementation
|
|
* specific SPI*.h (SPICC26XXDMA.h, SPIMSP432DMA.h, etc.. ) files.
|
|
* While commands from SPI.h are API portable across driver implementations,
|
|
* not all implementations may support all these commands.
|
|
* Conversely, commands from driver implementation specific SPI*.h files add
|
|
* unique driver capabilities but are not API portable across all SPI driver
|
|
* implementations.
|
|
*
|
|
* Commands supported by SPI.h follow a SPI_CMD_\<cmd\> naming
|
|
* convention.<br>
|
|
* Commands supported by SPI*.h follow a SPI*_CMD_\<cmd\> naming
|
|
* convention.<br>
|
|
* Each control command defines @b arg differently. The types of @b arg are
|
|
* documented with each command.
|
|
*
|
|
* See @ref SPI_CMD "SPI_control command codes" for command codes.
|
|
*
|
|
* See @ref SPI_STATUS "SPI_control return status codes" for status codes.
|
|
*
|
|
* @pre SPI_open() has to be called first.
|
|
*
|
|
* @param handle A #SPI_Handle returned from SPI_open()
|
|
*
|
|
* @param cmd SPI.h or SPI*.h commands.
|
|
*
|
|
* @param controlArg An optional R/W (read/write) command argument
|
|
* accompanied with cmd
|
|
*
|
|
* @return Implementation specific return codes. Negative values indicate
|
|
* unsuccessful operations.
|
|
*
|
|
* @sa SPI_open()
|
|
*/
|
|
extern int_fast16_t SPI_control(SPI_Handle handle, uint_fast16_t cmd,
|
|
void *controlArg);
|
|
|
|
/*!
|
|
* @brief This function initializes the SPI module.
|
|
*
|
|
* @pre The SPI_config[] array must exist and be persistent before this
|
|
* function can be called. This function must also be called before
|
|
* any other SPI driver APIs. This function call does not modify any
|
|
* peripheral registers.
|
|
*/
|
|
extern void SPI_init(void);
|
|
|
|
/*!
|
|
* @brief This function opens a given SPI peripheral.
|
|
*
|
|
* @pre SPI controller has been initialized using SPI_init()
|
|
*
|
|
* @param index Index of config to use in the *SPI_config* array
|
|
*
|
|
* @param params Pointer to an parameter block, if NULL it will use
|
|
* default values. All the fields in this structure are
|
|
* RO (read-only).
|
|
*
|
|
* @return A #SPI_Handle on success or a NULL on an error or if it has been
|
|
* opened already.
|
|
*
|
|
* @sa SPI_init()
|
|
* @sa SPI_close()
|
|
*/
|
|
extern SPI_Handle SPI_open(uint_least8_t index, SPI_Params *params);
|
|
|
|
/*!
|
|
* @brief Function to initialize the #SPI_Params struct to its defaults
|
|
*
|
|
* @param params An pointer to #SPI_Params structure for
|
|
* initialization
|
|
*
|
|
* Defaults values are:
|
|
* * SPI_Params.transferMode = #SPI_MODE_BLOCKING
|
|
* * SPI_Params.transferTimeout = #SPI_WAIT_FOREVER
|
|
* * SPI_Params.transferCallbackFxn = NULL
|
|
* * SPI_Params.mode = #SPI_MASTER
|
|
* * SPI_Params.bitRate = 1000000 (Hz)
|
|
* * SPI_Params.dataSize = 8 (bits)
|
|
* * SPI_Params.frameFormat = #SPI_POL0_PHA0
|
|
*/
|
|
extern void SPI_Params_init(SPI_Params *params);
|
|
|
|
/*!
|
|
* @brief Function to perform SPI transactions
|
|
*
|
|
* If the SPI is in #SPI_MASTER mode, it will immediately start the
|
|
* transaction. If the SPI is in #SPI_SLAVE mode, it prepares the driver for
|
|
* a transaction with a SPI master device. The device will then wait until
|
|
* the master begins the transfer.
|
|
*
|
|
* In #SPI_MODE_BLOCKING, #SPI_transfer() will block task execution until the
|
|
* transaction has completed or a timeout has occurred.
|
|
*
|
|
* In #SPI_MODE_CALLBACK, %SPI_transfer() does not block task execution, but
|
|
* calls a #SPI_CallbackFxn once the transfer has finished. This makes
|
|
* %SPI_tranfer() safe to be used within a Task, software or hardware
|
|
* interrupt context. If queued transactions are supported SPI_Transfer may
|
|
* be called multiple times to queue multiple transactions. If the driver does
|
|
* not support this functionality additional calls will return false. Refer to
|
|
* device specific SPI driver documentation for support information.
|
|
*
|
|
* From calling #SPI_transfer() until transfer completion, the #SPI_Transaction
|
|
* structure must stay persistent and must not be altered by application code.
|
|
* It is also forbidden to modify the content of the #SPI_Transaction.txBuf
|
|
* during a transaction, even though the physical transfer might not have
|
|
* started yet. Doing this can result in data corruption. This is especially
|
|
* important for slave operations where SPI_transfer() might be called a long
|
|
* time before the actual data transfer begins.
|
|
*
|
|
* @param handle A #SPI_Handle
|
|
*
|
|
* @param transaction A pointer to a #SPI_Transaction. All of the fields within
|
|
* transaction except #SPI_Transaction.count and
|
|
* #SPI_Transaction.status are WO (write-only) unless
|
|
* otherwise noted in the driver implementations. If a
|
|
* transaction timeout has occurred, #SPI_Transaction.count
|
|
* will contain the number of frames that were transferred.
|
|
* Neither is it allowed to modify the transaction object nor
|
|
* the content of #SPI_Transaction.txBuf until the transfer
|
|
* has completed.
|
|
*
|
|
* @return @p true if started successfully; else @p false
|
|
*
|
|
* @sa #SPI_open
|
|
* @sa #SPI_transferCancel
|
|
*/
|
|
extern bool SPI_transfer(SPI_Handle handle, SPI_Transaction *transaction);
|
|
|
|
/*!
|
|
* @brief Function to cancel SPI transactions
|
|
*
|
|
* In #SPI_MODE_BLOCKING, SPI_transferCancel has no effect.
|
|
*
|
|
* In #SPI_MODE_CALLBACK, SPI_transferCancel() will stop an SPI transfer if
|
|
* if one is in progress.
|
|
* If a transaction was in progress, its callback function will be called
|
|
* in context from which this API is called from. The #SPI_CallbackFxn
|
|
* function can determine if the transaction was successful or not by reading
|
|
* the #SPI_Status status value in the #SPI_Transaction structure.
|
|
*
|
|
* @pre SPI_init(), SPI_open(), SPI_transfer() are called
|
|
*
|
|
* @param handle A #SPI_Handle
|
|
*
|
|
* @sa #SPI_open
|
|
* @sa #SPI_transfer
|
|
*/
|
|
extern void SPI_transferCancel(SPI_Handle handle);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif /* ti_drivers_SPI__include */
|