STM32 related improvements, better SPI driver, improved DMA infrastructure.

git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@2122 35acf78f-673a-0410-8e92-d51de3d6d3f4
This commit is contained in:
gdisirio 2010-08-10 14:07:42 +00:00
parent 2d1ded91fe
commit 1c64ee6921
5 changed files with 123 additions and 79 deletions

View File

@ -53,9 +53,6 @@ SPIDriver SPID3;
/* Driver local variables. */ /* Driver local variables. */
/*===========================================================================*/ /*===========================================================================*/
static uint16_t dummyrx;
static uint16_t dummytx;
/*===========================================================================*/ /*===========================================================================*/
/* Driver local functions. */ /* Driver local functions. */
/*===========================================================================*/ /*===========================================================================*/
@ -63,8 +60,8 @@ static uint16_t dummytx;
static void spi_stop(SPIDriver *spip) { static void spi_stop(SPIDriver *spip) {
/* Stops RX and TX DMA channels.*/ /* Stops RX and TX DMA channels.*/
spip->spd_dmarx->CCR = 0; dmaChannelDisable(spip->spd_dmarx);
spip->spd_dmatx->CCR = 0; dmaChannelDisable(spip->spd_dmatx);
/* Stops SPI operations.*/ /* Stops SPI operations.*/
spip->spd_spi->CR1 &= ~SPI_CR1_SPE; spip->spd_spi->CR1 &= ~SPI_CR1_SPE;
@ -74,32 +71,16 @@ static void spi_stop(SPIDriver *spip) {
chSysUnlockFromIsr(); chSysUnlockFromIsr();
} }
static void spi_start_wait(SPIDriver *spip, size_t n, static void spi_start_wait(SPIDriver *spip) {
const void *txbuf, void *rxbuf) {
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;
/* SPI enable.*/
chSysLock(); chSysLock();
spip->spd_spi->CR1 |= SPI_CR1_SPE;
/* DMAs start.*/ /* DMAs start.*/
spip->spd_dmarx->CCR |= DMA_CCR1_EN; dmaChannelEnable(spip->spd_dmarx);
spip->spd_dmatx->CCR |= DMA_CCR1_EN; dmaChannelEnable(spip->spd_dmatx);
/* SPI enable.*/
spip->spd_spi->CR1 |= SPI_CR1_SPE;
/* Wait for completion event.*/ /* Wait for completion event.*/
spip->spd_thread = currp; spip->spd_thread = currp;
@ -121,11 +102,10 @@ CH_IRQ_HANDLER(DMA1_Ch2_IRQHandler) {
CH_IRQ_PROLOGUE(); CH_IRQ_PROLOGUE();
spi_stop(&SPID1); spi_stop(&SPID1);
if ((DMA1->ISR & DMA_ISR_TEIF2) != 0) { if ((STM32_DMA1->ISR & DMA_ISR_TEIF2) != 0) {
STM32_SPI_SPI1_DMA_ERROR_HOOK(); STM32_SPI_SPI1_DMA_ERROR_HOOK();
} }
DMA1->IFCR = DMA_IFCR_CGIF2 | DMA_IFCR_CTCIF2 | dmaClearChannel(STM32_DMA1, STM32_DMA_CHANNEL_2);
DMA_IFCR_CHTIF2 | DMA_IFCR_CTEIF2;
CH_IRQ_EPILOGUE(); CH_IRQ_EPILOGUE();
} }
@ -138,8 +118,7 @@ CH_IRQ_HANDLER(DMA1_Ch3_IRQHandler) {
CH_IRQ_PROLOGUE(); CH_IRQ_PROLOGUE();
STM32_SPI_SPI1_DMA_ERROR_HOOK(); STM32_SPI_SPI1_DMA_ERROR_HOOK();
DMA1->IFCR = DMA_IFCR_CGIF3 | DMA_IFCR_CTCIF3 | dmaClearChannel(STM32_DMA1, STM32_DMA_CHANNEL_3);
DMA_IFCR_CHTIF3 | DMA_IFCR_CTEIF3;
CH_IRQ_EPILOGUE(); CH_IRQ_EPILOGUE();
} }
@ -154,11 +133,10 @@ CH_IRQ_HANDLER(DMA1_Ch4_IRQHandler) {
CH_IRQ_PROLOGUE(); CH_IRQ_PROLOGUE();
spi_stop(&SPID2); spi_stop(&SPID2);
if ((DMA1->ISR & DMA_ISR_TEIF4) != 0) { if ((STM32_DMA1->ISR & DMA_ISR_TEIF4) != 0) {
STM32_SPI_SPI2_DMA_ERROR_HOOK(); STM32_SPI_SPI2_DMA_ERROR_HOOK();
} }
DMA1->IFCR = DMA_IFCR_CGIF4 | DMA_IFCR_CTCIF4 | dmaClearChannel(STM32_DMA1, STM32_DMA_CHANNEL_4);
DMA_IFCR_CHTIF4 | DMA_IFCR_CTEIF4;
CH_IRQ_EPILOGUE(); CH_IRQ_EPILOGUE();
} }
@ -171,8 +149,7 @@ CH_IRQ_HANDLER(DMA1_Ch5_IRQHandler) {
CH_IRQ_PROLOGUE(); CH_IRQ_PROLOGUE();
STM32_SPI_SPI2_DMA_ERROR_HOOK(); STM32_SPI_SPI2_DMA_ERROR_HOOK();
DMA1->IFCR = DMA_IFCR_CGIF5 | DMA_IFCR_CTCIF5 | dmaClearChannel(STM32_DMA1, STM32_DMA_CHANNEL_5);
DMA_IFCR_CHTIF5 | DMA_IFCR_CTEIF5;
CH_IRQ_EPILOGUE(); CH_IRQ_EPILOGUE();
} }
@ -187,11 +164,10 @@ CH_IRQ_HANDLER(DMA2_Ch1_IRQHandler) {
CH_IRQ_PROLOGUE(); CH_IRQ_PROLOGUE();
spi_stop(&SPID3); spi_stop(&SPID3);
if ((DMA2->ISR & DMA_ISR_TEIF1) != 0) { if ((STM32_DMA2->ISR & DMA_ISR_TEIF1) != 0) {
STM32_SPI_SPI3_DMA_ERROR_HOOK(); STM32_SPI_SPI3_DMA_ERROR_HOOK();
} }
DMA2->IFCR = DMA_IFCR_CGIF1 | DMA_IFCR_CTCIF1 | dmaClearChannel(STM32_DMA2, STM32_DMA_CHANNEL_1);
DMA_IFCR_CHTIF1 | DMA_IFCR_CTEIF1;
CH_IRQ_EPILOGUE(); CH_IRQ_EPILOGUE();
} }
@ -204,8 +180,7 @@ CH_IRQ_HANDLER(DMA2_Ch2_IRQHandler) {
CH_IRQ_PROLOGUE(); CH_IRQ_PROLOGUE();
STM32_SPI_SPI3_DMA_ERROR_HOOK(); STM32_SPI_SPI3_DMA_ERROR_HOOK();
DMA2->IFCR = DMA_IFCR_CGIF2 | DMA_IFCR_CTCIF2 | dmaClearChannel(STM32_DMA2, STM32_DMA_CHANNEL_2);
DMA_IFCR_CHTIF2 | DMA_IFCR_CTEIF2;
CH_IRQ_EPILOGUE(); CH_IRQ_EPILOGUE();
} }
@ -220,17 +195,14 @@ CH_IRQ_HANDLER(DMA2_Ch2_IRQHandler) {
*/ */
void spi_lld_init(void) { void spi_lld_init(void) {
dummytx = 0xFFFF;
#if STM32_SPI_USE_SPI1 #if STM32_SPI_USE_SPI1
RCC->APB2RSTR = RCC_APB2RSTR_SPI1RST; RCC->APB2RSTR = RCC_APB2RSTR_SPI1RST;
RCC->APB2RSTR = 0; RCC->APB2RSTR = 0;
spiObjectInit(&SPID1); spiObjectInit(&SPID1);
SPID1.spd_thread = NULL; SPID1.spd_thread = NULL;
SPID1.spd_spi = SPI1; SPID1.spd_spi = SPI1;
SPID1.spd_dmarx = DMA1_Channel2; SPID1.spd_dmarx = STM32_DMA1_CH2;
SPID1.spd_dmatx = DMA1_Channel3; SPID1.spd_dmatx = STM32_DMA1_CH3;
SPID1.spd_dmaprio = STM32_SPI_SPI1_DMA_PRIORITY << 12;
#endif #endif
#if STM32_SPI_USE_SPI2 #if STM32_SPI_USE_SPI2
@ -239,9 +211,8 @@ void spi_lld_init(void) {
spiObjectInit(&SPID2); spiObjectInit(&SPID2);
SPID2.spd_thread = NULL; SPID2.spd_thread = NULL;
SPID2.spd_spi = SPI2; SPID2.spd_spi = SPI2;
SPID2.spd_dmarx = DMA1_Channel4; SPID2.spd_dmarx = STM32_DMA1_CH4;
SPID2.spd_dmatx = DMA1_Channel5; SPID2.spd_dmatx = STM32_DMA1_CH5;
SPID2.spd_dmaprio = STM32_SPI_SPI2_DMA_PRIORITY << 12;
#endif #endif
#if STM32_SPI_USE_SPI3 #if STM32_SPI_USE_SPI3
@ -250,9 +221,8 @@ void spi_lld_init(void) {
spiObjectInit(&SPID3); spiObjectInit(&SPID3);
SPID3.spd_thread = NULL; SPID3.spd_thread = NULL;
SPID3.spd_spi = SPI3; SPID3.spd_spi = SPI3;
SPID3.spd_dmarx = DMA2_Channel1; SPID3.spd_dmarx = STM32_DMA2_CH1;
SPID3.spd_dmatx = DMA2_Channel2; SPID3.spd_dmatx = STM32_DMA2_CH2;
SPID3.spd_dmaprio = STM32_SPI_SPI3_DMA_PRIORITY << 12;
#endif #endif
} }
@ -297,10 +267,19 @@ void spi_lld_start(SPIDriver *spip) {
#endif #endif
/* DMA setup.*/ /* DMA setup.*/
spip->spd_dmarx->CPAR = (uint32_t)&spip->spd_spi->DR; dmaChannelSetPeripheral(spip->spd_dmarx, &spip->spd_spi->DR);
spip->spd_dmatx->CPAR = (uint32_t)&spip->spd_spi->DR; dmaChannelSetPeripheral(spip->spd_dmatx, &spip->spd_spi->DR);
} }
/* More DMA setup.*/
if ((spip->spd_config->spc_cr1 & SPI_CR1_DFF) == 0)
spip->spd_dmaccr = (STM32_SPI_SPI2_DMA_PRIORITY << 12) |
DMA_CCR1_TEIE; /* 8 bits transfers. */
else
spip->spd_dmaccr = (STM32_SPI_SPI2_DMA_PRIORITY << 12) |
DMA_CCR1_TEIE | DMA_CCR1_MSIZE_0 |
DMA_CCR1_PSIZE_0; /* 16 bits transfers. */
/* SPI setup.*/ /* SPI setup.*/
spip->spd_spi->CR1 = spip->spd_config->spc_cr1 | SPI_CR1_MSTR; spip->spd_spi->CR1 = spip->spd_config->spc_cr1 | SPI_CR1_MSTR;
spip->spd_spi->CR2 = SPI_CR2_SSOE | SPI_CR2_RXDMAEN | SPI_CR2_TXDMAEN; spip->spd_spi->CR2 = SPI_CR2_SSOE | SPI_CR2_RXDMAEN | SPI_CR2_TXDMAEN;
@ -373,10 +352,14 @@ void spi_lld_unselect(SPIDriver *spip) {
* @param[in] n number of words to be ignored * @param[in] n number of words to be ignored
*/ */
void spi_lld_ignore(SPIDriver *spip, size_t n) { void spi_lld_ignore(SPIDriver *spip, size_t n) {
uint16_t dummyrx;
uint16_t dummytx = 0xFFFF;
spip->spd_dmarx->CCR = DMA_CCR1_TCIE | DMA_CCR1_TEIE; dmaChannelSetup(spip->spd_dmarx, n, &dummyrx,
spip->spd_dmatx->CCR = DMA_CCR1_DIR | DMA_CCR1_TEIE; spip->spd_dmaccr | DMA_CCR1_TCIE);
spi_start_wait(spip, n, &dummytx, &dummyrx); dmaChannelSetup(spip->spd_dmatx, n, &dummytx,
spip->spd_dmaccr | DMA_CCR1_DIR);
spi_start_wait(spip);
} }
/** /**
@ -393,9 +376,11 @@ void spi_lld_ignore(SPIDriver *spip, size_t n) {
void spi_lld_exchange(SPIDriver *spip, size_t n, void spi_lld_exchange(SPIDriver *spip, size_t n,
const void *txbuf, void *rxbuf) { const void *txbuf, void *rxbuf) {
spip->spd_dmarx->CCR = DMA_CCR1_TCIE | DMA_CCR1_MINC | DMA_CCR1_TEIE; dmaChannelSetup(spip->spd_dmarx, n, rxbuf,
spip->spd_dmatx->CCR = DMA_CCR1_DIR | DMA_CCR1_MINC | DMA_CCR1_TEIE; spip->spd_dmaccr | DMA_CCR1_TCIE | DMA_CCR1_MINC);
spi_start_wait(spip, n, txbuf, rxbuf); dmaChannelSetup(spip->spd_dmatx, n, txbuf,
spip->spd_dmaccr | DMA_CCR1_DIR | DMA_CCR1_MINC);
spi_start_wait(spip);
} }
/** /**
@ -408,10 +393,13 @@ void spi_lld_exchange(SPIDriver *spip, size_t n,
* @param[in] txbuf the pointer to the transmit buffer * @param[in] txbuf the pointer to the transmit buffer
*/ */
void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf) { void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf) {
uint16_t dummyrx;
spip->spd_dmarx->CCR = DMA_CCR1_TCIE | DMA_CCR1_TEIE; dmaChannelSetup(spip->spd_dmarx, n, &dummyrx,
spip->spd_dmatx->CCR = DMA_CCR1_DIR | DMA_CCR1_MINC | DMA_CCR1_TEIE; spip->spd_dmaccr | DMA_CCR1_TCIE);
spi_start_wait(spip, n, txbuf, &dummyrx); dmaChannelSetup(spip->spd_dmatx, n, txbuf,
spip->spd_dmaccr | DMA_CCR1_DIR | DMA_CCR1_MINC);
spi_start_wait(spip);
} }
/** /**
@ -424,10 +412,13 @@ void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf) {
* @param[out] rxbuf the pointer to the receive buffer * @param[out] rxbuf the pointer to the receive buffer
*/ */
void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf) { void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf) {
uint16_t dummytx = 0xFFFF;
spip->spd_dmarx->CCR = DMA_CCR1_TCIE | DMA_CCR1_MINC | DMA_CCR1_TEIE; dmaChannelSetup(spip->spd_dmarx, n, rxbuf,
spip->spd_dmatx->CCR = DMA_CCR1_DIR | DMA_CCR1_TEIE; spip->spd_dmaccr | DMA_CCR1_TCIE | DMA_CCR1_MINC);
spi_start_wait(spip, n, &dummytx, rxbuf); dmaChannelSetup(spip->spd_dmatx, n, &dummytx,
spip->spd_dmaccr | DMA_CCR1_DIR);
spi_start_wait(spip);
} }
#endif /* CH_HAL_USE_SPI */ #endif /* CH_HAL_USE_SPI */

