From e9edd478029209ba06f09a380590e4ae3e844985 Mon Sep 17 00:00:00 2001 From: gdisirio Date: Tue, 28 May 2013 14:12:55 +0000 Subject: [PATCH] SPC5xx DSPI driver working on SPC563Mxx. git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@5766 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/hal/platforms/SPC5xx/DSPI_v1/spi_lld.c | 185 ++++++++++++++++++-- os/hal/platforms/SPC5xx/EDMA_v1/spc5_edma.c | 2 +- os/hal/src/spi.c | 1 - testhal/SPC563Mxx/SPI/main.c | 41 +++-- 4 files changed, 196 insertions(+), 33 deletions(-) diff --git a/os/hal/platforms/SPC5xx/DSPI_v1/spi_lld.c b/os/hal/platforms/SPC5xx/DSPI_v1/spi_lld.c index f16e6cf0a..c705d9de5 100644 --- a/os/hal/platforms/SPC5xx/DSPI_v1/spi_lld.c +++ b/os/hal/platforms/SPC5xx/DSPI_v1/spi_lld.c @@ -102,7 +102,7 @@ SPIDriver SPID4; */ static const edma_channel_config_t spi_dspi0_tx1_dma_config = { SPC5_DSPI0_TX1_DMA_DEV_ID, SPC5_SPI_DSPI0_DMA_PRIO, SPC5_SPI_DSPI0_DMA_IRQ_PRIO, - NULL, spi_serve_dma_error_irq, &SPID1 + spi_serve_tx_irq, spi_serve_dma_error_irq, &SPID1 }; /** @@ -128,7 +128,7 @@ static const edma_channel_config_t spi_dspi0_rx_dma_config = { */ static const edma_channel_config_t spi_dspi1_tx1_dma_config = { SPC5_DSPI1_TX1_DMA_DEV_ID, SPC5_SPI_DSPI1_DMA_PRIO, SPC5_SPI_DSPI1_DMA_IRQ_PRIO, - NULL, spi_serve_dma_error_irq, &SPID2 + spi_serve_tx_irq, spi_serve_dma_error_irq, &SPID2 }; /** @@ -154,7 +154,7 @@ static const edma_channel_config_t spi_dspi1_rx_dma_config = { */ static const edma_channel_config_t spi_dspi2_tx1_dma_config = { SPC5_DSPI2_TX1_DMA_DEV_ID, SPC5_SPI_DSPI2_DMA_PRIO, SPC5_SPI_DSPI2_DMA_IRQ_PRIO, - NULL, spi_serve_dma_error_irq, &SPID3 + spi_serve_tx_irq, spi_serve_dma_error_irq, &SPID3 }; /** @@ -180,7 +180,7 @@ static const edma_channel_config_t spi_dspi2_rx_dma_config = { */ static const edma_channel_config_t spi_dspi3_tx1_dma_config = { SPC5_DSPI3_TX1_DMA_DEV_ID, SPC5_SPI_DSPI3_DMA_PRIO, SPC5_SPI_DSPI3_DMA_IRQ_PRIO, - NULL, spi_serve_dma_error_irq, &SPID4 + spi_serve_tx_irq, spi_serve_dma_error_irq, &SPID4 }; /** @@ -204,6 +204,33 @@ static const edma_channel_config_t spi_dspi3_rx_dma_config = { /* Driver local functions. */ /*===========================================================================*/ +/** + * @brief Starts reception using DMA ignoring the received data. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] n number of words to be exchanged + * + * @notapi + */ +static void spi_start_dma_rx_ignore(SPIDriver *spip, size_t n) { + static uint32_t datasink; + + edmaChannelSetup(spip->rx_channel, /* channel. */ + DSPI_POPR8_ADDRESS(spip), /* src. */ + &datasink, /* dst. */ + 0, /* soff, do not advance. */ + 0, /* doff, do not advance. */ + 0, /* ssize, 16 bits transfers.*/ + 0, /* dsize, 16 bits transfers.*/ + 1, /* nbytes, always one. */ + n, /* iter. */ + 0, /* slast. */ + 0, /* dlast. */ + EDMA_TCD_MODE_DREQ | EDMA_TCD_MODE_INT_END); /* mode.*/ + + edmaChannelStart(spip->rx_channel); +} + /** * @brief Starts reception using DMA for frames up to 8 bits. * @@ -262,6 +289,42 @@ static void spi_start_dma_rx16(SPIDriver *spip, edmaChannelStart(spip->rx_channel); } +/** + * @brief Starts transmission using DMA for frames up to 8 bits. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] n number of words to be exchanged + * + * @notapi + */ +static void spi_start_dma_tx_ignore(SPIDriver *spip, size_t n) { + + /* Preparing the TX intermediate buffer with the fixed part.*/ + spip->tx_intbuf = spip->config->pushr | (uint32_t)0xFFFF; + + /* The first frame is pushed by the CPU, then the DMA is activated to + send the following frames. This should reduce latency on the operation + start.*/ + spip->dspi->PUSHR.R = spip->tx_last = spip->tx_intbuf; + + /* Setting up TX1 DMA TCD parameters for 32 bits transfers.*/ + edmaChannelSetup(spip->tx1_channel, /* channel. */ + &spip->tx_intbuf, /* src. */ + &spip->dspi->PUSHR.R, /* dst. */ + 0, /* soff, do not advance. */ + 0, /* doff, do not advance. */ + 2, /* ssize, 32 bits transfers.*/ + 2, /* dsize, 32 bits transfers.*/ + 4, /* nbytes, always four. */ + n - 2, /* iter. */ + 0, /* slast, no source adjust. */ + 0, /* dlast, no dest.adjust. */ + EDMA_TCD_MODE_DREQ | EDMA_TCD_MODE_INT_END); /* mode. */ + + /* Starting TX1 DMA channel.*/ + edmaChannelStart(spip->tx1_channel); +} + /** * @brief Starts transmission using DMA for frames up to 8 bits. * @@ -382,6 +445,27 @@ static void spi_start_dma_tx16(SPIDriver *spip, edmaChannelStart(spip->tx1_channel); } +/** + * @brief Starts idle bits using FIFO pre-filling. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] n number of words to be exchanged + * + * @notapi + */ +static void spi_tx_prefill_ignore(SPIDriver *spip, size_t n) { + uint32_t cmd = spip->config->pushr; + + do { + if (--n == 0) { + spip->dspi->PUSHR.R = (SPC5_PUSHR_EOQ | cmd | (uint32_t)0xFFFF) & + ~SPC5_PUSHR_CONT; + break; + } + spip->dspi->PUSHR.R = cmd | (uint32_t)0xFFFF; + } while (TRUE); +} + /** * @brief Starts transmission using FIFO pre-filling for frames up to 8 bits. * @@ -442,7 +526,8 @@ static void spi_tx_prefill16(SPIDriver *spip, static void spi_serve_rx_irq(edma_channel_t channel, void *p) { SPIDriver *spip = (SPIDriver *)p; - (void)channel; + /* Clearing RX channel state.*/ + edmaChannelStop(channel); /* Stops the DSPI and clears the queues.*/ spip->dspi->MCR.R = DSPI_MCR_ENFORCED_BITS | SPC5_MCR_HALT | @@ -455,7 +540,7 @@ static void spi_serve_rx_irq(edma_channel_t channel, void *p) { } /** - * @brief Shared TX2 DMA events service routine. + * @brief Shared TX1/TX2 DMA events service routine. * * @param[in] channel the channel number * @param[in] p parameter for the registered function @@ -467,6 +552,10 @@ static void spi_serve_tx_irq(edma_channel_t channel, void *p) { (void)channel; + /* Clearing TX channels state.*/ + edmaChannelStop(spip->tx1_channel); + edmaChannelStop(spip->tx2_channel); + /* If the TX FIFO is full then the push of the last frame is delagated to an interrupt handler else it is performed immediately. Both conditions can be true depending on the SPI speed and ISR latency.*/ @@ -836,9 +925,22 @@ void spi_lld_unselect(SPIDriver *spip) { */ void spi_lld_ignore(SPIDriver *spip, size_t n) { - (void)spip; - (void)n; + /* Starting transfer.*/ + spip->dspi->SR.R = spip->dspi->SR.R; + spip->dspi->MCR.R = DSPI_MCR_ENFORCED_BITS | spip->config->mcr; + /* Setting up the RX DMA channel.*/ + spi_start_dma_rx_ignore(spip, n); + + if (n <= SPC5_DSPI_FIFO_DEPTH) { + /* If the total transfer size is smaller than the TX FIFO size then + the whole transmitted data is pushed here and the TX DMA is not + activated.*/ + spi_tx_prefill_ignore(spip, n); + } + else { + spi_start_dma_tx_ignore(spip, n); + } } /** @@ -909,10 +1011,36 @@ void spi_lld_exchange(SPIDriver *spip, size_t n, */ void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf) { - (void)spip; - (void)n; - (void)txbuf; + /* Starting transfer.*/ + spip->dspi->SR.R = spip->dspi->SR.R; + spip->dspi->MCR.R = DSPI_MCR_ENFORCED_BITS | spip->config->mcr; + /* Setting up the RX DMA channel.*/ + spi_start_dma_rx_ignore(spip, n); + + /* DMAs require a different setup depending on the frame size.*/ + if (spip->dspi->CTAR[0].B.FMSZ < 8) { + if (n <= SPC5_DSPI_FIFO_DEPTH) { + /* If the total transfer size is smaller than the TX FIFO size then + the whole transmitted data is pushed here and the TX DMA is not + activated.*/ + spi_tx_prefill8(spip, n, txbuf); + } + else { + spi_start_dma_tx8(spip, n, txbuf); + } + } + else { + if (n <= SPC5_DSPI_FIFO_DEPTH) { + /* If the total transfer size is smaller than the TX FIFO size then + the whole transmitted data is pushed here and the TX DMA is not + activated.*/ + spi_tx_prefill16(spip, n, txbuf); + } + else { + spi_start_dma_tx16(spip, n, txbuf); + } + } } /** @@ -930,10 +1058,29 @@ void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf) { */ void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf) { - (void)spip; - (void)n; - (void)rxbuf; + /* Starting transfer.*/ + spip->dspi->SR.R = spip->dspi->SR.R; + spip->dspi->MCR.R = DSPI_MCR_ENFORCED_BITS | spip->config->mcr; + /* DMAs require a different setup depending on the frame size.*/ + if (spip->dspi->CTAR[0].B.FMSZ < 8) { + /* Setting up the RX DMA channel.*/ + spi_start_dma_rx8(spip, n, rxbuf); + } + else { + /* Setting up the RX DMA channel.*/ + spi_start_dma_rx16(spip, n, rxbuf); + } + + if (n <= SPC5_DSPI_FIFO_DEPTH) { + /* If the total transfer size is smaller than the TX FIFO size then + the whole transmitted data is pushed here and the TX DMA is not + activated.*/ + spi_tx_prefill_ignore(spip, n); + } + else { + spi_start_dma_tx_ignore(spip, n); + } } /** @@ -950,10 +1097,12 @@ void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf) { */ uint16_t spi_lld_polled_exchange(SPIDriver *spip, uint16_t frame) { - (void)spip; - (void)frame; - - return 0; + spip->dspi->MCR.R = DSPI_MCR_ENFORCED_BITS | spip->config->mcr; + spip->dspi->PUSHR.R = (SPC5_PUSHR_EOQ | spip->config->pushr | + (uint32_t)frame) & ~SPC5_PUSHR_CONT; + while (!spip->dspi->SR.B.RFDF) + ; + return (uint16_t)spip->dspi->POPR.R; } #endif /* HAL_USE_SPI */ diff --git a/os/hal/platforms/SPC5xx/EDMA_v1/spc5_edma.c b/os/hal/platforms/SPC5xx/EDMA_v1/spc5_edma.c index 4504afd68..a0538ca78 100644 --- a/os/hal/platforms/SPC5xx/EDMA_v1/spc5_edma.c +++ b/os/hal/platforms/SPC5xx/EDMA_v1/spc5_edma.c @@ -1345,7 +1345,7 @@ edma_channel_t edmaChannelAllocate(const edma_channel_config_t *ccfg) { */ void edmaChannelRelease(edma_channel_t channel) { - chDbgCheck((channel < 0) && (channel >= SPC5_EDMA_NCHANNELS), + chDbgCheck((channel >= 0) && (channel < SPC5_EDMA_NCHANNELS), "edmaChannelAllocate"); chDbgAssert(channels[channel] != NULL, "edmaChannelRelease(), #1", diff --git a/os/hal/src/spi.c b/os/hal/src/spi.c index b4eccb0af..2dc0cc6ee 100644 --- a/os/hal/src/spi.c +++ b/os/hal/src/spi.c @@ -126,7 +126,6 @@ void spiStop(SPIDriver *spip) { chSysLock(); chDbgAssert((spip->state == SPI_STOP) || (spip->state == SPI_READY), "spiStop(), #1", "invalid state"); - spi_lld_unselect(spip); spi_lld_stop(spip); spip->state = SPI_STOP; chSysUnlock(); diff --git a/testhal/SPC563Mxx/SPI/main.c b/testhal/SPC563Mxx/SPI/main.c index b0cbe773b..df186e7e7 100644 --- a/testhal/SPC563Mxx/SPI/main.c +++ b/testhal/SPC563Mxx/SPI/main.c @@ -18,15 +18,15 @@ #include "hal.h" /* - * Maximum speed SPI configuration (21MHz, CPHA=0, CPOL=0, MSb first). + * Maximum speed SPI configuration. */ static const SPIConfig hs_spicfg = { NULL, 0, 0, SPC5_MCR_PCSIS0, /* MCR. */ - SPC5_CTAR_CSSCK_DIV64 | SPC5_CTAR_ASC_DIV64 | SPC5_CTAR_FMSZ(8) | - SPC5_CTAR_PBR_PRE2 | SPC5_CTAR_BR_DIV128, /* CTAR0. */ + SPC5_CTAR_CSSCK_DIV2 | SPC5_CTAR_ASC_DIV2 | SPC5_CTAR_FMSZ(8) | + SPC5_CTAR_PBR_PRE2 | SPC5_CTAR_BR_DIV2, /* CTAR0. */ SPC5_PUSHR_CONT | SPC5_PUSHR_PCS(0) /* PUSHR. */ }; @@ -37,8 +37,9 @@ static const SPIConfig ls_spicfg = { NULL, 0, 0, - 0, /* MCR. */ - SPC5_CTAR_FMSZ(8) | SPC5_CTAR_PBR_PRE2 | SPC5_CTAR_BR_DIV256, /* CTAR0. */ + SPC5_MCR_PCSIS0, /* MCR. */ + SPC5_CTAR_CSSCK_DIV64 | SPC5_CTAR_ASC_DIV64 | SPC5_CTAR_FMSZ(8) | + SPC5_CTAR_PBR_PRE2 | SPC5_CTAR_BR_DIV256, /* CTAR0. */ SPC5_PUSHR_CONT | SPC5_PUSHR_PCS(0) /* PUSHR. */ }; @@ -58,7 +59,7 @@ static msg_t spi_thread_1(void *p) { chRegSetThreadName("SPI thread 1"); while (TRUE) { spiAcquireBus(&SPID2); /* Acquire ownership of the bus. */ - palSetPad(PORT11, P11_LED1); /* LED ON. */ + palClearPad(PORT11, P11_LED1); /* LED ON. */ spiStart(&SPID2, &hs_spicfg); /* Setup transfer parameters. */ spiSelect(&SPID2); /* Slave Select assertion. */ spiExchange(&SPID2, 512, @@ -79,7 +80,7 @@ static msg_t spi_thread_2(void *p) { chRegSetThreadName("SPI thread 2"); while (TRUE) { spiAcquireBus(&SPID2); /* Acquire ownership of the bus. */ - palClearPad(PORT11, P11_LED1); /* LED OFF. */ + palSetPad(PORT11, P11_LED1); /* LED OFF. */ spiStart(&SPID2, &ls_spicfg); /* Setup transfer parameters. */ spiSelect(&SPID2); /* Slave Select assertion. */ spiExchange(&SPID2, 512, @@ -116,19 +117,33 @@ int main(void) { for (i = 0; i < sizeof(txbuf); i++) txbuf[i] = (uint8_t)i; - spiStart(&SPID2, &hs_spicfg); + /* Starting driver for test.*/ + spiStart(&SPID2, &ls_spicfg); SIU.PCR[102].R = PAL_MODE_OUTPUT_ALTERNATE(1); /* SCK */ SIU.PCR[103].R = PAL_MODE_OUTPUT_ALTERNATE(1); /* SIN */ SIU.PCR[104].R = PAL_MODE_OUTPUT_ALTERNATE(1); /* SOUT */ SIU.PCR[105].R = PAL_MODE_OUTPUT_ALTERNATE(1); /* PCS[0] */ - spiExchange(&SPID2, 4, txbuf, rxbuf); - spiExchange(&SPID2, 4, txbuf, rxbuf); - spiExchange(&SPID2, 4, txbuf, rxbuf); + /* Testing sending and receiving at the same time.*/ spiExchange(&SPID2, 4, txbuf, rxbuf); spiExchange(&SPID2, 32, txbuf, rxbuf); spiExchange(&SPID2, 512, txbuf, rxbuf); -#if 0 + + /* Testing clock pulses without data buffering.*/ + spiIgnore(&SPID2, 4); + spiIgnore(&SPID2, 32); + + /* Testing sending data ignoring incoming data.*/ + spiSend(&SPID2, 4, txbuf); + spiSend(&SPID2, 32, txbuf); + + /* Testing receiving data while sending idle bits (high level).*/ + spiReceive(&SPID2, 4, rxbuf); + spiReceive(&SPID2, 32, rxbuf); + + /* Testing stop procedure.*/ + spiStop(&SPID2); + /* * Starting the transmitter and receiver threads. */ @@ -136,7 +151,7 @@ int main(void) { NORMALPRIO + 1, spi_thread_1, NULL); chThdCreateStatic(spi_thread_2_wa, sizeof(spi_thread_2_wa), NORMALPRIO + 1, spi_thread_2, NULL); -#endif + /* * Normal main() thread activity, in this demo it does nothing. */