diff --git a/os/xhal/codegen/hal_spi.xml b/os/xhal/codegen/hal_spi.xml index 41215d9c7..3b2b0ad56 100644 --- a/os/xhal/codegen/hal_spi.xml +++ b/os/xhal/codegen/hal_spi.xml @@ -8,6 +8,26 @@ + + + Enables the circular buffer mode. + + + Enables the slave mode. + + + Memory buffers frame size. + + + Memory frame size is 8 bits + + + Memory frame size is 16 bits + + + Memory frame size is 32 bits + + @p spiSelect() and @p spiUnselect() do nothing. @@ -69,6 +89,10 @@ + + Type of SPI transfer mode options. + + Type of structure representing a SPI driver. @@ -103,16 +127,9 @@ architecture dependent, fields. - - - Enables the circular buffer mode. - - - - - Enables the slave mode. - - + + SPI transfer mode options. + The chip select line. @@ -146,6 +163,7 @@ spi_lld_config_fields;]]> + 0U)); #if SPI_SUPPORTS_CIRCULAR -osalDbgCheck((__spi_getfield(self, circular) == false) || ((n & 1U) == 0U)); +osalDbgCheck(((__spi_getfield(self, mode) & SPI_MODE_CIRCULAR) == 0U) || + ((n & 1U) == 0U)); #endif osalDbgAssert(self->state == HAL_DRV_STATE_READY, "not ready"); @@ -268,7 +287,8 @@ osalDbgCheckClassI(); osalDbgCheck((self != NULL) && (n > 0U) && (rxbuf != NULL) && (txbuf != NULL)); #if SPI_SUPPORTS_CIRCULAR -osalDbgCheck((__spi_getfield(self, circular) == false) || ((n & 1U) == 0U)); +osalDbgCheck(((__spi_getfield(self, mode) & SPI_MODE_CIRCULAR) == 0U) || + ((n & 1U) == 0U)); #endif osalDbgAssert(self->state == HAL_DRV_STATE_READY, "not ready"); @@ -341,7 +361,8 @@ osalDbgCheckClassI(); osalDbgCheck((self != NULL) && (n > 0U) && (txbuf != NULL)); #if SPI_SUPPORTS_CIRCULAR -osalDbgCheck((__spi_getfield(self, circular) == false) || ((n & 1U) == 0U)); +osalDbgCheck(((__spi_getfield(self, mode) & SPI_MODE_CIRCULAR) == 0U) || + ((n & 1U) == 0U)); #endif osalDbgAssert(self->state == HAL_DRV_STATE_READY, "not ready"); @@ -410,7 +431,8 @@ osalDbgCheckClassI(); osalDbgCheck((self != NULL) && (n > 0U) && (rxbuf != NULL)); #if SPI_SUPPORTS_CIRCULAR -osalDbgCheck((__spi_getfield(self, circular) == false) || ((n & 1U) == 0U)); +osalDbgCheck(((__spi_getfield(self, mode) & SPI_MODE_CIRCULAR) == 0U) || + ((n & 1U) == 0U)); #endif osalDbgAssert(self->state == HAL_DRV_STATE_READY, "not ready"); diff --git a/os/xhal/include/hal_spi.h b/os/xhal/include/hal_spi.h index ab6659b28..5d7fb8f20 100644 --- a/os/xhal/include/hal_spi.h +++ b/os/xhal/include/hal_spi.h @@ -33,6 +33,41 @@ /* Module constants. */ /*===========================================================================*/ +/** + * @name SPI operation modes + * @{ + */ +/** + * @brief Enables the circular buffer mode. + */ +#define SPI_MODE_CIRCULAR 1U << 0 + +/** + * @brief Enables the slave mode. + */ +#define SPI_MODE_SLAVE 1U << 1 + +/** + * @brief Memory buffers frame size. + */ +#define SPI_MODE_FSIZE_MASK 3U << 2 + +/** + * @brief Memory frame size is 8 bits. + */ +#define SPI_MODE_FSIZE_8 0U << 2 + +/** + * @brief Memory frame size is 16 bits. + */ +#define SPI_MODE_FSIZE_16 1U << 2 + +/** + * @brief Memory frame size is 32 bits. + */ +#define SPI_MODE_FSIZE_32 2U << 2 +/** @} */ + /** * @name SPI CS modes * @{ @@ -150,6 +185,11 @@ /* Module data structures and types. */ /*===========================================================================*/ +/** + * @brief Type of SPI transfer mode options. + */ +typedef uint_fast16_t spi_mode_t; + /** * @brief Type of structure representing a SPI driver. */ @@ -187,18 +227,10 @@ typedef struct hal_spi_driver SPIDriver; * architecture dependent, fields. */ struct hal_spi_config { -#if (SPI_SUPPORTS_CIRCULAR == TRUE) || defined (__DOXYGEN__) /** - * @brief Enables the circular buffer mode. + * @brief SPI transfer mode options. */ - 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 */ + spi_mode_t mode; #if (SPI_SELECT_MODE == SPI_SELECT_MODE_LINE) || defined (__DOXYGEN__) /** * @brief The chip select line. diff --git a/os/xhal/ports/STM32/LLD/SPIv2/hal_spi_lld.c b/os/xhal/ports/STM32/LLD/SPIv2/hal_spi_lld.c index 5417ae8fa..988fabc5d 100644 --- a/os/xhal/ports/STM32/LLD/SPIv2/hal_spi_lld.c +++ b/os/xhal/ports/STM32/LLD/SPIv2/hal_spi_lld.c @@ -120,8 +120,7 @@ SPIDriver SPID6; * Default SPI configuration. */ static const hal_spi_config_t spi_default_config = { - .circular = false, - .slave = false, + .mode = 0U, #if (SPI_SELECT_MODE == SPI_SELECT_MODE_LINE) || defined (__DOXYGEN__) .ssline = PAL_LINE(STM32_SPI_DEFAULT_PORT, STM32_SPI_DEFAULT_PAD); #elif SPI_SELECT_MODE == SPI_SELECT_MODE_PORT @@ -149,7 +148,7 @@ static void spi_lld_enable(SPIDriver *spip) { uint32_t cr1, cr2; /* SPI setup.*/ - if (config->slave) { + if ((config->mode & SPI_MODE_SLAVE) != 0U) { cr1 = config->cr1 & ~(SPI_CR1_MSTR | SPI_CR1_SPE); cr2 = config->cr2 | SPI_CR2_FRXTH | SPI_CR2_RXDMAEN | SPI_CR2_TXDMAEN; } @@ -174,7 +173,7 @@ static void spi_lld_enable(SPIDriver *spip) { */ static void spi_lld_disable(SPIDriver *spip) { - if (!__spi_getfield(spip, slave)) { + if ((__spi_getfield(spip, mode) & SPI_MODE_SLAVE) == 0U) { /* Master mode, stopping gracefully.*/ /* Stopping TX DMA channel.*/ @@ -266,7 +265,7 @@ static void spi_lld_serve_rx_interrupt(SPIDriver *spip, uint32_t flags) { /* Reporting the failure.*/ __spi_isr_error_code(spip, HAL_RET_HW_FAILURE); } - else if (__spi_getfield(spip, circular)) { + else if ((__spi_getfield(spip, mode) & SPI_MODE_CIRCULAR) != 0U) { if ((flags & STM32_DMA_ISR_HTIF) != 0U) { /* Half buffer interrupt.*/ __spi_isr_half_code(spip); @@ -686,6 +685,7 @@ void spi_lld_stop(SPIDriver *spip) { const hal_spi_config_t *spi_lld_configure(hal_spi_driver_c *spip, const hal_spi_config_t *config) { uint32_t ds; + spi_mode_t mode = __spi_getfield(spip, mode); if (config == NULL) { config = &spi_default_config; @@ -695,23 +695,46 @@ const hal_spi_config_t *spi_lld_configure(hal_spi_driver_c *spip, spi_lld_disable(spip); /* Configuration-specific DMA setup.*/ + spip->rxdmamode &= ~STM32_DMA_CR_SIZE_MASK; + spip->txdmamode &= ~STM32_DMA_CR_SIZE_MASK; + + /* Size of the peripheral port large enough to accommodate the physical + frame size.*/ ds = __spi_getfield(spip, cr2) & SPI_CR2_DS; if (!ds || (ds <= (SPI_CR2_DS_2 | SPI_CR2_DS_1 | SPI_CR2_DS_0))) { /* Frame width is 8 bits or smaller.*/ - spip->rxdmamode = (spip->rxdmamode & ~STM32_DMA_CR_SIZE_MASK) | - STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE; - spip->txdmamode = (spip->txdmamode & ~STM32_DMA_CR_SIZE_MASK) | - STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE; + spip->rxdmamode |= STM32_DMA_CR_PSIZE_BYTE; + spip->txdmamode |= STM32_DMA_CR_PSIZE_BYTE; } else { /* Frame width is larger than 8 bits.*/ - spip->rxdmamode = (spip->rxdmamode & ~STM32_DMA_CR_SIZE_MASK) | - STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD; - spip->txdmamode = (spip->txdmamode & ~STM32_DMA_CR_SIZE_MASK) | - STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD; + spip->rxdmamode |= STM32_DMA_CR_PSIZE_HWORD; + spip->txdmamode |= STM32_DMA_CR_PSIZE_HWORD; } - if (__spi_getfield(spip, circular)) { + /* Size of the memory port as specified in the configuration. This may + result in data truncation or zero-padding if the peripheral and memory + port sizes differ. + The behavior is also different between DMAv1 and DMAv2.*/ + switch (mode & SPI_MODE_FSIZE_MASK) { + case SPI_MODE_FSIZE_8: + spip->rxdmamode |= STM32_DMA_CR_MSIZE_BYTE; + spip->txdmamode |= STM32_DMA_CR_MSIZE_BYTE; + break; + case SPI_MODE_FSIZE_16: + spip->rxdmamode |= STM32_DMA_CR_MSIZE_HWORD; + spip->txdmamode |= STM32_DMA_CR_MSIZE_HWORD; + break; + case SPI_MODE_FSIZE_32: + spip->rxdmamode |= STM32_DMA_CR_MSIZE_WORD; + spip->txdmamode |= STM32_DMA_CR_MSIZE_WORD; + break; + default: + /* Unsupported mode.*/ + return NULL; + } + + if ((mode & SPI_MODE_CIRCULAR) != 0U) { spip->rxdmamode |= (STM32_DMA_CR_CIRC | STM32_DMA_CR_HTIE); spip->txdmamode |= (STM32_DMA_CR_CIRC | STM32_DMA_CR_HTIE); } diff --git a/os/xhal/src/hal_spi.c b/os/xhal/src/hal_spi.c index d62752e80..362a2b9a3 100644 --- a/os/xhal/src/hal_spi.c +++ b/os/xhal/src/hal_spi.c @@ -241,7 +241,8 @@ msg_t spiStartIgnoreI(void *ip, size_t n) { osalDbgCheck((self != NULL) && (n > 0U)); #if SPI_SUPPORTS_CIRCULAR - osalDbgCheck((__spi_getfield(self, circular) == false) || ((n & 1U) == 0U)); + osalDbgCheck(((__spi_getfield(self, mode) & SPI_MODE_CIRCULAR) == 0U) || + ((n & 1U) == 0U)); #endif osalDbgAssert(self->state == HAL_DRV_STATE_READY, "not ready"); @@ -314,7 +315,8 @@ msg_t spiStartExchangeI(void *ip, size_t n, const void *txbuf, void *rxbuf) { osalDbgCheck((self != NULL) && (n > 0U) && (rxbuf != NULL) && (txbuf != NULL)); #if SPI_SUPPORTS_CIRCULAR - osalDbgCheck((__spi_getfield(self, circular) == false) || ((n & 1U) == 0U)); + osalDbgCheck(((__spi_getfield(self, mode) & SPI_MODE_CIRCULAR) == 0U) || + ((n & 1U) == 0U)); #endif osalDbgAssert(self->state == HAL_DRV_STATE_READY, "not ready"); @@ -388,7 +390,8 @@ msg_t spiStartSendI(void *ip, size_t n, const void *txbuf) { osalDbgCheck((self != NULL) && (n > 0U) && (txbuf != NULL)); #if SPI_SUPPORTS_CIRCULAR - osalDbgCheck((__spi_getfield(self, circular) == false) || ((n & 1U) == 0U)); + osalDbgCheck(((__spi_getfield(self, mode) & SPI_MODE_CIRCULAR) == 0U) || + ((n & 1U) == 0U)); #endif osalDbgAssert(self->state == HAL_DRV_STATE_READY, "not ready"); @@ -460,7 +463,8 @@ msg_t spiStartReceiveI(void *ip, size_t n, void *rxbuf) { osalDbgCheck((self != NULL) && (n > 0U) && (rxbuf != NULL)); #if SPI_SUPPORTS_CIRCULAR - osalDbgCheck((__spi_getfield(self, circular) == false) || ((n & 1U) == 0U)); + osalDbgCheck(((__spi_getfield(self, mode) & SPI_MODE_CIRCULAR) == 0U) || + ((n & 1U) == 0U)); #endif osalDbgAssert(self->state == HAL_DRV_STATE_READY, "not ready");