diff options
Diffstat (limited to 'os/hal/ports/SAMA/LLD/SPIv1')
-rw-r--r-- | os/hal/ports/SAMA/LLD/SPIv1/hal_spi_lld.c | 205 | ||||
-rw-r--r-- | os/hal/ports/SAMA/LLD/SPIv1/hal_spi_lld.h | 300 |
2 files changed, 397 insertions, 108 deletions
diff --git a/os/hal/ports/SAMA/LLD/SPIv1/hal_spi_lld.c b/os/hal/ports/SAMA/LLD/SPIv1/hal_spi_lld.c index ccacf5e70..95625ca07 100644 --- a/os/hal/ports/SAMA/LLD/SPIv1/hal_spi_lld.c +++ b/os/hal/ports/SAMA/LLD/SPIv1/hal_spi_lld.c @@ -56,7 +56,6 @@ spip->SPI_WPMR = SPI_WPMR_WPKEY_PASSWD; \ } - /*===========================================================================*/ /* Driver exported variables. */ /*===========================================================================*/ @@ -114,8 +113,8 @@ SPIDriver FSPID4; /* Driver local variables and types. */ /*===========================================================================*/ -static const uint8_t dummytx = 0xFFU; -static uint8_t dummyrx; +static const CACHE_ALIGNED uint8_t dummytx = 0xFFU; +CACHE_ALIGNED static uint8_t dummyrx; /*===========================================================================*/ /* Driver local functions. */ @@ -142,6 +141,13 @@ static void spi_lld_serve_rx_interrupt(SPIDriver *spip, uint32_t flags) { dmaChannelDisable(spip->dmatx); dmaChannelDisable(spip->dmarx); +#if (SAMA_SPI_CACHE_USER_MANAGED == FALSE) + /* D-Cache is enabled */ + /* No operation for dummyrx */ + if ((uint32_t) spip->rxbuf != (uint32_t) &dummyrx) + cacheInvalidateRegion(spip->rxbuf, spip->rxbytes); +#endif + /* Portable SPI ISR code defined in the high level driver, note, it is a macro.*/ _spi_isr_code(spip); @@ -156,7 +162,6 @@ static void spi_lld_serve_rx_interrupt(SPIDriver *spip, uint32_t flags) { static void spi_lld_serve_tx_interrupt(SPIDriver *spip, uint32_t flags) { /* DMA errors handling.*/ - #if defined(SAMA_SPI_DMA_ERROR_HOOK) (void)spip; if ((flags & (XDMAC_CIS_WBEIS | XDMAC_CIS_ROIS)) != 0) { @@ -189,6 +194,7 @@ void spi_lld_init(void) { /* Driver initialization.*/ spiObjectInit(&SPID0); SPID0.spi = SPI0; + SPID0.flexcom = NULL; SPID0.dmarx = NULL; SPID0.dmatx = NULL; SPID0.rxdmamode = XDMAC_CC_TYPE_PER_TRAN | @@ -222,6 +228,7 @@ void spi_lld_init(void) { /* Driver initialization.*/ spiObjectInit(&SPID1); SPID1.spi = SPI1; + SPID1.flexcom = NULL; SPID1.dmarx = NULL; SPID1.dmatx = NULL; SPID1.rxdmamode = XDMAC_CC_TYPE_PER_TRAN | @@ -443,6 +450,15 @@ void spi_lld_start(SPIDriver *spip) { (sama_dmaisr_t)spi_lld_serve_tx_interrupt, (void *)spip); osalDbgAssert(spip->dmatx != NULL, "no channel allocated"); + +#if SAMA_SPI0_USE_GCLK +#if SAMA_SPI0_GCLK_DIV > 256 + #error "SPI0 GCLK divider out of range" +#endif + pmcConfigGclk(ID_SPI0, SAMA_SPI0_GCLK_SOURCE, SAMA_SPI0_GCLK_DIV); + pmcEnableGclk(ID_SPI0); +#endif /* SAMA_SPI0_USE_GCLK */ + /* Enable SPI0 clock */ pmcEnableSPI0(); } @@ -458,6 +474,15 @@ void spi_lld_start(SPIDriver *spip) { (sama_dmaisr_t)spi_lld_serve_tx_interrupt, (void *)spip); osalDbgAssert(spip->dmatx != NULL, "no channel allocated"); + +#if SAMA_SPI1_USE_GCLK +#if SAMA_SPI1_GCLK_DIV > 256 + #error "SPI1 GCLK divider out of range" +#endif + pmcConfigGclk(ID_SPI1, SAMA_SPI1_GCLK_SOURCE, SAMA_SPI1_GCLK_DIV); + pmcEnableGclk(ID_SPI1); +#endif /* SAMA_SPI1_USE_GCLK */ + /* Enable SPI1 clock */ pmcEnableSPI1(); } @@ -475,6 +500,15 @@ void spi_lld_start(SPIDriver *spip) { osalDbgAssert(spip->dmatx != NULL, "no channel allocated"); /* Enabling SPI on FLEXCOM */ spip->flexcom->FLEX_MR = FLEX_MR_OPMODE_SPI; + +#if SAMA_FSPI0_USE_GCLK +#if SAMA_FSPI0_GCLK_DIV > 256 + #error "FSPI0 GCLK divider out of range" +#endif + pmcConfigGclk(ID_FLEXCOM0, SAMA_FSPI0_GCLK_SOURCE, SAMA_FSPI0_GCLK_DIV); + pmcEnableGclk(ID_FLEXCOM0); +#endif /* SAMA_FSPI0_USE_GCLK */ + /* Enable FLEXCOM0 clock */ pmcEnableFLEXCOM0(); } @@ -492,6 +526,15 @@ void spi_lld_start(SPIDriver *spip) { osalDbgAssert(spip->dmatx != NULL, "no channel allocated"); /* Enabling SPI on FLEXCOM */ spip->flexcom->FLEX_MR = FLEX_MR_OPMODE_SPI; + +#if SAMA_FSPI1_USE_GCLK +#if SAMA_FSPI1_GCLK_DIV > 256 + #error "FSPI1 GCLK divider out of range" +#endif + pmcConfigGclk(ID_FLEXCOM1, SAMA_FSPI1_GCLK_SOURCE, SAMA_FSPI1_GCLK_DIV); + pmcEnableGclk(ID_FLEXCOM1); +#endif /* SAMA_FSPI1_USE_GCLK */ + /* Enable FLEXCOM1 clock */ pmcEnableFLEXCOM1(); } @@ -509,6 +552,15 @@ void spi_lld_start(SPIDriver *spip) { osalDbgAssert(spip->dmatx != NULL, "no channel allocated"); /* Enabling SPI on FLEXCOM */ spip->flexcom->FLEX_MR = FLEX_MR_OPMODE_SPI; + +#if SAMA_FSPI2_USE_GCLK +#if SAMA_FSPI2_GCLK_DIV > 256 + #error "FSPI2 GCLK divider out of range" +#endif + pmcConfigGclk(ID_FLEXCOM2, SAMA_FSPI2_GCLK_SOURCE, SAMA_FSPI2_GCLK_DIV); + pmcEnableGclk(ID_FLEXCOM2); +#endif /* SAMA_FSPI2_USE_GCLK */ + /* Enable FLEXCOM2 clock */ pmcEnableFLEXCOM2(); } @@ -526,6 +578,15 @@ void spi_lld_start(SPIDriver *spip) { osalDbgAssert(spip->dmatx != NULL, "no channel allocated"); /* Enabling SPI on FLEXCOM */ spip->flexcom->FLEX_MR = FLEX_MR_OPMODE_SPI; + +#if SAMA_FSPI3_USE_GCLK +#if SAMA_FSPI3_GCLK_DIV > 256 + #error "FSPI3 GCLK divider out of range" +#endif + pmcConfigGclk(ID_FLEXCOM3, SAMA_FSPI3_GCLK_SOURCE, SAMA_FSPI3_GCLK_DIV); + pmcEnableGclk(ID_FLEXCOM3); +#endif /* SAMA_FSPI3_USE_GCLK */ + /* Enable FLEXCOM3 clock */ pmcEnableFLEXCOM3(); } @@ -543,7 +604,16 @@ void spi_lld_start(SPIDriver *spip) { osalDbgAssert(spip->dmatx != NULL, "no channel allocated"); /* Enabling SPI on FLEXCOM */ spip->flexcom->FLEX_MR = FLEX_MR_OPMODE_SPI; - /* Enable FLEXCOM4 clock */ + +#if SAMA_FSPI4_USE_GCLK +#if SAMA_FSPI4_GCLK_DIV > 256 + #error "FSPI4 GCLK divider out of range" +#endif + pmcConfigGclk(ID_FLEXCOM4, SAMA_FSPI4_GCLK_SOURCE, SAMA_FSPI4_GCLK_DIV); + pmcEnableGclk(ID_FLEXCOM4); +#endif /* SAMA_FSPI4_USE_GCLK */ + + /* Enable FLEXCOM4 clock */ pmcEnableFLEXCOM4(); } #endif /* SAMA_SPI_USE_FLEXCOM4 */ @@ -605,20 +675,32 @@ void spi_lld_stop(SPIDriver *spip) { if (&SPID0 == spip) /* Disable SPI0 clock */ pmcDisableSPI0(); +#if SAMA_SPI0_USE_GCLK + pmcDisableGclk(ID_SPI0); +#endif /* SAMA_SPI0_USE_GCLK */ + +#endif /* SAMA_SPI_USE_SPI0 */ -#endif /* SAMA_SPI_USE_SPI1 */ #if SAMA_SPI_USE_SPI1 if (&SPID1 == spip) /* Disable SPI1 clock */ pmcDisableSPI1(); -#endif /* SAMA_SPI_USE_FLEXCOM0 */ +#if SAMA_SPI1_USE_GCLK + pmcDisableGclk(ID_SPI1); +#endif /* SAMA_SPI1_USE_GCLK */ + +#endif /* SAMA_SPI_USE_SPI1 */ #if SAMA_SPI_USE_FLEXCOM0 if (&FSPID0 == spip) /* Disable FLEXCOM0 clock */ pmcDisableFLEXCOM0(); +#if SAMA_FSPI0_USE_GCLK + pmcDisableGclk(ID_FLEXCOM0); +#endif /* SAMA_FSPI0_USE_GCLK */ + #endif /* SAMA_SPI_USE_FLEXCOM0 */ #if SAMA_SPI_USE_FLEXCOM1 @@ -626,6 +708,10 @@ void spi_lld_stop(SPIDriver *spip) { /* Disable FLEXCOM1 clock */ pmcDisableFLEXCOM1(); +#if SAMA_FSPI1_USE_GCLK + pmcDisableGclk(ID_FLEXCOM1); +#endif /* SAMA_FSPI1_USE_GCLK */ + #endif /* SAMA_SPI_USE_FLEXCOM1 */ #if SAMA_SPI_USE_FLEXCOM2 @@ -633,6 +719,10 @@ void spi_lld_stop(SPIDriver *spip) { /* Disable FLEXCOM2 clock */ pmcDisableFLEXCOM2(); +#if SAMA_FSPI2_USE_GCLK + pmcDisableGclk(ID_FLEXCOM2); +#endif /* SAMA_FSPI2_USE_GCLK */ + #endif /* SAMA_SPI_USE_FLEXCOM2 */ #if SAMA_SPI_USE_FLEXCOM3 @@ -640,6 +730,10 @@ void spi_lld_stop(SPIDriver *spip) { /* Disable FLEXCOM3 clock */ pmcDisableFLEXCOM3(); +#if SAMA_FSPI3_USE_GCLK + pmcDisableGclk(ID_FLEXCOM3); +#endif /* SAMA_FSPI3_USE_GCLK */ + #endif /* SAMA_SPI_USE_FLEXCOM3 */ #if SAMA_SPI_USE_FLEXCOM4 @@ -647,8 +741,16 @@ void spi_lld_stop(SPIDriver *spip) { /* Disable FLEXCOM4 clock */ pmcDisableFLEXCOM4(); +#if SAMA_FSPI4_USE_GCLK + pmcDisableGclk(ID_FLEXCOM4); +#endif /* SAMA_FSPI4_USE_GCLK */ + #endif /* SAMA_SPI_USE_FLEXCOM4 */ } + + spip->txbuf = NULL; + spip->rxbuf = NULL; + spip->rxbytes = 0; } #if (SPI_SELECT_MODE == (SPI_SELECT_MODE_LLD || SPI_SELECT_MODE_PAD || \ @@ -695,12 +797,35 @@ void spi_lld_unselect(SPIDriver *spip) { void spi_lld_exchange(SPIDriver *spip, size_t n, const void *txbuf, void *rxbuf) { + spip->txbuf = txbuf; + spip->rxbuf = rxbuf; + spip->rxbytes = n; + +#if (SAMA_SPI_CACHE_USER_MANAGED == FALSE) + + osalDbgAssert(!((uint32_t) txbuf & (L1_CACHE_BYTES - 1)), "txbuf address not cache aligned"); + osalDbgAssert(!((uint32_t) rxbuf & (L1_CACHE_BYTES - 1)), "rxbuf address not cache aligned"); + + /* + * If size is not multiple of cache line, clean cache region is required. + */ + if (n & (L1_CACHE_BYTES - 1)) { + cacheCleanRegion((uint8_t *) rxbuf, n); + } + /* Cache is enabled */ + cacheCleanRegion((uint8_t *) txbuf, n); +#endif /* SAMA_SPI_CACHE_USER_MANAGED */ + /* Writing channel */ + /* Change mode to incremented address for dummytx */ + dmaChannelSetMode(spip->dmatx, spip->txdmamode | XDMAC_CC_SAM_INCREMENTED_AM); dmaChannelSetSource(spip->dmatx, txbuf); dmaChannelSetDestination(spip->dmatx, &spip->spi->SPI_TDR); dmaChannelSetTransactionSize(spip->dmatx, n); /* Reading channel */ + /* Change mode to incremented address */ + dmaChannelSetMode(spip->dmarx, spip->rxdmamode | XDMAC_CC_DAM_INCREMENTED_AM); dmaChannelSetSource(spip->dmarx, &spip->spi->SPI_RDR); dmaChannelSetDestination(spip->dmarx, rxbuf); dmaChannelSetTransactionSize(spip->dmarx, n); @@ -724,17 +849,37 @@ void spi_lld_exchange(SPIDriver *spip, size_t n, */ void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf) { + spip->txbuf = txbuf; + spip->rxbuf = &dummyrx; + spip->rxbytes = n; + +#if (SAMA_SPI_CACHE_USER_MANAGED == FALSE) + + osalDbgAssert(!((uint32_t) txbuf & (L1_CACHE_BYTES - 1)), "address not cache aligned"); + + /* Cache is enabled */ + cacheCleanRegion((uint8_t *) txbuf, n); +#endif /* SAMA_SPI_CACHE_USER_MANAGED */ + /* Writing channel */ + + /* Change mode to incremented address for dummytx */ + dmaChannelSetMode(spip->dmatx, spip->txdmamode | XDMAC_CC_SAM_INCREMENTED_AM); + dmaChannelSetSource(spip->dmatx, txbuf); dmaChannelSetDestination(spip->dmatx, &spip->spi->SPI_TDR); dmaChannelSetTransactionSize(spip->dmatx, n); /* Reading channel */ + + /* Change mode from incremented to fixed address for dummyrx */ + dmaChannelSetMode(spip->dmarx, spip->rxdmamode & ~XDMAC_CC_DAM_INCREMENTED_AM); + dmaChannelSetSource(spip->dmarx, &spip->spi->SPI_RDR); dmaChannelSetDestination(spip->dmarx, &dummyrx); dmaChannelSetTransactionSize(spip->dmarx, n); - /* Enable write protection. */ + /* Enable channel. */ dmaChannelEnable(spip->dmarx); dmaChannelEnable(spip->dmatx); @@ -759,12 +904,33 @@ void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf) { */ void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf) { + spip->rxbuf = rxbuf; + spip->rxbytes = n; + +#if (SAMA_SPI_CACHE_USER_MANAGED == FALSE) + + osalDbgAssert(!((uint32_t) rxbuf & (L1_CACHE_BYTES - 1)), "address not cache aligned"); + + /* + * If size is not multiple of cache line, clean cache region is required. + */ + if (n & (L1_CACHE_BYTES - 1)) { + cacheCleanRegion((uint8_t *) rxbuf, n); + } +#endif /* SAMA_SPI_CACHE_USER_MANAGED */ + /* Writing channel */ + /* Change mode from incremented to fixed address for dummytx */ + dmaChannelSetMode(spip->dmatx, spip->txdmamode & ~XDMAC_CC_SAM_INCREMENTED_AM); + dmaChannelSetSource(spip->dmatx, &dummytx); dmaChannelSetDestination(spip->dmatx, &spip->spi->SPI_TDR); dmaChannelSetTransactionSize(spip->dmatx, n); /* Reading channel */ + /* Change mode to incremented address */ + dmaChannelSetMode(spip->dmarx, spip->rxdmamode | XDMAC_CC_DAM_INCREMENTED_AM); + dmaChannelSetSource(spip->dmarx, &spip->spi->SPI_RDR); dmaChannelSetDestination(spip->dmarx, rxbuf); dmaChannelSetTransactionSize(spip->dmarx, n); @@ -773,6 +939,29 @@ void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf) { dmaChannelEnable(spip->dmatx); } +/** + * @brief Exchanges one frame using a polled wait. + * @details This synchronous function exchanges one frame using a polled + * synchronization method. This function is useful when exchanging + * small amount of data on high speed channels, usually in this + * situation is much more efficient just wait for completion using + * polling than suspending the thread waiting for an interrupt. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] frame the data frame to send over the SPI bus + * @return The received data frame from the SPI bus. + */ +uint16_t spi_lld_polled_exchange(SPIDriver *spip, uint16_t frame) { + + while((spip->spi->SPI_SR & SPI_SR_TXEMPTY) == 1); + + spip->spi->SPI_TDR = (uint8_t) frame; + + while((spip->spi->SPI_SR & SPI_SR_RDRF) == 0); + + return (uint16_t) spip->spi->SPI_RDR; +} + #endif /* HAL_USE_SPI */ /** @} */ diff --git a/os/hal/ports/SAMA/LLD/SPIv1/hal_spi_lld.h b/os/hal/ports/SAMA/LLD/SPIv1/hal_spi_lld.h index f9be8bdee..df448eaec 100644 --- a/os/hal/ports/SAMA/LLD/SPIv1/hal_spi_lld.h +++ b/os/hal/ports/SAMA/LLD/SPIv1/hal_spi_lld.h @@ -25,7 +25,7 @@ #ifndef HAL_SPI_LLD_H
#define HAL_SPI_LLD_H
-#if HAL_USE_SPI || defined(__DOXYGEN__)
+#if (HAL_USE_SPI == TRUE) || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
@@ -53,15 +53,58 @@ #endif
/**
+ * @brief SPI0 Generic clock enable.
+ * @details If set to @p TRUE the support for GCLK SPI0 is included.
+ */
+#if !defined(SAMA_SPI0_USE_GCLK) || defined(__DOXYGEN__)
+#define SAMA_SPI0_USE_GCLK FALSE
+#endif
+
+/**
+ * @brief SPI0 Generic clock source.
+ */
+#if !defined(SAMA_SPI0_GCLK_SOURCE) || defined(__DOXYGEN__)
+#define SAMA_SPI0_GCLK_SOURCE SAMA_GCLK_MCK_CLK
+#endif
+
+/**
+ * @brief SPI0 Generic clock div.
+ */
+#if !defined(SAMA_SPI0_GCLK_DIV) || defined(__DOXYGEN__)
+#define SAMA_SPI0_GCLK_DIV 21
+#endif
+
+/**
* @brief SPI1 driver enable switch.
* @details If set to @p TRUE the support for SPI1 is included.
- * @note The default is @p FALSE.
*/
#if !defined(SAMA_SPI_USE_SPI1) || defined(__DOXYGEN__)
#define SAMA_SPI_USE_SPI1 FALSE
#endif
/**
+ * @brief SPI1 Generic clock enable.
+ * @details If set to @p TRUE the support for GCLK SPI1 is included.
+ */
+#if !defined(SAMA_SPI1_USE_GCLK) || defined(__DOXYGEN__)
+#define SAMA_SPI1_USE_GCLK FALSE
+#endif
+
+/**
+ * @brief SPI1 Generic clock source.
+ */
+#if !defined(SAMA_SPI1_GCLK_SOURCE) || defined(__DOXYGEN__)
+#define SAMA_SPI1_GCLK_SOURCE SAMA_GCLK_MCK_CLK
+#endif
+
+/**
+ * @brief SPI1 Generic clock div.
+ */
+#if !defined(SAMA_SPI1_GCLK_DIV) || defined(__DOXYGEN__)
+#define SAMA_SPI1_GCLK_DIV 21
+#endif
+
+/**
* @brief SPI FLEXCOM0 driver enable switch.
* @details If set to @p TRUE the support for FLEXCOM0 is included.
*/
@@ -70,6 +113,28 @@ #endif
/**
+ * @brief FSPI0 Generic clock enable.
+ * @details If set to @p TRUE the support for GCLK FSPI0 is included.
+ */
+#if !defined(SAMA_FSPI0_USE_GCLK) || defined(__DOXYGEN__)
+#define SAMA_FSPI0_USE_GCLK FALSE
+#endif
+
+/**
+ * @brief FSPI0 Generic clock source.
+ */
+#if !defined(SAMA_FSPI0_GCLK_SOURCE) || defined(__DOXYGEN__)
+#define SAMA_FSPI0_GCLK_SOURCE SAMA_GCLK_MCK_CLK
+#endif
+
+/**
+ * @brief FSPI0 Generic clock div.
+ */
+#if !defined(SAMA_FSPI0_GCLK_DIV) || defined(__DOXYGEN__)
+#define SAMA_FSPI0_GCLK_DIV 21
+#endif
+
+/**
* @brief SPI FLEXCOM1 driver enable switch.
* @details If set to @p TRUE the support for FLEXCOM1 is included.
*/
@@ -78,6 +143,28 @@ #endif
/**
+ * @brief FSPI1 Generic clock enable.
+ * @details If set to @p TRUE the support for GCLK FSPI1 is included.
+ */
+#if !defined(SAMA_FSPI1_USE_GCLK) || defined(__DOXYGEN__)
+#define SAMA_FSPI1_USE_GCLK FALSE
+#endif
+
+/**
+ * @brief FSPI1 Generic clock source.
+ */
+#if !defined(SAMA_FSPI1_GCLK_SOURCE) || defined(__DOXYGEN__)
+#define SAMA_FSPI1_GCLK_SOURCE SAMA_GCLK_MCK_CLK
+#endif
+
+/**
+ * @brief FSPI1 Generic clock div.
+ */
+#if !defined(SAMA_FSPI1_GCLK_DIV) || defined(__DOXYGEN__)
+#define SAMA_FSPI1_GCLK_DIV 21
+#endif
+
+/**
* @brief SPI FLEXCOM2 driver enable switch.
* @details If set to @p TRUE the support for FLEXCOM2 is included.
*/
@@ -86,6 +173,28 @@ #endif
/**
+ * @brief FSPI2 Generic clock enable.
+ * @details If set to @p TRUE the support for GCLK FSPI2 is included.
+ */
+#if !defined(SAMA_FSPI2_USE_GCLK) || defined(__DOXYGEN__)
+#define SAMA_FSPI2_USE_GCLK FALSE
+#endif
+
+/**
+ * @brief FSPI2 Generic clock source.
+ */
+#if !defined(SAMA_FSPI2_GCLK_SOURCE) || defined(__DOXYGEN__)
+#define SAMA_FSPI2_GCLK_SOURCE SAMA_GCLK_MCK_CLK
+#endif
+
+/**
+ * @brief FSPI2 Generic clock div.
+ */
+#if !defined(SAMA_FSPI2_GCLK_DIV) || defined(__DOXYGEN__)
+#define SAMA_FSPI2_GCLK_DIV 21
+#endif
+
+/**
* @brief SPI FLEXCOM3 driver enable switch.
* @details If set to @p TRUE the support for FLEXCOM3 is included.
*/
@@ -94,6 +203,28 @@ #endif
/**
+ * @brief FSPI3 Generic clock enable.
+ * @details If set to @p TRUE the support for GCLK FSPI3 is included.
+ */
+#if !defined(SAMA_FSPI3_USE_GCLK) || defined(__DOXYGEN__)
+#define SAMA_FSPI3_USE_GCLK FALSE
+#endif
+
+/**
+ * @brief FSPI3 Generic clock source.
+ */
+#if !defined(SAMA_FSPI3_GCLK_SOURCE) || defined(__DOXYGEN__)
+#define SAMA_FSPI3_GCLK_SOURCE SAMA_GCLK_MCK_CLK
+#endif
+
+/**
+ * @brief FSPI3 Generic clock div.
+ */
+#if !defined(SAMA_FSPI3_GCLK_DIV) || defined(__DOXYGEN__)
+#define SAMA_FSPI3_GCLK_DIV 21
+#endif
+
+/**
* @brief SPI FLEXCOM4 driver enable switch.
* @details If set to @p TRUE the support for FLEXCOM4 is included.
*/
@@ -102,6 +233,28 @@ #endif
/**
+ * @brief FSPI4 Generic clock enable.
+ * @details If set to @p TRUE the support for GCLK FSPI4 is included.
+ */
+#if !defined(SAMA_FSPI4_USE_GCLK) || defined(__DOXYGEN__)
+#define SAMA_FSPI4_USE_GCLK FALSE
+#endif
+
+/**
+ * @brief FSPI4 Generic clock source.
+ */
+#if !defined(SAMA_FSPI4_GCLK_SOURCE) || defined(__DOXYGEN__)
+#define SAMA_FSPI4_GCLK_SOURCE SAMA_GCLK_MCK_CLK
+#endif
+
+/**
+ * @brief FSPI4 Generic clock div.
+ */
+#if !defined(SAMA_FSPI4_GCLK_DIV) || defined(__DOXYGEN__)
+#define SAMA_FSPI4_GCLK_DIV 21
+#endif
+
+/**
* @brief SPI0 DMA interrupt priority level setting.
*/
#if !defined(SAMA_SPI_SPI0_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__)
@@ -151,6 +304,22 @@ #endif
/** @} */
+/**
+ * @brief SPI DMA error hook.
+ * @note The default action for DMA errors is a system halt because DMA
+ * error can only happen because programming errors.
+ */
+#if !defined(SAMA_SPI_DMA_ERROR_HOOK) || defined(__DOXYGEN__)
+#define SAMA_SPI_DMA_ERROR_HOOK(spip) osalSysHalt("DMA failure")
+#endif
+
+/**
+ * @brief SPI cache managing.
+ */
+#if !defined(SAMA_SPI_CACHE_USER_MANAGED) || defined(__DOXYGEN__)
+#define SAMA_SPI_CACHE_USER_MANAGED FALSE
+#endif
+
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
@@ -230,106 +399,36 @@ /* Driver data structures and types. */
/*===========================================================================*/
-/**
- * @brief Type of a structure representing an SPI driver.
- */
-typedef struct SPIDriver SPIDriver;
+#define spi_lld_driver_fields \
+ /* Pointer to the SPIx registers block.*/ \
+ Spi *spi; \
+ /* Pointer to the FLEXCOMx registers block.*/ \
+ Flexcom *flexcom; \
+ /* Receive DMA stream.*/ \
+ sama_dma_channel_t *dmarx; \
+ /* Transmit DMA stream.*/ \
+ sama_dma_channel_t *dmatx; \
+ /* RX DMA mode bit mask.*/ \
+ uint32_t rxdmamode; \
+ /* TX DMA mode bit mask.*/ \
+ uint32_t txdmamode; \
+ /* Pointer to the TX buffer location.*/ \
+ const uint8_t *txbuf; \
+ /* Pointer to the RX buffer location.*/ \
+ uint8_t *rxbuf; \
+ /* Number of bytes in RX phase.*/ \
+ size_t rxbytes;
/**
- * @brief SPI notification callback type.
- *
- * @param[in] spip pointer to the @p SPIDriver object triggering the
- * callback
- */
-typedef void (*spicallback_t)(SPIDriver *spip);
-
-/**
- * @brief Driver configuration structure.
- */
-typedef struct {
-#if (SPI_SUPPORTS_CIRCULAR == TRUE) || defined(__DOXYGEN__)
- /**
- * @brief Enables the circular buffer mode.
- */
- bool circular;
-#endif
- /**
- * @brief Operation complete callback or @p NULL.
- */
- spicallback_t end_cb;
- /* End of the mandatory fields.*/
- /**
- * @brief The chip select line number.
- */
- uint16_t npcs;
- /**
- * @brief SPI MR register initialization data.
- */
- uint32_t mr;
- /**
- * @brief SPI CSR register initialization data.
- */
+ * @brief Low level fields of the SPI configuration structure.
+ */
+#define spi_lld_config_fields \
+ /* The chip select line number.*/ \
+ uint8_t npcs; \
+ /* SPI MR register initialization data.*/ \
+ uint32_t mr; \
+ /* SPI CSR register initialization data.*/ \
uint32_t csr;
-} SPIConfig;
-
-/**
- * @brief Structure representing an SPI driver.
- * @note Implementations may extend this structure to contain more,
- * architecture dependent, fields.
- */
-struct SPIDriver {
- /**
- * @brief Driver state.
- */
- spistate_t state;
- /**
- * @brief Current configuration data.
- */
- const SPIConfig *config;
-#if SPI_USE_WAIT || defined(__DOXYGEN__)
- /**
- * @brief Waiting thread.
- */
- thread_reference_t thread;
-#endif /* SPI_USE_WAIT */
-#if SPI_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
- /**
- * @brief Mutex protecting the bus.
- */
- mutex_t mutex;
-#endif /* SPI_USE_MUTUAL_EXCLUSION */
-#if defined(SPI_DRIVER_EXT_FIELDS)
- SPI_DRIVER_EXT_FIELDS
-#endif
- /* End of the mandatory fields.*/
- /**
- * @brief Pointer to the SPIx registers block.
- */
- Spi *spi;
-#if SAMA_SPI_USE_FLEXCOM
- /**
- * @brief Pointer to the FLEXCOMx registers block.
- */
- Flexcom *flexcom;
-#endif
- /**
- * @brief Receive DMA stream.
- */
- sama_dma_channel_t *dmarx;
- /**
- * @brief Transmit DMA stream.
- */
- sama_dma_channel_t *dmatx;
- /**
- * @brief RX DMA mode bit mask.
- */
- uint32_t rxdmamode;
- /**
- * @brief TX DMA mode bit mask.
- */
- uint32_t txdmamode;
-};
-
/*===========================================================================*/
/* Driver macros. */
@@ -371,7 +470,7 @@ extern SPIDriver FSPID4; #ifdef __cplusplus
extern "C" {
#endif
-void spi_lld_init(void);
+ void spi_lld_init(void);
void spi_lld_start(SPIDriver *spip);
void spi_lld_stop(SPIDriver *spip);
void spi_lld_select(SPIDriver *spip);
@@ -381,6 +480,7 @@ void spi_lld_init(void); const void *txbuf, void *rxbuf);
void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf);
void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf);
+ uint16_t spi_lld_polled_exchange(SPIDriver *spip, uint16_t frame);
#ifdef __cplusplus
}
|