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. */ /* 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. */ /* Low Level Driver interrupt handlers. */
/*===========================================================================*/ /*===========================================================================*/
#if USE_STM32_SPI1 || defined(__DOXYGEN__) #if USE_STM32_SPI1 || defined(__DOXYGEN__)
/**
* @brief SPI1 RX DMA interrupt handler (channel 2).
*/
CH_IRQ_HANDLER(Vector70) { CH_IRQ_HANDLER(Vector70) {
CH_IRQ_PROLOGUE(); 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(); CH_IRQ_EPILOGUE();
} }
#endif #endif
#if USE_STM32_SPI2 || defined(__DOXYGEN__) #if USE_STM32_SPI2 || defined(__DOXYGEN__)
/**
* @brief SPI2 RX DMA interrupt handler (channel 4).
*/
CH_IRQ_HANDLER(Vector78) { CH_IRQ_HANDLER(Vector78) {
CH_IRQ_PROLOGUE(); 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(); CH_IRQ_EPILOGUE();
} }
#endif #endif
@ -78,10 +170,11 @@ CH_IRQ_HANDLER(Vector78) {
*/ */
void spi_lld_init(void) { void spi_lld_init(void) {
dummyrx = dummytx = 0xFFFF; dummytx = 0xFFFF;
#if USE_STM32_SPI1 #if USE_STM32_SPI1
spiObjectInit(&SPID1); spiObjectInit(&SPID1);
SPID1.spd_thread = NULL;
SPID1.spd_spi = SPI1; SPID1.spd_spi = SPI1;
SPID1.spd_dmarx = DMA1_Channel2; SPID1.spd_dmarx = DMA1_Channel2;
SPID1.spd_dmatx = DMA1_Channel3; SPID1.spd_dmatx = DMA1_Channel3;
@ -92,6 +185,7 @@ void spi_lld_init(void) {
#if USE_STM32_SPI2 #if USE_STM32_SPI2
spiObjectInit(&SPID2); spiObjectInit(&SPID2);
SPID2.spd_thread = NULL;
SPID2.spd_spi = SPI2; SPID2.spd_spi = SPI2;
SPID2.spd_dmarx = DMA1_Channel4; SPID2.spd_dmarx = DMA1_Channel4;
SPID2.spd_dmatx = DMA1_Channel5; SPID2.spd_dmatx = DMA1_Channel5;
@ -115,6 +209,20 @@ void spi_lld_setup(SPIDriver *spip) {
/* DMA setup.*/ /* DMA setup.*/
spip->spd_dmarx->CPAR = (uint32_t)&spip->spd_spi->DR; spip->spd_dmarx->CPAR = (uint32_t)&spip->spd_spi->DR;
spip->spd_dmatx->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. * @details This function performs a simultaneous transmit/receive operation.
* *
* @param[in] spip pointer to the @p SPIDriver object * @param[in] spip pointer to the @p SPIDriver object
* @param n number of words to be exchanged * @param n number of words to exchange
* @param rxbuf the pointer to the receive buffer, if @p NULL is specified then * @param rxbuf the pointer to the receive buffer
* the input data is discarded. * @param txbuf the pointer to the transmit buffer
* Note that the buffer is organized as an uint8_t array for * @return The operation status is returned.
* data sizes below or equal to 8 bits else it is organized as * @retval RDY_OK operation complete.
* an uint16_t array. * @retval RDY_RESET hardware failure.
* @param txbuf the pointer to the transmit buffer, if @p NULL is specified all *
* ones are transmitted. * @note The buffers are organized as uint8_t arrays for data sizes below or
* Note that the buffer is organized as an uint8_t array for * equal to 8 bits else it is organized as uint16_t arrays.
* data sizes below or equal to 8 bits else it is organized as
* an uint16_t array.
*/ */
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) {
uint32_t baseccr, ccr;
/* Common DMA setup.*/ spip->spd_dmarx->CCR = DMA_CCR1_TCIE | DMA_CCR1_MINC |
baseccr = spip->spd_dmaprio; DMA_CCR1_TEIE | DMA_CCR1_EN;
if ((spip->spd_config->spc_cr1 & SPI_CR1_DFF) != 0) spip->spd_dmatx->CCR = DMA_CCR1_DIR | DMA_CCR1_MINC |
baseccr |= DMA_CCR1_MSIZE_0 | DMA_CCR1_PSIZE_0; /* 16 bits transfer.*/ 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; * @brief Sends data ever the SPI bus.
if (rxbuf == NULL) *
rxbuf = &dummyrx; * @param[in] spip pointer to the @p SPIDriver object
else * @param n number of words to send
ccr |= DMA_CCR1_MINC; * @param txbuf the pointer to the transmit buffer
spip->spd_dmarx->CMAR = (uint32_t)rxbuf; * @return The operation status is returned.
spip->spd_dmarx->CNDTR = (uint32_t)n; * @retval RDY_OK operation complete.
spip->spd_dmarx->CCR = ccr; * @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.*/ spip->spd_dmarx->CCR = DMA_CCR1_TCIE |
ccr = baseccr | DMA_CCR1_DIR | DMA_CCR1_TEIE | DMA_CCR1_EN; DMA_CCR1_TEIE | DMA_CCR1_EN;
if (txbuf == NULL) spip->spd_dmatx->CCR = DMA_CCR1_DIR | DMA_CCR1_MINC |
txbuf = &dummytx; DMA_CCR1_TEIE | DMA_CCR1_EN;
else dma_start(spip, n, &dummyrx, txbuf);
ccr |= DMA_CCR1_PINC; return spi_start_wait(spip);
spip->spd_dmatx->CMAR = (uint32_t)txbuf; }
spip->spd_dmatx->CNDTR = (uint32_t)n;
spip->spd_dmatx->CCR = ccr;
/* 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 #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 * @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 * because of the channels ordering the RX channel has always priority
* over the TX channel. * over the TX channel.
@ -68,7 +68,7 @@
#endif #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 * @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 * because of the channels ordering the RX channel has always priority
* over the TX channel. * over the TX channel.
@ -97,7 +97,7 @@ typedef struct {
/** /**
* @brief Clock pulses to be generated after initialization. * @brief Clock pulses to be generated after initialization.
*/ */
cnt_t spc_clkpulses; cnt_t spc_initcnt;
/* End of the mandatory fields.*/ /* End of the mandatory fields.*/
/** /**
* @brief The chip select line port. * @brief The chip select line port.
@ -136,6 +136,10 @@ typedef struct {
*/ */
const SPIConfig *spd_config; const SPIConfig *spd_config;
/* End of the mandatory fields.*/ /* End of the mandatory fields.*/
/**
* @brief Thread waiting for I/O completion.
*/
Thread *spd_thread;
/** /**
* @brief Pointer to the SPIx registers block. * @brief Pointer to the SPIx registers block.
*/ */
@ -174,7 +178,9 @@ extern "C" {
void spi_lld_setup(SPIDriver *spip); void spi_lld_setup(SPIDriver *spip);
void spi_lld_select(SPIDriver *spip); void spi_lld_select(SPIDriver *spip);
void spi_lld_unselect(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 #ifdef __cplusplus
} }
#endif #endif

View File

@ -59,6 +59,7 @@ void spiObjectInit(SPIDriver *spip) {
*/ */
void spiSetup(SPIDriver *spip, const SPIConfig *config) { void spiSetup(SPIDriver *spip, const SPIConfig *config) {
chDbgCheck((spip != NULL) && (config != NULL), "spiSetup");
chDbgAssert(spip->spd_state == SPI_IDLE, chDbgAssert(spip->spd_state == SPI_IDLE,
"spiSetup(), #1", "spiSetup(), #1",
"not idle"); "not idle");
@ -74,6 +75,8 @@ void spiSetup(SPIDriver *spip, const SPIConfig *config) {
*/ */
void spiSelect(SPIDriver *spip) { void spiSelect(SPIDriver *spip) {
chDbgCheck(spip != NULL, "spiSelect");
chSysLock(); chSysLock();
chDbgAssert(spip->spd_state == SPI_IDLE, chDbgAssert(spip->spd_state == SPI_IDLE,
@ -93,6 +96,8 @@ void spiSelect(SPIDriver *spip) {
*/ */
void spiUnselect(SPIDriver *spip) { void spiUnselect(SPIDriver *spip) {
chDbgCheck(spip != NULL, "spiUnselect");
chSysLock(); chSysLock();
chDbgAssert(spip->spd_state == SPI_ACTIVE, 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 * data sizes below or equal to 8 bits else it is organized as
* an uint16_t array. * 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, chDbgAssert(spip->spd_state == SPI_ACTIVE,
"spiExchange(), #1", "spiExchange(), #1",
"not active"); "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__) #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) { void spiAcquireBus(SPIDriver *spip) {
chDbgCheck(spip != NULL, "spiAcquireBus");
#if CH_USE_MUTEXES #if CH_USE_MUTEXES
chMtxLock(&spip->spd_mutex); chMtxLock(&spip->spd_mutex);
#elif CH_USE_SEMAPHORES #elif CH_USE_SEMAPHORES
@ -160,6 +217,8 @@ void spiAcquireBus(SPIDriver *spip) {
*/ */
void spiReleaseBus(SPIDriver *spip) { void spiReleaseBus(SPIDriver *spip) {
chDbgCheck(spip != NULL, "spiReleaseBus");
#if CH_USE_MUTEXES #if CH_USE_MUTEXES
(void)spip; (void)spip;
chMtxUnlock(); chMtxUnlock();

View File

@ -48,7 +48,9 @@ extern "C" {
void spiSetup(SPIDriver *spip, const SPIConfig *config); void spiSetup(SPIDriver *spip, const SPIConfig *config);
void spiSelect(SPIDriver *spip); void spiSelect(SPIDriver *spip);
void spiUnselect(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 #if SPI_USE_MUTUAL_EXCLUSION
void spiAcquireBus(SPIDriver *spip); void spiAcquireBus(SPIDriver *spip);
void spiReleaseBus(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. * @details This function performs a simultaneous transmit/receive operation.
* *
* @param[in] spip pointer to the @p SPIDriver object * @param[in] spip pointer to the @p SPIDriver object
* @param n number of words to be exchanged * @param n number of words to exchange
* @param rxbuf the pointer to the receive buffer, if @p NULL is specified then * @param rxbuf the pointer to the receive buffer
* the input data is discarded. * @param txbuf the pointer to the transmit buffer
* Note that the buffer is organized as an uint8_t array for * @return The operation status is returned.
* data sizes below or equal to 8 bits else it is organized as * @retval RDY_OK operation complete.
* an uint16_t array. * @retval RDY_RESET hardware failure.
* @param txbuf the pointer to the transmit buffer, if @p NULL is specified all *
* ones are transmitted. * @note The buffers are organized as uint8_t arrays for data sizes below or
* Note that the buffer is organized as an uint8_t array for * equal to 8 bits else it is organized as uint16_t arrays.
* data sizes below or equal to 8 bits else it is organized as
* an uint16_t array.
*/ */
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. * @brief Clock pulses to be generated after initialization.
*/ */
cnt_t spc_clkpulses; cnt_t spc_initcnt;
/* End of the mandatory fields.*/ /* End of the mandatory fields.*/
} SPIConfig; } SPIConfig;
@ -102,7 +102,9 @@ extern "C" {
void spi_lld_setup(SPIDriver *spip); void spi_lld_setup(SPIDriver *spip);
void spi_lld_select(SPIDriver *spip); void spi_lld_select(SPIDriver *spip);
void spi_lld_unselect(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 #ifdef __cplusplus
} }
#endif #endif