From e79ef9f80120860120a8e06d0552228bb76499c7 Mon Sep 17 00:00:00 2001 From: Giovanni Di Sirio Date: Fri, 16 Jun 2023 11:32:07 +0000 Subject: [PATCH] More SPI-related code in XHAL. git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@16286 27425a3e-05d8-49a3-a47f-9c15f0e5edd8 --- os/xhal/codegen/hal_base_driver.xml | 14 +- os/xhal/codegen/hal_cb_driver.xml | 53 +++++- os/xhal/codegen/hal_spi.xml | 258 ++++++++++++++++++++------ os/xhal/include/hal_base_driver.h | 6 +- os/xhal/include/hal_buffered_serial.h | 4 + os/xhal/include/hal_cb_driver.h | 77 +++++++- os/xhal/include/hal_sio.h | 8 + os/xhal/include/hal_spi.h | 83 +++++++++ os/xhal/src/hal_base_driver.c | 9 +- os/xhal/src/hal_cb_driver.c | 17 ++ os/xhal/src/hal_spi.c | 65 ++++++- 11 files changed, 511 insertions(+), 83 deletions(-) diff --git a/os/xhal/codegen/hal_base_driver.xml b/os/xhal/codegen/hal_base_driver.xml index c676d2798..074d9147a 100644 --- a/os/xhal/codegen/hal_base_driver.xml +++ b/os/xhal/codegen/hal_base_driver.xml @@ -17,8 +17,6 @@ - - @@ -66,6 +64,9 @@ Driver state. + + Associated configuration structure. + Driver argument. @@ -89,12 +90,13 @@ state = HAL_DRV_STATE_STOP; -self->arg = NULL; +self->state = HAL_DRV_STATE_STOP; +self->arg = NULL; +self->config = NULL; osalMutexObjectInit(&self->mutex); #if HAL_USE_REGISTRY == TRUE -self->id = 0U; -self->name = "unk"; +self->id = 0U; +self->name = "unk"; drv_reg_insert(self); #endif]]> diff --git a/os/xhal/codegen/hal_cb_driver.xml b/os/xhal/codegen/hal_cb_driver.xml index b0fafdb14..42c49ee41 100644 --- a/os/xhal/codegen/hal_cb_driver.xml +++ b/os/xhal/codegen/hal_cb_driver.xml @@ -7,6 +7,12 @@ hal_base_driver.xml + + + + + + Generic HAL notification callback type. @@ -29,22 +35,59 @@ self->cb = NULL;]]> - - - Associates a callback to the driver instance. + + + + Associates a callback to the driver instance. + - Callback function to be associated. Passing @p NULL disables the - existing callback, if any. + Callback function to be associated. Passing @p NULL + disables the existing callback, if any. + cb = cb;]]> + + Returns the callback associated to the driver instance. cb;]]> + + Checks for @p HAL_DRV_STATE_COMPLETE state. +
+ + The check result. + If the current state is not @p HAL_DRV_STATE_COMPLETE. + If the current state is @p HAL_DRV_STATE_COMPLETE. + + state == HAL_DRV_STATE_COMPLETE);]]> +
+ + Checks for @p HAL_DRV_STATE_ERROR state. +
+ + The check result. + If the current state is not @p HAL_DRV_STATE_ERROR. + If the current state is @p HAL_DRV_STATE_ERROR. + + state == HAL_DRV_STATE_ERROR);]]> +
diff --git a/os/xhal/codegen/hal_spi.xml b/os/xhal/codegen/hal_spi.xml index 945cdb9be..37e3ea034 100644 --- a/os/xhal/codegen/hal_spi.xml +++ b/os/xhal/codegen/hal_spi.xml @@ -1,7 +1,8 @@ + name="hal_spi" descr="SPI Driver" check="HAL_USE_SPI == TRUE" + editcode="false"> SPI Driver macros and structures. hal_cb_driver.xml @@ -31,7 +32,8 @@ Support for thread synchronization API. - + Handling method for SPI CS line. @@ -53,7 +55,8 @@ Type of structure representing a SPI configuration - (legacy). + (legacy). + @@ -87,13 +90,15 @@ Enables the slave mode. - + The chip select line. Only used in master mode. - + The chip select port. Only used in master mode. @@ -103,7 +108,8 @@ Only used in master mode. - + The chip select port. Only used in master mode. @@ -126,12 +132,18 @@ SPI_CONFIG_EXT_FIELDS]]> ancestorname="hal_cb_driver" descr="SPI driver"> Class of a SPI driver. + + + Synchronization point for transfer. + + + @@ -154,7 +166,8 @@ SPI_DRIVER_EXT_INIT_HOOK(self);
- Number of frames to be + Number of frames + to be ignored. The operation status. @@ -188,7 +201,8 @@ return msg;]]>
- Number of frames to be + Number of frames + to be ignored. The operation status. @@ -211,13 +225,16 @@ return msg;]]> if enabled.]]> - Number of frames to be + Number of frames + to be exchanged. - Pointer to the + Pointer + to the transmit buffer. - Pointer to the + Pointer to + the receive buffer. The operation status. @@ -253,13 +270,16 @@ return msg;]]> if enabled.]]> - Number of frames to be + Number of frames + to be exchanged. - Pointer to the + Pointer + to the transmit buffer. - Pointer to the + Pointer to + the receive buffer. The operation status. @@ -282,10 +302,12 @@ return msg;]]> if enabled.]]> - Number of frames to be + Number of frames + to be exchanged. - Pointer to the + Pointer + to the transmit buffer. The operation status. @@ -320,10 +342,12 @@ return msg;]]> if enabled.]]> - Number of frames to be + Number of frames + to be exchanged. - Pointer to the + Pointer + to the transmit buffer. The operation status. @@ -346,10 +370,12 @@ return msg;]]> if enabled.]]> - Number of frames to be + Number of frames + to be exchanged. - Pointer to the + Pointer to + the receive buffer. The operation status. @@ -384,10 +410,12 @@ return msg;]]> if enabled.]]> - Number of frames to be + Number of frames + to be exchanged. - Pointer to the + Pointer to + the receive buffer. The operation status. @@ -403,7 +431,8 @@ return msg;]]> Stops the ongoing SPI operation. - Pointer to the counter + Pointer to the + counter of frames not yet transferred or @p NULL. The operation status. @@ -439,7 +468,8 @@ return msg;]]> Stops the ongoing SPI operation. - Pointer to the counter + Pointer to the + counter of frames not yet transferred or @p NULL. The operation status. @@ -459,14 +489,18 @@ return msg;]]> - Synchronization + Synchronization timeout. The synchronization result. - If operation completed without errors. + If operation completed without + errors. + + If synchronization timed out. + + If the transfer has been stopped. - If synchronization timed out. - If the transfer has been stopped. - Synchronization + Synchronization timeout. The synchronization result. - If operation completed without errors. + If operation completed without + errors. + + If synchronization timed out. + + If the transfer has been stopped. - If synchronization timed out. - If the transfer has been stopped. of a series of idle words on the SPI bus and ignores the received data.]]>
- Number of frames to be + Number of + frames to be ignored. The operation status. - If operation completed without errors. + If operation completed without + errors. + + If synchronization timed out. + + If the transfer has been stopped. - If synchronization timed out. - If the transfer has been stopped.
- Number of frames to be + Number of + frames to be exchanged. - Pointer to + Pointer + to the transmit buffer. - Pointer to the + Pointer to + the receive buffer. The operation status. - If operation completed without errors. + If operation completed without + errors. + + If synchronization timed out. + + If the transfer has been stopped. - If synchronization timed out. - If the transfer has been stopped.
- Number of frames to be + Number of + frames to be exchanged. - Pointer to + Pointer + to the transmit buffer. The operation status. - If operation completed without errors. + If operation completed without + errors. + + If synchronization timed out. + + If the transfer has been stopped. - If synchronization timed out. - If the transfer has been stopped.
- Number of frames to be + Number of + frames to be exchanged. - Pointer to the + Pointer to + the receive buffer. The operation status. - If operation completed without errors. + If operation completed without + errors. + + If synchronization timed out. + + If the transfer has been stopped. - If synchronization timed out. - If the transfer has been stopped.
- + Asserts the slave select signal and prepares for - transfers. + transfers. + spi_lld_unselect(self);]]> - + config->ssline);]]> palSetLine(self->config->ssline);]]> - + config->ssport, self->config->ssmask);]]> palSetPort(self->config->ssport, self->config->ssmask);]]> - + config->ssport, self->config->sspad);]]> palSetPad(self->config->ssport, self->config->sspad);]]> + + + Wakes up the waiting thread. + This function is meant to be used in the low level + drivers implementations only. + + The wakeup + message. + + + sync_transfer, MSG_OK); +osalSysUnlockFromISR();]]> + + + + + + + + + Common ISR code in linear mode. +
+ This function is meant to be used in the low level + drivers implementations only. + + + config->data_cb) { + self->state = HAL_DRV_STATE_COMPLETE; + self->config->data_cb(spip); + if (self->state == HAL_DRV_STATE_COMPLETE) + self->state = HAL_DRV_STATE_READY; +} +else { + self->state = HAL_DRV_STATE_READY; +} + +#if SPI_USE_SYNCHRONIZATION == TRUE +/* Thread wakeup, if any.*/ +osalSysLockFromISR(); +osalThreadResumeI(&self->sync_transfer, MSG_OK); +osalSysUnlockFromISR(); +#endif]]> +
+ + + + + + + + + config = config;]]> + + + + +
SPI Driver initialization. - - This function is implicitly invoked by @p halInit(), there is no - need to explicitly initialize the driver. - + cb = cb; + self->vmt->setcb(ip, cb); } +/** @} */ +/** + * @name Inline methods of hal_cb_driver_c + * @{ + */ /** * @memberof hal_cb_driver_c * @public @@ -177,6 +196,60 @@ static inline hal_cb_t drvGetCallback(void *ip) { return self->cb; } + +/** + * @memberof hal_cb_driver_c + * @public + * + * @brief Checks for @p HAL_DRV_STATE_COMPLETE state. + * @details The @p HAL_DRV_STATE_COMPLETE state is used by those drivers + * triggering multiple callbacks for a single asynchronous + * operation, it marks the last callback in the sequence. + * @note This function is meant to be called exclusively from the driver + * callback. + * + * @param[in,out] ip Pointer to a @p hal_cb_driver_c instance. + * @return The check result. + * @retval false If the current state is not @p + * HAL_DRV_STATE_COMPLETE. + * @retval true If the current state is @p + * HAL_DRV_STATE_COMPLETE. + * + * @api + */ +CC_FORCE_INLINE +static inline bool drvStateIsCompleteI(void *ip) { + hal_cb_driver_c *self = (hal_cb_driver_c *)ip; + + return (bool)(self->state == HAL_DRV_STATE_COMPLETE); +} + +/** + * @memberof hal_cb_driver_c + * @public + * + * @brief Checks for @p HAL_DRV_STATE_ERROR state. + * @details The @p HAL_DRV_STATE_ERROR state during a callback marks an + * error in an asynchronous operation, the operation is implicitly + * stopped and the driver is switched back to its @p + * HAL_DRV_STATE_READY state. + * @note This function is meant to be called exclusively from the driver + * callback. + * + * @param[in,out] ip Pointer to a @p hal_cb_driver_c instance. + * @return The check result. + * @retval false If the current state is not @p + * HAL_DRV_STATE_ERROR. + * @retval true If the current state is @p HAL_DRV_STATE_ERROR. + * + * @api + */ +CC_FORCE_INLINE +static inline bool drvStateIsErrorI(void *ip) { + hal_cb_driver_c *self = (hal_cb_driver_c *)ip; + + return (bool)(self->state == HAL_DRV_STATE_ERROR); +} /** @} */ #endif /* HAL_CB_DRIVER_H */ diff --git a/os/xhal/include/hal_sio.h b/os/xhal/include/hal_sio.h index db803a449..71f2c9f2a 100644 --- a/os/xhal/include/hal_sio.h +++ b/os/xhal/include/hal_sio.h @@ -565,6 +565,10 @@ struct hal_sio_driver { * @brief Driver state. */ driver_state_t state; + /** + * @brief Associated configuration structure. + */ + const void *config; /** * @brief Driver argument. */ @@ -672,6 +676,10 @@ struct hal_buffered_sio { * @brief Driver state. */ driver_state_t state; + /** + * @brief Associated configuration structure. + */ + const void *config; /** * @brief Driver argument. */ diff --git a/os/xhal/include/hal_spi.h b/os/xhal/include/hal_spi.h index 558bc6f0d..48edc2220 100644 --- a/os/xhal/include/hal_spi.h +++ b/os/xhal/include/hal_spi.h @@ -225,6 +225,7 @@ struct hal_spi_driver_vmt { void (*stop)(void *ip); msg_t (*configure)(void *ip, const void *config); /* From hal_cb_driver_c.*/ + void (*setcb)(void *ip, hal_cb_t cb); /* From hal_spi_driver_c.*/ }; @@ -240,6 +241,10 @@ struct hal_spi_driver { * @brief Driver state. */ driver_state_t state; + /** + * @brief Associated configuration structure. + */ + const void *config; /** * @brief Driver argument. */ @@ -269,6 +274,12 @@ struct hal_spi_driver { * @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 @@ -287,6 +298,10 @@ extern "C" { /* 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); + msg_t __spi_configure_impl(void *ip, const void *config); + void __spi_setcb_impl(void *ip, hal_cb_t cb); 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); @@ -422,6 +437,74 @@ static inline void spiUnselectX(void *ip) { palSetPad(self->config->ssport, self->config->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_OK); + 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; +} +#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; + if (self->config->data_cb) { + self->state = HAL_DRV_STATE_COMPLETE; + self->config->data_cb(spip); + if (self->state == HAL_DRV_STATE_COMPLETE) + self->state = HAL_DRV_STATE_READY; + } + else { + self->state = HAL_DRV_STATE_READY; + } + +#if SPI_USE_SYNCHRONIZATION == TRUE + /* Thread wakeup, if any.*/ + osalSysLockFromISR(); + osalThreadResumeI(&self->sync_transfer, MSG_OK); + osalSysUnlockFromISR(); +#endif +} /** @} */ #endif /* HAL_USE_SPI == TRUE */ diff --git a/os/xhal/src/hal_base_driver.c b/os/xhal/src/hal_base_driver.c index b6cb69f99..3d273f03a 100644 --- a/os/xhal/src/hal_base_driver.c +++ b/os/xhal/src/hal_base_driver.c @@ -218,12 +218,13 @@ void *__drv_objinit_impl(void *ip, const void *vmt) { __bo_objinit_impl(self, vmt); /* Initialization code.*/ - self->state = HAL_DRV_STATE_STOP; - self->arg = NULL; + self->state = HAL_DRV_STATE_STOP; + self->arg = NULL; + self->config = NULL; osalMutexObjectInit(&self->mutex); #if HAL_USE_REGISTRY == TRUE - self->id = 0U; - self->name = "unk"; + self->id = 0U; + self->name = "unk"; drv_reg_insert(self); #endif diff --git a/os/xhal/src/hal_cb_driver.c b/os/xhal/src/hal_cb_driver.c index c720aa028..3a235853f 100644 --- a/os/xhal/src/hal_cb_driver.c +++ b/os/xhal/src/hal_cb_driver.c @@ -104,6 +104,23 @@ void __cbdrv_dispose_impl(void *ip) { /* Finalization of the ancestors-defined parts.*/ __drv_dispose_impl(self); } + +/** + * @memberof hal_cb_driver_c + * @protected + * + * @brief Implementation of method @p drvSetCallback(). + * @note This function is meant to be used by derived classes. + * + * @param[in,out] ip Pointer to a @p hal_cb_driver_c instance. + * @param cb Callback function to be associated. Passing @p + * NULL disables the existing callback, if any. + */ +void __cbdrv_setcb_impl(void *ip, hal_cb_t cb) { + hal_cb_driver_c *self = (hal_cb_driver_c *)ip; + + self->cb = cb; +} /** @} */ /** @} */ diff --git a/os/xhal/src/hal_spi.c b/os/xhal/src/hal_spi.c index 1370061d0..964d7818b 100644 --- a/os/xhal/src/hal_spi.c +++ b/os/xhal/src/hal_spi.c @@ -122,6 +122,64 @@ void __spi_dispose_impl(void *ip) { /* Finalization of the ancestors-defined parts.*/ __cbdrv_dispose_impl(self); } + +/** + * @memberof hal_spi_driver_c + * @protected + * + * @brief Override of method @p __drv_start(). + * + * @param[in,out] ip Pointer to a @p hal_spi_driver_c instance. + * @return The operation status. + */ +msg_t __spi_start_impl(void *ip) { + hal_spi_driver_c *self = (hal_spi_driver_c *)ip; +} + +/** + * @memberof hal_spi_driver_c + * @protected + * + * @brief Override of method @p __drv_stop(). + * + * @param[in,out] ip Pointer to a @p hal_spi_driver_c instance. + */ +void __spi_stop_impl(void *ip) { + hal_spi_driver_c *self = (hal_spi_driver_c *)ip; +} + +/** + * @memberof hal_spi_driver_c + * @protected + * + * @brief Override of method @p drvConfigureX(). + * + * @param[in,out] ip Pointer to a @p hal_spi_driver_c instance. + * @param[in] config New driver configuration. + */ +msg_t __spi_configure_impl(void *ip, const void *config) { + hal_spi_driver_c *self = (hal_spi_driver_c *)ip; + + self->config = config; +} + +/** + * @memberof hal_spi_driver_c + * @protected + * + * @brief Override of method @p drvSetCallback(). + * + * @param[in,out] ip Pointer to a @p hal_spi_driver_c instance. + * @param cb Callback function to be associated. Passing @p + * NULL disables the existing callback, if any. + */ +void __spi_setcb_impl(void *ip, hal_cb_t cb) { + hal_spi_driver_c *self = (hal_spi_driver_c *)ip; + + __cbdrv_setcb_impl(self); + + spi_lld_setcb(self, cb); +} /** @} */ /** @@ -130,9 +188,10 @@ void __spi_dispose_impl(void *ip) { */ const struct hal_spi_driver_vmt __hal_spi_driver_vmt = { .dispose = __spi_dispose_impl, - .start = NULL /* Method not found.*/, - .stop = NULL /* Method not found.*/, - .configure = NULL /* Method not found.*/ + .start = __spi_start_impl, + .stop = __spi_stop_impl, + .configure = __spi_configure_impl, + .setcb = __spi_setcb_impl }; /**