git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@1256 35acf78f-673a-0410-8e92-d51de3d6d3f4

This commit is contained in:
gdisirio 2009-10-26 16:02:29 +00:00
parent 34f29ab36c
commit a1db002da5
6 changed files with 290 additions and 59 deletions

View File

@ -47,24 +47,116 @@ static uint16_t dummytx;
/* Low Level Driver local functions. */
/*===========================================================================*/
static void spi_stop(SPIDriver *spip, msg_t msg) {
/* Stops RX and TX DMA channels.*/
spip->spd_dmarx->CCR = 0;
spip->spd_dmatx->CCR = 0;
/* Stops SPI operations.*/
spip->spd_spi->CR1 &= ~SPI_CR1_SPE;
chSchReadyI(spip->spd_thread)->p_msg = msg;
}
static void dma_start(SPIDriver *spip, size_t n, void *rxbuf, void *txbuf) {
uint32_t ccr;
/* Common DMA setup.*/
ccr = spip->spd_dmaprio;
if ((spip->spd_config->spc_cr1 & SPI_CR1_DFF) != 0)
ccr |= DMA_CCR1_MSIZE_0 | DMA_CCR1_PSIZE_0; /* 16 bits transfer.*/
/* RX DMA setup.*/
spip->spd_dmarx->CMAR = (uint32_t)rxbuf;
spip->spd_dmarx->CNDTR = (uint32_t)n;
spip->spd_dmarx->CCR |= ccr;
/* TX DMA setup.*/
spip->spd_dmatx->CMAR = (uint32_t)txbuf;
spip->spd_dmatx->CNDTR = (uint32_t)n;
spip->spd_dmatx->CCR |= ccr;
}
static msg_t spi_start_wait(SPIDriver *spip) {
msg_t msg;
chSysLock();
spip->spd_spi->CR1 |= SPI_CR1_SPE; /* SPI enable.*/
spip->spd_thread = currp;
chSchGoSleepS(PRSUSPENDED); /* Wait for completion event.*/
spip->spd_thread = NULL;
msg = currp->p_rdymsg;
chSysUnlock();
return msg;
}
/*===========================================================================*/
/* Low Level Driver interrupt handlers. */
/*===========================================================================*/
#if USE_STM32_SPI1 || defined(__DOXYGEN__)
/**
* @brief SPI1 RX DMA interrupt handler (channel 2).
*/
CH_IRQ_HANDLER(Vector70) {
CH_IRQ_PROLOGUE();
if ((DMA1->ISR & DMA_ISR_TCIF2) != 0)
spi_stop(&SPID1, RDY_OK);
else
spi_stop(&SPID1, RDY_RESET);
DMA1->IFCR |= DMA_IFCR_CGIF2 | DMA_IFCR_CTCIF2 |
DMA_IFCR_CHTIF2 | DMA_IFCR_CTEIF2;
CH_IRQ_EPILOGUE();
}
/**
* @brief SPI1 TX DMA interrupt handler (channel 3).
*/
CH_IRQ_HANDLER(Vector74) {
CH_IRQ_PROLOGUE();
spi_stop(&SPID1, RDY_RESET);
DMA1->IFCR |= DMA_IFCR_CGIF3 | DMA_IFCR_CTCIF3 |
DMA_IFCR_CHTIF3 | DMA_IFCR_CTEIF3;
CH_IRQ_EPILOGUE();
}
#endif
#if USE_STM32_SPI2 || defined(__DOXYGEN__)
/**
* @brief SPI2 RX DMA interrupt handler (channel 4).
*/
CH_IRQ_HANDLER(Vector78) {
CH_IRQ_PROLOGUE();
if ((DMA1->ISR & DMA_ISR_TCIF2) != 0)
spi_stop(&SPID2, RDY_OK);
else
spi_stop(&SPID2, RDY_RESET);
DMA2->IFCR |= DMA_IFCR_CGIF4 | DMA_IFCR_CTCIF4 |
DMA_IFCR_CHTIF4 | DMA_IFCR_CTEIF4;
CH_IRQ_EPILOGUE();
}
/**
* @brief SPI2 TX DMA interrupt handler (channel 5).
*/
CH_IRQ_HANDLER(Vector7C) {
CH_IRQ_PROLOGUE();
spi_stop(&SPID2, RDY_RESET);
DMA2->IFCR |= DMA_IFCR_CGIF5 | DMA_IFCR_CTCIF5 |
DMA_IFCR_CHTIF5 | DMA_IFCR_CTEIF5;
CH_IRQ_EPILOGUE();
}
#endif
@ -78,10 +170,11 @@ CH_IRQ_HANDLER(Vector78) {
*/
void spi_lld_init(void) {
dummyrx = dummytx = 0xFFFF;
dummytx = 0xFFFF;
#if USE_STM32_SPI1
spiObjectInit(&SPID1);
SPID1.spd_thread = NULL;
SPID1.spd_spi = SPI1;
SPID1.spd_dmarx = DMA1_Channel2;
SPID1.spd_dmatx = DMA1_Channel3;
@ -92,6 +185,7 @@ void spi_lld_init(void) {
#if USE_STM32_SPI2
spiObjectInit(&SPID2);
SPID2.spd_thread = NULL;
SPID2.spd_spi = SPI2;
SPID2.spd_dmarx = DMA1_Channel4;
SPID2.spd_dmatx = DMA1_Channel5;
@ -115,6 +209,20 @@ void spi_lld_setup(SPIDriver *spip) {
/* DMA setup.*/
spip->spd_dmarx->CPAR = (uint32_t)&spip->spd_spi->DR;
spip->spd_dmatx->CPAR = (uint32_t)&spip->spd_spi->DR;
/*
* If specified in the configuration then emits a pulses train on
* the SPI clock line without asserting any slave.
*/
if (spip->spd_config->spc_initcnt > 0) {
spip->spd_dmarx->CCR = DMA_CCR1_TCIE |
DMA_CCR1_TEIE | DMA_CCR1_EN;
spip->spd_dmatx->CCR = DMA_CCR1_DIR |
DMA_CCR1_TEIE | DMA_CCR1_EN;
dma_start(spip, (size_t)spip->spd_config->spc_initcnt,
&dummyrx, &dummytx);
(void) spi_start_wait(spip);
}
}
/**
@ -143,48 +251,70 @@ void spi_lld_unselect(SPIDriver *spip) {
* @details This function performs a simultaneous transmit/receive operation.
*
* @param[in] spip pointer to the @p SPIDriver object
* @param n number of words to be exchanged
* @param rxbuf the pointer to the receive buffer, if @p NULL is specified then
* the input data is discarded.
* Note that the buffer is organized as an uint8_t array for
* data sizes below or equal to 8 bits else it is organized as
* an uint16_t array.
* @param txbuf the pointer to the transmit buffer, if @p NULL is specified all
* ones are transmitted.
* Note that the buffer is organized as an uint8_t array for
* data sizes below or equal to 8 bits else it is organized as
* an uint16_t array.
* @param n number of words to exchange
* @param rxbuf the pointer to the receive buffer
* @param txbuf the pointer to the transmit buffer
* @return The operation status is returned.
* @retval RDY_OK operation complete.
* @retval RDY_RESET hardware failure.
*
* @note The buffers are organized as uint8_t arrays for data sizes below or
* equal to 8 bits else it is organized as uint16_t arrays.
*/
void spi_lld_exchange(SPIDriver *spip, size_t n, void *rxbuf, void *txbuf) {
uint32_t baseccr, ccr;
msg_t spi_lld_exchange(SPIDriver *spip, size_t n, void *rxbuf, void *txbuf) {
/* Common DMA setup.*/
baseccr = spip->spd_dmaprio;
if ((spip->spd_config->spc_cr1 & SPI_CR1_DFF) != 0)
baseccr |= DMA_CCR1_MSIZE_0 | DMA_CCR1_PSIZE_0; /* 16 bits transfer.*/
spip->spd_dmarx->CCR = DMA_CCR1_TCIE | DMA_CCR1_MINC |
DMA_CCR1_TEIE | DMA_CCR1_EN;
spip->spd_dmatx->CCR = DMA_CCR1_DIR | DMA_CCR1_MINC |
DMA_CCR1_TEIE | DMA_CCR1_EN;
dma_start(spip, n, rxbuf, txbuf);
return spi_start_wait(spip);
}
/* RX DMA setup.*/
ccr = baseccr | DMA_CCR1_TCIE | DMA_CCR1_TEIE | DMA_CCR1_EN;
if (rxbuf == NULL)
rxbuf = &dummyrx;
else
ccr |= DMA_CCR1_MINC;
spip->spd_dmarx->CMAR = (uint32_t)rxbuf;
spip->spd_dmarx->CNDTR = (uint32_t)n;
spip->spd_dmarx->CCR = ccr;
/**
* @brief Sends data ever the SPI bus.
*
* @param[in] spip pointer to the @p SPIDriver object
* @param n number of words to send
* @param txbuf the pointer to the transmit buffer
* @return The operation status is returned.
* @retval RDY_OK operation complete.
* @retval RDY_RESET hardware failure.
*
* @note The buffers are organized as uint8_t arrays for data sizes below or
* equal to 8 bits else it is organized as uint16_t arrays.
*/
msg_t spi_lld_send(SPIDriver *spip, size_t n, void *txbuf) {
/* TX DMA setup.*/
ccr = baseccr | DMA_CCR1_DIR | DMA_CCR1_TEIE | DMA_CCR1_EN;
if (txbuf == NULL)
txbuf = &dummytx;
else
ccr |= DMA_CCR1_PINC;
spip->spd_dmatx->CMAR = (uint32_t)txbuf;
spip->spd_dmatx->CNDTR = (uint32_t)n;
spip->spd_dmatx->CCR = ccr;
spip->spd_dmarx->CCR = DMA_CCR1_TCIE |
DMA_CCR1_TEIE | DMA_CCR1_EN;
spip->spd_dmatx->CCR = DMA_CCR1_DIR | DMA_CCR1_MINC |
DMA_CCR1_TEIE | DMA_CCR1_EN;
dma_start(spip, n, &dummyrx, txbuf);
return spi_start_wait(spip);
}
/* SPI enable.*/
spip->spd_spi->CR1 != SPI_CR1_SPE;
/**
* @brief Receives data from the SPI bus.
*
* @param[in] spip pointer to the @p SPIDriver object
* @param n number of words to receive
* @param rxbuf the pointer to the receive buffer
* @return The operation status is returned.
* @retval RDY_OK operation complete.
* @retval RDY_RESET hardware failure.
*
* @note The buffers are organized as uint8_t arrays for data sizes below or
* equal to 8 bits else it is organized as uint16_t arrays.
*/
msg_t spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf) {
spip->spd_dmarx->CCR = DMA_CCR1_TCIE | DMA_CCR1_MINC |
DMA_CCR1_TEIE | DMA_CCR1_EN;
spip->spd_dmatx->CCR = DMA_CCR1_DIR |
DMA_CCR1_TEIE | DMA_CCR1_EN;
dma_start(spip, n, rxbuf, &dummytx);
return spi_start_wait(spip);
}
/** @} */

View File

@ -58,7 +58,7 @@
#endif
/**
* @brief SPI1 DMA priority (0..3).
* @brief SPI1 DMA priority (0..3|lowest..highest).
* @note The priority level is used for both the TX and RX DMA channels but
* because of the channels ordering the RX channel has always priority
* over the TX channel.
@ -68,7 +68,7 @@
#endif
/**
* @brief SPI2 DMA priority (0..3).
* @brief SPI2 DMA priority (0..3|lowest..highest).
* @note The priority level is used for both the TX and RX DMA channels but
* because of the channels ordering the RX channel has always priority
* over the TX channel.
@ -97,7 +97,7 @@ typedef struct {
/**
* @brief Clock pulses to be generated after initialization.
*/
cnt_t spc_clkpulses;
cnt_t spc_initcnt;
/* End of the mandatory fields.*/
/**
* @brief The chip select line port.
@ -136,6 +136,10 @@ typedef struct {
*/
const SPIConfig *spd_config;
/* End of the mandatory fields.*/
/**
* @brief Thread waiting for I/O completion.
*/
Thread *spd_thread;
/**
* @brief Pointer to the SPIx registers block.
*/
@ -174,7 +178,9 @@ extern "C" {
void spi_lld_setup(SPIDriver *spip);
void spi_lld_select(SPIDriver *spip);
void spi_lld_unselect(SPIDriver *spip);
void spi_lld_exchange(SPIDriver *spip, size_t n, void *rxbuf, void *txbuf);
msg_t spi_lld_exchange(SPIDriver *spip, size_t n, void *rxbuf, void *txbuf);
msg_t spi_lld_send(SPIDriver *spip, size_t n, void *txbuf);
msg_t spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf);
#ifdef __cplusplus
}
#endif

View File

@ -59,6 +59,7 @@ void spiObjectInit(SPIDriver *spip) {
*/
void spiSetup(SPIDriver *spip, const SPIConfig *config) {
chDbgCheck((spip != NULL) && (config != NULL), "spiSetup");
chDbgAssert(spip->spd_state == SPI_IDLE,
"spiSetup(), #1",
"not idle");
@ -74,6 +75,8 @@ void spiSetup(SPIDriver *spip, const SPIConfig *config) {
*/
void spiSelect(SPIDriver *spip) {
chDbgCheck(spip != NULL, "spiSelect");
chSysLock();
chDbgAssert(spip->spd_state == SPI_IDLE,
@ -93,6 +96,8 @@ void spiSelect(SPIDriver *spip) {
*/
void spiUnselect(SPIDriver *spip) {
chDbgCheck(spip != NULL, "spiUnselect");
chSysLock();
chDbgAssert(spip->spd_state == SPI_ACTIVE,
@ -121,13 +126,63 @@ void spiUnselect(SPIDriver *spip) {
* data sizes below or equal to 8 bits else it is organized as
* an uint16_t array.
*/
void spiExchange(SPIDriver *spip, size_t n, void *rxbuf, void *txbuf) {
msg_t spiExchange(SPIDriver *spip, size_t n, void *rxbuf, void *txbuf) {
chDbgCheck((spip != NULL) && (n > 0) && (rxbuf != NULL) && (txbuf != NULL),
"spiExchange");
chDbgAssert(spip->spd_state == SPI_ACTIVE,
"spiExchange(), #1",
"not active");
spi_lld_exchange(spip, n, rxbuf, txbuf);
return spi_lld_exchange(spip, n, rxbuf, txbuf);
}
/**
* @brief Sends data ever the SPI bus.
*
* @param[in] spip pointer to the @p SPIDriver object
* @param n number of words to send
* @param txbuf the pointer to the transmit buffer
* @return The operation status is returned.
* @retval RDY_OK operation complete.
* @retval RDY_RESET hardware failure.
*
* @note The buffers are organized as uint8_t arrays for data sizes below or
* equal to 8 bits else it is organized as uint16_t arrays.
*/
msg_t spiSend(SPIDriver *spip, size_t n, void *txbuf) {
chDbgCheck((spip != NULL) && (n > 0) && (txbuf != NULL),
"spiSend");
chDbgAssert(spip->spd_state == SPI_ACTIVE,
"spiSend(), #1",
"not active");
return spi_lld_send(spip, n, txbuf);
}
/**
* @brief Receives data from the SPI bus.
*
* @param[in] spip pointer to the @p SPIDriver object
* @param n number of words to receive
* @param rxbuf the pointer to the receive buffer
* @return The operation status is returned.
* @retval RDY_OK operation complete.
* @retval RDY_RESET hardware failure.
*
* @note The buffers are organized as uint8_t arrays for data sizes below or
* equal to 8 bits else it is organized as uint16_t arrays.
*/
msg_t spiReceive(SPIDriver *spip, size_t n, void *rxbuf) {
chDbgCheck((spip != NULL) && (n > 0) && (rxbuf != NULL),
"spiReceive");
chDbgAssert(spip->spd_state == SPI_ACTIVE,
"spiReceive(), #1",
"not active");
return spi_lld_receive(spip, n, rxbuf);
}
#if SPI_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
@ -143,6 +198,8 @@ void spiExchange(SPIDriver *spip, size_t n, void *rxbuf, void *txbuf) {
*/
void spiAcquireBus(SPIDriver *spip) {
chDbgCheck(spip != NULL, "spiAcquireBus");
#if CH_USE_MUTEXES
chMtxLock(&spip->spd_mutex);
#elif CH_USE_SEMAPHORES
@ -160,6 +217,8 @@ void spiAcquireBus(SPIDriver *spip) {
*/
void spiReleaseBus(SPIDriver *spip) {
chDbgCheck(spip != NULL, "spiReleaseBus");
#if CH_USE_MUTEXES
(void)spip;
chMtxUnlock();

View File

@ -48,7 +48,9 @@ extern "C" {
void spiSetup(SPIDriver *spip, const SPIConfig *config);
void spiSelect(SPIDriver *spip);
void spiUnselect(SPIDriver *spip);
void spiExchange(SPIDriver *spip, size_t n, void *rxbuf, void *txbuf);
msg_t spiExchange(SPIDriver *spip, size_t n, void *rxbuf, void *txbuf);
msg_t spiSend(SPIDriver *spip, size_t n, void *txbuf);
msg_t spiReceive(SPIDriver *spip, size_t n, void *rxbuf);
#if SPI_USE_MUTUAL_EXCLUSION
void spiAcquireBus(SPIDriver *spip);
void spiReleaseBus(SPIDriver *spip);

View File

@ -79,19 +79,51 @@ void spi_lld_unselect(SPIDriver *spip) {
* @details This function performs a simultaneous transmit/receive operation.
*
* @param[in] spip pointer to the @p SPIDriver object
* @param n number of words to be exchanged
* @param rxbuf the pointer to the receive buffer, if @p NULL is specified then
* the input data is discarded.
* Note that the buffer is organized as an uint8_t array for
* data sizes below or equal to 8 bits else it is organized as
* an uint16_t array.
* @param txbuf the pointer to the transmit buffer, if @p NULL is specified all
* ones are transmitted.
* Note that the buffer is organized as an uint8_t array for
* data sizes below or equal to 8 bits else it is organized as
* an uint16_t array.
* @param n number of words to exchange
* @param rxbuf the pointer to the receive buffer
* @param txbuf the pointer to the transmit buffer
* @return The operation status is returned.
* @retval RDY_OK operation complete.
* @retval RDY_RESET hardware failure.
*
* @note The buffers are organized as uint8_t arrays for data sizes below or
* equal to 8 bits else it is organized as uint16_t arrays.
*/
void spi_lld_exchange(SPIDriver *spip, size_t n, void *rxbuf, void *txbuf) {
msg_t spi_lld_exchange(SPIDriver *spip, size_t n, void *rxbuf, void *txbuf) {
}
/**
* @brief Sends data ever the SPI bus.
*
* @param[in] spip pointer to the @p SPIDriver object
* @param n number of words to send
* @param txbuf the pointer to the transmit buffer
* @return The operation status is returned.
* @retval RDY_OK operation complete.
* @retval RDY_RESET hardware failure.
*
* @note The buffers are organized as uint8_t arrays for data sizes below or
* equal to 8 bits else it is organized as uint16_t arrays.
*/
msg_t spi_lld_send(SPIDriver *spip, size_t n, void *txbuf) {
}
/**
* @brief Receives data from the SPI bus.
*
* @param[in] spip pointer to the @p SPIDriver object
* @param n number of words to receive
* @param rxbuf the pointer to the receive buffer
* @return The operation status is returned.
* @retval RDY_OK operation complete.
* @retval RDY_RESET hardware failure.
*
* @note The buffers are organized as uint8_t arrays for data sizes below or
* equal to 8 bits else it is organized as uint16_t arrays.
*/
msg_t spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf) {
}

View File

@ -62,7 +62,7 @@ typedef struct {
/**
* @brief Clock pulses to be generated after initialization.
*/
cnt_t spc_clkpulses;
cnt_t spc_initcnt;
/* End of the mandatory fields.*/
} SPIConfig;
@ -102,7 +102,9 @@ extern "C" {
void spi_lld_setup(SPIDriver *spip);
void spi_lld_select(SPIDriver *spip);
void spi_lld_unselect(SPIDriver *spip);
void spi_lld_exchange(SPIDriver *spip, size_t n, void *rxbuf, void *txbuf);
msg_t spi_lld_exchange(SPIDriver *spip, size_t n, void *rxbuf, void *txbuf);
msg_t spi_lld_send(SPIDriver *spip, size_t n, void *txbuf);
msg_t spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf);
#ifdef __cplusplus
}
#endif