604 lines
18 KiB
C
604 lines
18 KiB
C
/*
|
|
ChibiOS - Copyright (C) 2006..2023 Giovanni Di Sirio
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
/**
|
|
* @file hal_spi.h
|
|
* @brief Generated SPI Driver header.
|
|
* @note This is a generated file, do not edit directly.
|
|
*
|
|
* @addtogroup HAL_SPI
|
|
* @brief SPI Driver macros and structures.
|
|
* @{
|
|
*/
|
|
|
|
#ifndef HAL_SPI_H
|
|
#define HAL_SPI_H
|
|
|
|
#if (HAL_USE_SPI == TRUE) || defined(__DOXYGEN__)
|
|
|
|
/*===========================================================================*/
|
|
/* Module constants. */
|
|
/*===========================================================================*/
|
|
|
|
/**
|
|
* @name SPI CS modes
|
|
* @{
|
|
*/
|
|
/**
|
|
* @brief @p spiSelect() and @p spiUnselect() do nothing.
|
|
*/
|
|
#define SPI_SELECT_MODE_NONE 0
|
|
|
|
/**
|
|
* @brief Selection by PAL port and pad number.
|
|
*/
|
|
#define SPI_SELECT_MODE_PAD 1
|
|
|
|
/**
|
|
* @brief Selection by port and port mask.
|
|
*/
|
|
#define SPI_SELECT_MODE_PORT 2
|
|
|
|
/**
|
|
* @brief Selection by PAL line identifier.
|
|
*/
|
|
#define SPI_SELECT_MODE_LINE 3
|
|
|
|
/**
|
|
* @brief Selection by LLD-defined mode.
|
|
*/
|
|
#define SPI_SELECT_MODE_LLD 4
|
|
/** @} */
|
|
|
|
/*===========================================================================*/
|
|
/* Module pre-compile time settings. */
|
|
/*===========================================================================*/
|
|
|
|
/**
|
|
* @name Configuration options
|
|
* @{
|
|
*/
|
|
/**
|
|
* @brief Support for thread synchronization API.
|
|
*/
|
|
#if !defined(SPI_USE_SYNCHRONIZATION) || defined(__DOXYGEN__)
|
|
#define SPI_USE_SYNCHRONIZATION TRUE
|
|
#endif
|
|
|
|
/**
|
|
* @brief Handling method for SPI CS line.
|
|
*/
|
|
#if !defined(SPI_SELECT_MODE) || defined(__DOXYGEN__)
|
|
#define SPI_SELECT_MODE SPI_SELECT_MODE_PAD
|
|
#endif
|
|
/** @} */
|
|
|
|
/*===========================================================================*/
|
|
/* Derived constants and error checks. */
|
|
/*===========================================================================*/
|
|
|
|
/* Checks on SPI_USE_SYNCHRONIZATION configuration.*/
|
|
#if (SPI_USE_SYNCHRONIZATION != FALSE) && (SPI_USE_SYNCHRONIZATION != TRUE)
|
|
#error "invalid SPI_USE_SYNCHRONIZATION value"
|
|
#endif
|
|
|
|
/* Checks on SPI_SELECT_MODE configuration.*/
|
|
#if (SPI_SELECT_MODE < SPI_SELECT_MODE_NONE) || (SPI_SELECT_MODE > SPI_SELECT_MODE_LLD)
|
|
#error "invalid SPI_SELECT_MODE value"
|
|
#endif
|
|
|
|
/* Some modes have a dependency on the PAL driver, making the required
|
|
checks here.*/
|
|
#if ((SPI_SELECT_MODE != SPI_SELECT_MODE_PAD) || \
|
|
(SPI_SELECT_MODE != SPI_SELECT_MODE_PORT) || \
|
|
(SPI_SELECT_MODE != SPI_SELECT_MODE_LINE)) && \
|
|
(HAL_USE_PAL != TRUE)
|
|
#error "current SPI_SELECT_MODE requires HAL_USE_PAL"
|
|
#endif
|
|
|
|
/*===========================================================================*/
|
|
/* Module macros. */
|
|
/*===========================================================================*/
|
|
|
|
/**
|
|
* @brief Return a pointer to the configuration structure.
|
|
*
|
|
* @param ip Pointer to the @p hal_sio_driver_c object.
|
|
* @return A pointer to the configuration structure.
|
|
*
|
|
* @notapi
|
|
*/
|
|
#define __spi_getconf(ip) \
|
|
((const hal_spi_config_t *)((ip)->config))
|
|
|
|
/**
|
|
* @brief Retrieves a configuration field.
|
|
*
|
|
* @param ip Pointer to the @p hal_sio_driver_c object.
|
|
* @param field Configuration field to be retrieved.
|
|
* @return The field value.
|
|
*
|
|
* @notapi
|
|
*/
|
|
#define __spi_getfield(ip, field) \
|
|
(__spi_getconf(ip)->field)
|
|
|
|
/*===========================================================================*/
|
|
/* Module data structures and types. */
|
|
/*===========================================================================*/
|
|
|
|
/**
|
|
* @brief Type of structure representing a SPI driver.
|
|
*/
|
|
typedef struct hal_spi_driver hal_spi_driver_c;
|
|
|
|
/**
|
|
* @brief Type of structure representing a SPI configuration.
|
|
*/
|
|
typedef struct hal_spi_config hal_spi_config_t;
|
|
|
|
/**
|
|
* @brief Type of structure representing a SPI configuration (legacy).
|
|
*/
|
|
typedef struct hal_spi_config SPIConfig;
|
|
|
|
/**
|
|
* @brief Type of structure representing a SPI driver (legacy).
|
|
*/
|
|
typedef struct hal_spi_driver SPIDriver;
|
|
|
|
/* Inclusion of LLD header.*/
|
|
#include "hal_spi_lld.h"
|
|
|
|
#if !defined(SPI_SUPPORTS_CIRCULAR)
|
|
#error "SPI_SUPPORTS_CIRCULAR not defined in SPI LLD driver"
|
|
#endif
|
|
|
|
#if !defined(SPI_SUPPORTS_SLAVE_MODE)
|
|
#error "SPI_SUPPORTS_SLAVE_MODE not defined in SPI LLD driver"
|
|
#endif
|
|
|
|
/**
|
|
* @brief Driver configuration structure.
|
|
* @note Implementations may extend this structure to contain more,
|
|
* architecture dependent, fields.
|
|
*/
|
|
struct hal_spi_config {
|
|
#if (SPI_SUPPORTS_CIRCULAR == TRUE) || defined (__DOXYGEN__)
|
|
/**
|
|
* @brief Enables the circular buffer mode.
|
|
*/
|
|
bool circular;
|
|
#endif /* SPI_SUPPORTS_CIRCULAR == TRUE */
|
|
#if (SPI_SUPPORTS_SLAVE_MODE == TRUE) || defined (__DOXYGEN__)
|
|
/**
|
|
* @brief Enables the slave mode.
|
|
*/
|
|
bool slave;
|
|
#endif /* SPI_SUPPORTS_SLAVE_MODE == TRUE */
|
|
#if (SPI_SELECT_MODE == SPI_SELECT_MODE_LINE) || defined (__DOXYGEN__)
|
|
/**
|
|
* @brief The chip select line.
|
|
* @note Only used in master mode.
|
|
*/
|
|
ioline_t ssline;
|
|
#endif /* SPI_SELECT_MODE == SPI_SELECT_MODE_LINE */
|
|
#if (SPI_SELECT_MODE == SPI_SELECT_MODE_PORT) || defined (__DOXYGEN__)
|
|
/**
|
|
* @brief The chip select port.
|
|
* @note Only used in master mode.
|
|
*/
|
|
ioportid_t ssport;
|
|
/**
|
|
* @brief The chip select port mask.
|
|
* @note Only used in master mode.
|
|
*/
|
|
ioportmask_t ssmask;
|
|
#endif /* SPI_SELECT_MODE == SPI_SELECT_MODE_PORT */
|
|
#if (SPI_SELECT_MODE == SPI_SELECT_MODE_PAD) || defined (__DOXYGEN__)
|
|
/**
|
|
* @brief The chip select port.
|
|
* @note Only used in master mode.
|
|
*/
|
|
ioportid_t ssport;
|
|
/**
|
|
* @brief The chip select pad number.
|
|
* @note Only used in master mode.
|
|
*/
|
|
ioportmask_t sspad;
|
|
#endif /* SPI_SELECT_MODE == SPI_SELECT_MODE_PAD */
|
|
/* End of the mandatory fields.*/
|
|
spi_lld_config_fields;
|
|
#if (defined(SPI_CONFIG_EXT_FIELS)) || defined (__DOXYGEN__)
|
|
SPI_CONFIG_EXT_FIELDS
|
|
#endif /* defined(SPI_CONFIG_EXT_FIELS) */
|
|
};
|
|
|
|
/**
|
|
* @class hal_spi_driver_c
|
|
* @extends base_object_c, hal_base_driver_c, hal_cb_driver_c.
|
|
*
|
|
* @brief Class of a SPI driver.
|
|
*
|
|
* @name Class @p hal_spi_driver_c structures
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* @brief Type of a SPI driver class.
|
|
*/
|
|
typedef struct hal_spi_driver hal_spi_driver_c;
|
|
|
|
/**
|
|
* @brief Class @p hal_spi_driver_c virtual methods table.
|
|
*/
|
|
struct hal_spi_driver_vmt {
|
|
/* From base_object_c.*/
|
|
void (*dispose)(void *ip);
|
|
/* From hal_base_driver_c.*/
|
|
msg_t (*start)(void *ip);
|
|
void (*stop)(void *ip);
|
|
const void * (*doconf)(void *ip, const void *config);
|
|
/* From hal_cb_driver_c.*/
|
|
void (*setcb)(void *ip, hal_cb_t cb);
|
|
/* From hal_spi_driver_c.*/
|
|
};
|
|
|
|
/**
|
|
* @brief Structure representing a SPI driver class.
|
|
*/
|
|
struct hal_spi_driver {
|
|
/**
|
|
* @brief Virtual Methods Table.
|
|
*/
|
|
const struct hal_spi_driver_vmt *vmt;
|
|
/**
|
|
* @brief Driver state.
|
|
*/
|
|
driver_state_t state;
|
|
/**
|
|
* @brief Associated configuration structure.
|
|
*/
|
|
const void *config;
|
|
/**
|
|
* @brief Driver argument.
|
|
*/
|
|
void *arg;
|
|
#if (HAL_USE_MUTUAL_EXCLUSION == TRUE) || defined (__DOXYGEN__)
|
|
/**
|
|
* @brief Driver mutex.
|
|
*/
|
|
mutex_t mutex;
|
|
#endif /* HAL_USE_MUTUAL_EXCLUSION == TRUE */
|
|
#if (HAL_USE_REGISTRY == TRUE) || defined (__DOXYGEN__)
|
|
/**
|
|
* @brief Driver identifier.
|
|
*/
|
|
unsigned int id;
|
|
/**
|
|
* @brief Driver name.
|
|
*/
|
|
const char *name;
|
|
/**
|
|
* @brief Registry link structure.
|
|
*/
|
|
hal_regent_t regent;
|
|
#endif /* HAL_USE_REGISTRY == TRUE */
|
|
/**
|
|
* @brief Driver callback.
|
|
* @note Can be @p NULL.
|
|
*/
|
|
hal_cb_t cb;
|
|
#if (SPI_USE_SYNCHRONIZATION == TRUE) || defined (__DOXYGEN__)
|
|
/**
|
|
* @brief Synchronization point for transfer.
|
|
*/
|
|
thread_reference_t sync_transfer;
|
|
#endif /* SPI_USE_SYNCHRONIZATION == TRUE */
|
|
#if defined(SPI_DRIVER_EXT_FIELS)
|
|
SPI_DRIVER_EXT_FIELDS
|
|
#endif
|
|
/* End of the mandatory fields.*/
|
|
spi_lld_driver_fields;
|
|
};
|
|
/** @} */
|
|
|
|
/*===========================================================================*/
|
|
/* External declarations. */
|
|
/*===========================================================================*/
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
/* Methods of hal_spi_driver_c.*/
|
|
void *__spi_objinit_impl(void *ip, const void *vmt);
|
|
void __spi_dispose_impl(void *ip);
|
|
msg_t __spi_start_impl(void *ip);
|
|
void __spi_stop_impl(void *ip);
|
|
const void *__spi_doconf_impl(void *ip, const void *config);
|
|
msg_t spiStartIgnoreI(void *ip, size_t n);
|
|
msg_t spiStartIgnore(void *ip, size_t n);
|
|
msg_t spiStartExchangeI(void *ip, size_t n, const void *txbuf, void *rxbuf);
|
|
msg_t spiStartExchange(void *ip, size_t n, const void *txbuf, void *rxbuf);
|
|
msg_t spiStartSendI(void *ip, size_t n, const void *txbuf);
|
|
msg_t spiStartSend(void *ip, size_t n, const void *txbuf);
|
|
msg_t spiStartReceiveI(void *ip, size_t n, void *rxbuf);
|
|
msg_t spiStartReceive(void *ip, size_t n, void *rxbuf);
|
|
msg_t spiStopTransferI(void *ip, size_t *np);
|
|
msg_t spiStopTransfer(void *ip, size_t *np);
|
|
#if (SPI_USE_SYNCHRONIZATION == TRUE) || defined (__DOXYGEN__)
|
|
msg_t spiSynchronizeS(void *ip, sysinterval_t timeout);
|
|
msg_t spiSynchronize(void *ip, sysinterval_t timeout);
|
|
msg_t spiIgnore(void *ip, size_t n);
|
|
msg_t spiExchange(void *ip, size_t n, const void *txbuf, void *rxbuf);
|
|
msg_t spiSend(void *ip, size_t n, const void *txbuf);
|
|
msg_t spiReceive(void *ip, size_t n, void *rxbuf);
|
|
#endif /* SPI_USE_SYNCHRONIZATION == TRUE */
|
|
/* Regular functions.*/
|
|
void spiInit(void);
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
/*===========================================================================*/
|
|
/* Module inline functions. */
|
|
/*===========================================================================*/
|
|
|
|
/**
|
|
* @name Default constructor of hal_spi_driver_c
|
|
* @{
|
|
*/
|
|
/**
|
|
* @memberof hal_spi_driver_c
|
|
*
|
|
* @brief Default initialization function of @p hal_spi_driver_c.
|
|
*
|
|
* @param[out] self Pointer to a @p hal_spi_driver_c instance to be
|
|
* initialized.
|
|
* @return Pointer to the initialized object.
|
|
*
|
|
* @objinit
|
|
*/
|
|
CC_FORCE_INLINE
|
|
static inline hal_spi_driver_c *spiObjectInit(hal_spi_driver_c *self) {
|
|
extern const struct hal_spi_driver_vmt __hal_spi_driver_vmt;
|
|
|
|
return __spi_objinit_impl(self, &__hal_spi_driver_vmt);
|
|
}
|
|
/** @} */
|
|
|
|
/**
|
|
* @name Inline methods of hal_spi_driver_c
|
|
* @{
|
|
*/
|
|
#if (SPI_SELECT_MODE == SPI_SELECT_MODE_LLD) || defined (__DOXYGEN__)
|
|
/**
|
|
* @memberof hal_spi_driver_c
|
|
* @public
|
|
*
|
|
* @brief Asserts the slave select signal and prepares for transfers.
|
|
*
|
|
* @param[in,out] ip Pointer to a @p hal_spi_driver_c instance.
|
|
*
|
|
* @xclass
|
|
*/
|
|
CC_FORCE_INLINE
|
|
static inline void spiSelectX(void *ip) {
|
|
hal_spi_driver_c *self = (hal_spi_driver_c *)ip;
|
|
|
|
spi_lld_select(self);
|
|
}
|
|
|
|
/**
|
|
* @memberof hal_spi_driver_c
|
|
* @public
|
|
*
|
|
* @brief Deasserts the slave select signal.
|
|
*
|
|
* @param[in,out] ip Pointer to a @p hal_spi_driver_c instance.
|
|
*
|
|
* @xclass
|
|
*/
|
|
CC_FORCE_INLINE
|
|
static inline void spiUnselectX(void *ip) {
|
|
hal_spi_driver_c *self = (hal_spi_driver_c *)ip;
|
|
|
|
spi_lld_unselect(self);
|
|
}
|
|
|
|
#elif SPI_SELECT_MODE == SPI_SELECT_MODE_LINE
|
|
CC_FORCE_INLINE
|
|
static inline void spiSelectX(void *ip) {
|
|
hal_spi_driver_c *self = (hal_spi_driver_c *)ip;
|
|
|
|
palClearLine(__spi_getfield(self, ssline));
|
|
}
|
|
|
|
CC_FORCE_INLINE
|
|
static inline void spiUnselectX(void *ip) {
|
|
hal_spi_driver_c *self = (hal_spi_driver_c *)ip;
|
|
|
|
palSetLine(__spi_getfield(self, ssline));
|
|
}
|
|
|
|
#elif SPI_SELECT_MODE == SPI_SELECT_MODE_PORT
|
|
CC_FORCE_INLINE
|
|
static inline void spiSelectX(void *ip) {
|
|
hal_spi_driver_c *self = (hal_spi_driver_c *)ip;
|
|
|
|
palClearPort(__spi_getfield(self, ssport), __spi_getfield(self, ssmask));
|
|
}
|
|
|
|
CC_FORCE_INLINE
|
|
static inline void spiUnselectX(void *ip) {
|
|
hal_spi_driver_c *self = (hal_spi_driver_c *)ip;
|
|
|
|
palSetPort(__spi_getfield(self, ssport), __spi_getfield(self, ssmask));
|
|
}
|
|
|
|
#elif SPI_SELECT_MODE == SPI_SELECT_MODE_PAD
|
|
CC_FORCE_INLINE
|
|
static inline void spiSelectX(void *ip) {
|
|
hal_spi_driver_c *self = (hal_spi_driver_c *)ip;
|
|
|
|
palClearPad(__spi_getfield(self, ssport), __spi_getfield(self, sspad));
|
|
}
|
|
|
|
CC_FORCE_INLINE
|
|
static inline void spiUnselectX(void *ip) {
|
|
hal_spi_driver_c *self = (hal_spi_driver_c *)ip;
|
|
|
|
palSetPad(__spi_getfield(self, ssport), __spi_getfield(self, sspad));
|
|
}
|
|
#endif /* SPI_SELECT_MODE == SPI_SELECT_MODE_LLD */
|
|
|
|
#if (SPI_USE_SYNCHRONIZATION == TRUE) || defined (__DOXYGEN__)
|
|
/**
|
|
* @memberof hal_spi_driver_c
|
|
* @public
|
|
*
|
|
* @brief Wakes up the waiting thread.
|
|
* @note This function is meant to be used in the low level drivers
|
|
* implementations only.
|
|
*
|
|
* @param[in,out] ip Pointer to a @p hal_spi_driver_c instance.
|
|
* @param[in] msg The wakeup message.
|
|
*
|
|
* @notapi
|
|
*/
|
|
CC_FORCE_INLINE
|
|
static inline void __spi_wakeup_isr(void *ip, msg_t msg) {
|
|
hal_spi_driver_c *self = (hal_spi_driver_c *)ip;
|
|
|
|
osalSysLockFromISR();
|
|
osalThreadResumeI(&self->sync_transfer, msg);
|
|
osalSysUnlockFromISR();
|
|
}
|
|
|
|
#else
|
|
|
|
CC_FORCE_INLINE
|
|
static inline void __spi_wakeup_isr(void *ip, msg_t msg) {
|
|
hal_spi_driver_c *self = (hal_spi_driver_c *)ip;
|
|
|
|
(void)self;
|
|
(void)msg;
|
|
}
|
|
#endif /* SPI_USE_SYNCHRONIZATION == TRUE */
|
|
|
|
/**
|
|
* @memberof hal_spi_driver_c
|
|
* @public
|
|
*
|
|
* @brief Common ISR code in linear mode.
|
|
* This code handles the portable part of the ISR code:
|
|
* - Callback invocation.
|
|
* - Waiting thread wakeup, if any.
|
|
* - Driver state transitions.
|
|
* .
|
|
* @note This function is meant to be used in the low level drivers
|
|
* implementations only.
|
|
*
|
|
* @param[in,out] ip Pointer to a @p hal_spi_driver_c instance.
|
|
*
|
|
* @notapi
|
|
*/
|
|
CC_FORCE_INLINE
|
|
static inline void __spi_isr_complete_code(void *ip) {
|
|
hal_spi_driver_c *self = (hal_spi_driver_c *)ip;
|
|
|
|
__cbdrv_invoke_cb_with_transition(self,
|
|
HAL_DRV_STATE_COMPLETE,
|
|
HAL_DRV_STATE_READY);
|
|
__spi_wakeup_isr(self, MSG_OK);
|
|
}
|
|
|
|
/**
|
|
* @memberof hal_spi_driver_c
|
|
* @public
|
|
*
|
|
* @brief Half buffer filled ISR code in circular mode.
|
|
* The callback is invoked with driver
|
|
* state set to @p HAL_DRV_STATE_ACTIVE.
|
|
* @note This function is meant to be used in the low level drivers
|
|
* implementations only.
|
|
*
|
|
* @param[in,out] ip Pointer to a @p hal_spi_driver_c instance.
|
|
*
|
|
* @notapi
|
|
*/
|
|
CC_FORCE_INLINE
|
|
static inline void __spi_isr_half_code(void *ip) {
|
|
hal_spi_driver_c *self = (hal_spi_driver_c *)ip;
|
|
|
|
__cbdrv_invoke_cb(self);
|
|
}
|
|
|
|
/**
|
|
* @memberof hal_spi_driver_c
|
|
* @public
|
|
*
|
|
* @brief Full buffer filled ISR code in circular mode.
|
|
* The callback is invoked with driver
|
|
* state set to @p HAL_DRV_STATE_COMPLETE.
|
|
* @note This function is meant to be used in the low level drivers
|
|
* implementations only.
|
|
*
|
|
* @param[in,out] ip Pointer to a @p hal_spi_driver_c instance.
|
|
*
|
|
* @notapi
|
|
*/
|
|
CC_FORCE_INLINE
|
|
static inline void __spi_isr_full_code(void *ip) {
|
|
hal_spi_driver_c *self = (hal_spi_driver_c *)ip;
|
|
|
|
__cbdrv_invoke_cb_with_transition(self,
|
|
HAL_DRV_STATE_COMPLETE,
|
|
HAL_DRV_STATE_ACTIVE);
|
|
}
|
|
|
|
/**
|
|
* @memberof hal_spi_driver_c
|
|
* @public
|
|
*
|
|
* @brief ISR error reporting code..
|
|
* The callback is invoked with driver
|
|
* state set to @p HAL_DRV_STATE_ERROR.
|
|
* @note This function is meant to be used in the low level drivers
|
|
* implementations only.
|
|
*
|
|
* @param[in,out] ip Pointer to a @p hal_spi_driver_c instance.
|
|
* @param[in] msg The error code.
|
|
*
|
|
* @notapi
|
|
*/
|
|
CC_FORCE_INLINE
|
|
static inline void __spi_isr_error_code(void *ip, msg_t msg) {
|
|
hal_spi_driver_c *self = (hal_spi_driver_c *)ip;
|
|
|
|
__cbdrv_invoke_cb_with_transition(self,
|
|
HAL_DRV_STATE_ERROR,
|
|
HAL_DRV_STATE_READY);
|
|
__spi_wakeup_isr(self, msg);
|
|
}
|
|
/** @} */
|
|
|
|
#endif /* HAL_USE_SPI == TRUE */
|
|
|
|
#endif /* HAL_SPI_H */
|
|
|
|
/** @} */
|