View File

@ -194,11 +194,11 @@ typedef struct {
/** @brief Pointer to the SPIx registers block.*/ /** @brief Pointer to the SPIx registers block.*/
SPI_TypeDef *spd_spi; SPI_TypeDef *spd_spi;
/** @brief Pointer to the receive DMA channel registers block.*/ /** @brief Pointer to the receive DMA channel registers block.*/
DMA_Channel_TypeDef *spd_dmarx; stm32_dma_channel_t *spd_dmarx;
/** @brief Pointer to the transmit DMA channel registers block.*/ /** @brief Pointer to the transmit DMA channel registers block.*/
DMA_Channel_TypeDef *spd_dmatx; stm32_dma_channel_t *spd_dmatx;
/** @brief DMA priority bit mask.*/ /** @brief DMA priority bit mask.*/
uint32_t spd_dmaprio; uint32_t spd_dmaccr;
} SPIDriver; } SPIDriver;
/*===========================================================================*/ /*===========================================================================*/

View File

@ -56,10 +56,17 @@ static cnt_t dmacnt2;
* @brief STM32 DMA helper initialization. * @brief STM32 DMA helper initialization.
*/ */
void dmaInit(void) { void dmaInit(void) {
int i;
dmacnt1 = 0; dmacnt1 = 0;
for (i = STM32_DMA_CHANNEL_7; i >= STM32_DMA_CHANNEL_1; i--)
dmaDisableChannel(STM32_DMA1, i);
STM32_DMA1->IFCR = 0xFFFFFFFF;
#if defined(STM32F10X_HD) || defined (STM32F10X_CL) #if defined(STM32F10X_HD) || defined (STM32F10X_CL)
dmacnt2 = 0; dmacnt2 = 0;
for (i = STM32_DMA_CHANNEL_5; i >= STM32_DMA_CHANNEL_1; i--)
dmaDisableChannel(STM32_DMA2, i);
STM32_DMA1->IFCR = 0xFFFFFFFF;
#endif #endif
} }

View File

@ -126,7 +126,53 @@ typedef struct {
#define STM32_DMA_CHANNEL_7 6 /**< @brief DMA channel 7. */ #define STM32_DMA_CHANNEL_7 6 /**< @brief DMA channel 7. */
/** /**
* @brief DMA channel setup. * @brief Associates a peripheral data register to a DMA channel.
*
* @param[in] dmachp dmachp to a stm32_dma_channel_t structure
* @param[in] cmar value to be written in the CPAR register
*/
#define dmaChannelSetPeripheral(dmachp, cpar) { \
(dmachp)->CPAR = (uint32_t)(cpar); \
}
/**
* @brief DMA channel setup by channel pointer.
* @note This macro does not change the CPAR register because that register
* value does not change frequently, it usually points to a peripheral
* data register.
*
* @param[in] dmachp dmachp to a stm32_dma_channel_t structure
* @param[in] cndtr value to be written in the CNDTR register
* @param[in] cmar value to be written in the CMAR register
* @param[in] ccr value to be written in the CCR register
*/
#define dmaChannelSetup(dmachp, cndtr, cmar, ccr) { \
(dmachp)->CNDTR = (uint32_t)(cndtr); \
(dmachp)->CMAR = (uint32_t)(cmar); \
(dmachp)->CCR = (uint32_t)(ccr); \
}
/**
* @brief DMA channel enable by channel pointer.
*
* @param[in] dmachp dmachp to a stm32_dma_channel_t structure
*/
#define dmaChannelEnable(dmachp) { \
(dmachp)->CCR |= DMA_CCR1_EN; \
}
/**
* @brief DMA channel disable by channel pointer.
*
* @param[in] dmachp dmachp to a stm32_dma_channel_t structure
*/
#define dmaChannelDisable(dmachp) { \
(dmachp)->CCR = 0; \
}
/**
* @brief DMA channel setup by channel ID.
* @note This macro does not change the CPAR register because that register * @note This macro does not change the CPAR register because that register
* value does not change frequently, it usually points to a peripheral * value does not change frequently, it usually points to a peripheral
* data register. * data register.
@ -140,14 +186,11 @@ typedef struct {
* @param[in] ccr value to be written in the CCR register * @param[in] ccr value to be written in the CCR register
*/ */
#define dmaSetupChannel(dmap, ch, cndtr, cmar, ccr) { \ #define dmaSetupChannel(dmap, ch, cndtr, cmar, ccr) { \
stm32_dma_channel_t *dmachp = &dmap->channels[ch]; \ dmaChannelSetup(&(dmap)->channels[ch], (cndtr), (cmar), (ccr)); \
(dmachp)->CNDTR = (uint32_t)(cndtr); \
(dmachp)->CMAR = (uint32_t)(cmar); \
(dmachp)->CCR = (uint32_t)(ccr); \
} }
/** /**
* @brief DMA channel enable. * @brief DMA channel enable by channel ID.
* @note Channels are numbered from 0 to 6, use the appropriate macro * @note Channels are numbered from 0 to 6, use the appropriate macro
* as parameter. * as parameter.
* *
@ -155,11 +198,11 @@ typedef struct {
* @param[in] ch channel number * @param[in] ch channel number
*/ */
#define dmaEnableChannel(dmap, ch) { \ #define dmaEnableChannel(dmap, ch) { \
(dmap)->channels[ch].CCR |= 1; \ dmaChannelEnable(&(dmap)->channels[ch]); \
} }
/** /**
* @brief DMA channel disable. * @brief DMA channel disable by channel ID.
* @note Channels are numbered from 0 to 6, use the appropriate macro * @note Channels are numbered from 0 to 6, use the appropriate macro
* as parameter. * as parameter.
* *
@ -167,7 +210,7 @@ typedef struct {
* @param[in] ch channel number * @param[in] ch channel number
*/ */
#define dmaDisableChannel(dmap, ch) { \ #define dmaDisableChannel(dmap, ch) { \
(dmap)->channels[ch].CCR = 0; \ dmaChannelDisable(&(dmap)->channels[ch]); \
} }
/** /**

View File

@ -80,7 +80,10 @@
- NEW: Added a generic BaseFileStream interface for future File System - NEW: Added a generic BaseFileStream interface for future File System
implementations or integrations (untested and not sure if it will stay or implementations or integrations (untested and not sure if it will stay or
change). change).
- OPT: Speed optimizations of the STM32 SPI driver, improved latency.
- CHANGE: Modified the STM32 ADC driver to use the new DMA infrastructure. - CHANGE: Modified the STM32 ADC driver to use the new DMA infrastructure.
- CHANGE: Modified the STM32 SPI driver to use the new DMA infrastructure.
- CHANGE: Added DMA cleanup code to the STM32 dmaInit() function.
- CHANGE: Simplified preprocessor conditions in the STM32 serial driver. - CHANGE: Simplified preprocessor conditions in the STM32 serial driver.
- CHANGE: Renamed most of the STM32 HAL settings macro names in order to - CHANGE: Renamed most of the STM32 HAL settings macro names in order to
make names more consistent. make names more consistent.