SPI on STM32F4

ChibiOS public support forum for topics related to the STMicroelectronics STM32 family of micro-controllers.

Moderators: barthess, RoccoMarco

sueng66
Posts: 10
Joined: Thu Jun 20, 2013 7:18 am

SPI on STM32F4

Postby sueng66 » Thu Jun 20, 2013 7:26 am

Hi all,

I have experiencing never success using SPI Driver on STM32F4 ( I am using Olimex STM32 E407 ). The SPI it self is working in manual mode and interrupt mode. The driver is working when I patched the driver to use interrupt instead of DMA transfer. It's look like the DMA logic never move data from memory to DR when the tx buffer already empty.

Does anybody experience same problem ?
note : I am using Chibios 2.6.0

Thanks

Regards

Sueng

User avatar
Tectu
Posts: 1226
Joined: Thu May 10, 2012 9:50 am
Location: Switzerland
Contact:

Re: SPI on STM32F4

Postby Tectu » Thu Jun 20, 2013 7:32 am

I'm currently not on ChibiOS/RT 2.6 but I used the E407 demo myself from the 2.5 version. I never had any trouble. Did you take the demo you can find in /demos or did you write up something yourself?


~ Tectu

sueng66
Posts: 10
Joined: Thu Jun 20, 2013 7:18 am

Re: SPI on STM32F4

Postby sueng66 » Thu Jun 20, 2013 7:47 am

Sorry to bother you all, after browsing the forum I realized that SPI2 and USART3 share common DMA channel , after disabling USART3 the SPI2 working normally using DMA.

Thanks

User avatar
Tectu
Posts: 1226
Joined: Thu May 10, 2012 9:50 am
Location: Switzerland
Contact:

Re: SPI on STM32F4

Postby Tectu » Thu Jun 20, 2013 7:50 am

Good to hear that it worked out - enjoy your SPI ;-)

By the way: When you want to use both at the same time, you may modify the DMA streams in your mcuconf.h. However, you must take a look into the datasheet first - I am not sure if the matrix allows it to map them across each other.


~ Tectu

sueng66
Posts: 10
Joined: Thu Jun 20, 2013 7:18 am

Re: SPI on STM32F4

Postby sueng66 » Thu Jun 20, 2013 7:53 am

you are right when the device has alternate DMA Channel in case SPI2 and USART3 both does not have another alternative DMA Channel

User avatar
Giovanni
Site Admin
Posts: 12855
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 712 times
Been thanked: 592 times
Contact:

Re: SPI on STM32F4

Postby Giovanni » Thu Jun 20, 2013 8:04 am

This is an STM32 limitation however there is a way to use both peripherals and using the same DMA channels, you just need to make sure you don't start both drivers at the same time, for example:

This would be OK:

Code: Select all

spiStart(&SPID2,...);
...
spiStop(&SPID2);
uartStart(&UARTD3,...);
...
uartStop(&UARTD3);

This would not work:

Code: Select all

spiStart(&SPID2,...);
uartStart(&UARTD3,...);
...
spiStop(&SPID2);
uartStop(&UARTD3);

Giovanni

User avatar
Tectu
Posts: 1226
Joined: Thu May 10, 2012 9:50 am
Location: Switzerland
Contact:

Re: SPI on STM32F4

Postby Tectu » Thu Jun 20, 2013 8:14 am

I took a quick look into the reference manual and as it looks it should be possible to use them both at the same time when you use SPI2 on channel 0 and USART3 on channel 4. However, you'll of course get new collisions then.


~ Tectu

sueng66
Posts: 10
Joined: Thu Jun 20, 2013 7:18 am

Re: SPI on STM32F4

Postby sueng66 » Thu Jun 20, 2013 8:16 am

yes that's another way, if there is a condition that both device have to work in parallel providing another alternative other than DMA maybe good point, like what I did before.

sueng66
Posts: 10
Joined: Thu Jun 20, 2013 7:18 am

Re: SPI on STM32F4

Postby sueng66 » Thu Jun 20, 2013 8:18 am

This is my work on SPI driver :

diff -ru SPIv1ori/spi_lld.c SPIv1/spi_lld.c
--- SPIv1ori/spi_lld.c 2013-06-20 11:58:46.005216869 +0700
+++ SPIv1/spi_lld.c 2013-06-20 14:08:59.785602257 +0700
@@ -80,6 +80,8 @@

static uint16_t dummytx;
static uint16_t dummyrx;
+static uint8_t adummyrx[16];
+static uint8_t adummytx[16];

/*===========================================================================*/
/* Driver local functions. */
@@ -130,6 +132,80 @@
(void)flags;
#endif
}
+
+#if SPI_USE_INT_NODMA || defined(__DOXYGEN__)
+static void serve_spi_irq(SPIDriver *spip) {
+ if(spip->spi->SR & SPI_SR_TXE) {
+ //ready to transmit
+ if(spip->txcnt>0) {
+ spip->spi->DR = (uint16_t)*(spip->txptr);
+ spip->txptr++;
+ spip->txcnt--;
+ if(spip->txcnt==0) {
+ spip->spi->CR2 &= ~(SPI_CR2_TXEIE);
+ spi_lld_serve_tx_interrupt(spip, 0);
+ }
+ } else if(spip->txcnt==0){
+ spi_lld_serve_tx_interrupt(spip, 0);
+ spip->txcnt = -1;
+ }
+ }
+ if(spip->spi->SR & SPI_SR_RXNE) {
+ //receive data ready
+ if(spip->rxcnt>0) {
+ *(spip->rxptr) = (uint8_t)spip->spi->DR;
+ spip->rxptr++;
+ spip->rxcnt--;
+ if(spip->rxcnt==0){
+ spip->spi->CR2 &= ~(SPI_CR2_RXNEIE);
+ spi_lld_serve_rx_interrupt(spip, 0);
+ spip->rxcnt = -1;
+ }
+ } else {
+ uint16_t tmp = spip->spi->DR;
+ }
+ }
+}
+
+#if STM32_SPI_USE_SPI1
+CH_IRQ_HANDLER(SPI1_IRQHandler) {
+ uint32_t flags;
+
+ CH_IRQ_PROLOGUE();
+
+ serve_spi_irq(&SPID1);
+
+ CH_IRQ_EPILOGUE();
+}
+#endif
+
+#if STM32_SPI_USE_SPI2
+
+CH_IRQ_HANDLER(SPI2_IRQHandler) {
+ uint32_t flags;
+
+ CH_IRQ_PROLOGUE();
+
+ serve_spi_irq(&SPID2);
+
+ CH_IRQ_EPILOGUE();
+}
+
+#endif
+
+#if STM32_SPI_USE_SPI3
+CH_IRQ_HANDLER(SPI3_IRQHandler) {
+ uint32_t flags;
+
+ CH_IRQ_PROLOGUE();
+
+ serve_spi_irq(&SPID1);
+
+ CH_IRQ_EPILOGUE();
+}
+#endif
+#endif
+

/*===========================================================================*/
/* Driver interrupt handlers. */
@@ -216,6 +292,7 @@
if (spip->state == SPI_STOP) {
#if STM32_SPI_USE_SPI1
if (&SPID1 == spip) {
+#if !SPI_USE_INT_NODMA
bool_t b;
b = dmaStreamAllocate(spip->dmarx,
STM32_SPI_SPI1_IRQ_PRIORITY,
@@ -227,11 +304,13 @@
(stm32_dmaisr_t)spi_lld_serve_tx_interrupt,
(void *)spip);
chDbgAssert(!b, "spi_lld_start(), #2", "stream already allocated");
- rccEnableSPI1(FALSE);
+#endif
+ rccEnableSPI1(FALSE);
}
#endif
#if STM32_SPI_USE_SPI2
if (&SPID2 == spip) {
+#if !SPI_USE_INT_NODMA
bool_t b;
b = dmaStreamAllocate(spip->dmarx,
STM32_SPI_SPI2_IRQ_PRIORITY,
@@ -243,11 +322,13 @@
(stm32_dmaisr_t)spi_lld_serve_tx_interrupt,
(void *)spip);
chDbgAssert(!b, "spi_lld_start(), #4", "stream already allocated");
+#endif
rccEnableSPI2(FALSE);
}
#endif
#if STM32_SPI_USE_SPI3
if (&SPID3 == spip) {
+#if !SPI_USE_INT_NODMA
bool_t b;
b = dmaStreamAllocate(spip->dmarx,
STM32_SPI_SPI3_IRQ_PRIORITY,
@@ -259,36 +340,60 @@
(stm32_dmaisr_t)spi_lld_serve_tx_interrupt,
(void *)spip);
chDbgAssert(!b, "spi_lld_start(), #6", "stream already allocated");
+#endif
rccEnableSPI3(FALSE);
}
#endif

/* DMA setup.*/
+#if !SPI_USE_INT_NODMA
dmaStreamSetPeripheral(spip->dmarx, &spip->spi->DR);
- dmaStreamSetPeripheral(spip->dmatx, &spip->spi->DR);
+ dmaStreamSetPeripheral(spip->dmatx, &spip->spi->DR);
+#endif
}

/* Configuration-specific DMA setup.*/
- if ((spip->config->cr1 & SPI_CR1_DFF) == 0) {
- /* Frame width is 8 bits or smaller.*/
+#if !SPI_USE_INT_NODMA
+ if ((spip->config->cr1 & SPI_CR1_DFF) == 0) { /* 8 bits transfers. */
spip->rxdmamode = (spip->rxdmamode & ~STM32_DMA_CR_SIZE_MASK) |
STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE;
spip->txdmamode = (spip->txdmamode & ~STM32_DMA_CR_SIZE_MASK) |
STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE;
}
- else {
- /* Frame width is larger than 8 bits.*/
+ else { /* 16 bits transfers. */
spip->rxdmamode = (spip->rxdmamode & ~STM32_DMA_CR_SIZE_MASK) |
STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD;
spip->txdmamode = (spip->txdmamode & ~STM32_DMA_CR_SIZE_MASK) |
STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD;
- }
+ }
+#endif
/* SPI setup and enable.*/
- spip->spi->CR1 = 0;
+ spip->spi->CR1 = 0;
spip->spi->CR1 = spip->config->cr1 | SPI_CR1_MSTR | SPI_CR1_SSM |
- SPI_CR1_SSI;
- spip->spi->CR2 = SPI_CR2_SSOE | SPI_CR2_RXDMAEN | SPI_CR2_TXDMAEN;
+ SPI_CR1_SSI ;
+#if SPI_USE_INT_NODMA
+ spip->spi->CR2 = SPI_CR2_SSOE;
+#else
+ spip->spi->CR2 = SPI_CR2_SSOE | SPI_CR2_RXDMAEN | SPI_CR2_TXDMAEN;
+#endif
spip->spi->CR1 |= SPI_CR1_SPE;
+#if SPI_USE_INT_NODMA
+#if STM32_SPI_USE_SPI1
+ if (&SPID1 == spip) {
+ nvicEnableVector(SPI1_IRQn, CORTEX_PRIORITY_MASK(STM32_SPI_SPI1_IRQ_PRIORITY));
+ }
+#endif
+#if STM32_SPI_USE_SPI2
+ if (&SPID2 == spip) {
+ nvicEnableVector(SPI2_IRQn, CORTEX_PRIORITY_MASK(STM32_SPI_SPI2_IRQ_PRIORITY));
+ }
+#endif
+#if STM32_SPI_USE_SPI3
+ if (&SPID3 == spip) {
+ nvicEnableVector(SPI3_IRQn, CORTEX_PRIORITY_MASK(STM32_SPI_SPI3_IRQ_PRIORITY));
+ }
+#endif
+#endif
}

/**
@@ -305,21 +410,30 @@

/* SPI disable.*/
spip->spi->CR1 = 0;
- spip->spi->CR2 = 0;
+#if !SPI_USE_INT_NODMA
dmaStreamRelease(spip->dmarx);
- dmaStreamRelease(spip->dmatx);
-
+ dmaStreamRelease(spip->dmatx);
+#endif
#if STM32_SPI_USE_SPI1
if (&SPID1 == spip)
- rccDisableSPI1(FALSE);
+ rccDisableSPI1(FALSE);
+#if SPI_USE_INT_NODMA
+ nvicDisableVector(SPI1_IRQn);
+#endif
#endif
#if STM32_SPI_USE_SPI2
if (&SPID2 == spip)
rccDisableSPI2(FALSE);
+#if SPI_USE_INT_NODMA
+ nvicDisableVector(SPI2_IRQn);
+#endif
#endif
#if STM32_SPI_USE_SPI3
if (&SPID3 == spip)
rccDisableSPI3(FALSE);
+#if SPI_USE_INT_NODMA
+ nvicDisableVector(SPI3_IRQn);
+#endif
#endif
}
}
@@ -361,7 +475,18 @@
* @notapi
*/
void spi_lld_ignore(SPIDriver *spip, size_t n) {
-
+#if SPI_USE_INT_NODMA
+ spip->txptr = adummytx;
+ spip->rxptr = adummyrx;
+ spip->txcnt = n;
+ spip->rxcnt = n;
+ if(spip->spi->SR & SPI_SR_TXE) {
+ spip->txcnt--;
+ spip->spi->DR = *spip->txptr;
+ spip->txptr++;
+ }
+ spip->spi->CR2 |= SPI_CR2_RXNEIE | SPI_CR2_TXEIE;
+#else
dmaStreamSetMemory0(spip->dmarx, &dummyrx);
dmaStreamSetTransactionSize(spip->dmarx, n);
dmaStreamSetMode(spip->dmarx, spip->rxdmamode);
@@ -371,7 +496,8 @@
dmaStreamSetMode(spip->dmatx, spip->txdmamode);

dmaStreamEnable(spip->dmarx);
- dmaStreamEnable(spip->dmatx);
+ dmaStreamEnable(spip->dmatx);
+#endif
}

/**
@@ -391,6 +517,18 @@
*/
void spi_lld_exchange(SPIDriver *spip, size_t n,
const void *txbuf, void *rxbuf) {
+#if SPI_USE_INT_NODMA
+ spip->txptr = txbuf;
+ spip->rxptr = rxbuf;
+ spip->txcnt = n;
+ spip->rxcnt = n;
+ if(spip->spi->SR & SPI_SR_TXE) {
+ spip->txcnt--;
+ spip->spi->DR = *spip->txptr;
+ spip->txptr++;
+ }
+ spip->spi->CR2 |= SPI_CR2_RXNEIE | SPI_CR2_TXEIE;
+#else

dmaStreamSetMemory0(spip->dmarx, rxbuf);
dmaStreamSetTransactionSize(spip->dmarx, n);
@@ -401,7 +539,8 @@
dmaStreamSetMode(spip->dmatx, spip->txdmamode | STM32_DMA_CR_MINC);

dmaStreamEnable(spip->dmarx);
- dmaStreamEnable(spip->dmatx);
+ dmaStreamEnable(spip->dmatx);
+#endif
}

/**
@@ -418,7 +557,19 @@
* @notapi
*/
void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf) {
- palTogglePad(GPIOE, GPIOE_LOG);
+
+#if SPI_USE_INT_NODMA
+ spip->txptr = txbuf;
+ spip->rxptr = adummyrx;
+ spip->txcnt = n;
+ spip->rxcnt = n;
+ if(spip->spi->SR & SPI_SR_TXE) {
+ spip->txcnt--;
+ spip->spi->DR = *spip->txptr;
+ spip->txptr++;
+ }
+ spip->spi->CR2 |= SPI_CR2_RXNEIE | SPI_CR2_TXEIE;
+#else
dmaStreamSetMemory0(spip->dmarx, &dummyrx);
dmaStreamSetTransactionSize(spip->dmarx, n);
dmaStreamSetMode(spip->dmarx, spip->rxdmamode);
@@ -428,7 +579,8 @@
dmaStreamSetMode(spip->dmatx, spip->txdmamode | STM32_DMA_CR_MINC);

dmaStreamEnable(spip->dmarx);
- dmaStreamEnable(spip->dmatx);
+ dmaStreamEnable(spip->dmatx);
+#endif
}

/**
@@ -446,6 +598,18 @@
*/
void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf) {

+#if SPI_USE_INT_NODMA
+ spip->txptr = adummytx;
+ spip->rxptr = rxbuf;
+ spip->txcnt = n;
+ spip->rxcnt = n;
+ if(spip->spi->SR & SPI_SR_TXE) {
+ spip->txcnt--;
+ spip->spi->DR = *spip->txptr;
+ spip->txptr++;
+ }
+ spip->spi->CR2 |= SPI_CR2_RXNEIE | SPI_CR2_TXEIE;
+#else
dmaStreamSetMemory0(spip->dmarx, rxbuf);
dmaStreamSetTransactionSize(spip->dmarx, n);
dmaStreamSetMode(spip->dmarx, spip->rxdmamode | STM32_DMA_CR_MINC);
@@ -455,7 +619,8 @@
dmaStreamSetMode(spip->dmatx, spip->txdmamode);

dmaStreamEnable(spip->dmarx);
- dmaStreamEnable(spip->dmatx);
+ dmaStreamEnable(spip->dmatx);
+#endif
}

/**
diff -ru SPIv1ori/spi_lld.h SPIv1/spi_lld.h
--- SPIv1ori/spi_lld.h 2013-05-05 08:55:04.000000000 +0700
+++ SPIv1/spi_lld.h 2013-06-20 14:08:59.745602081 +0700
@@ -363,7 +363,13 @@
/**
* @brief TX DMA mode bit mask.
*/
- uint32_t txdmamode;
+ uint32_t txdmamode;
+#if SPI_USE_INT_NODMA
+ uint8_t *txptr;
+ uint8_t txcnt;
+ uint8_t *rxptr;
+ uint8_t rxcnt;
+#endif
};

/*===========================================================================*/

User avatar
Tectu
Posts: 1226
Joined: Thu May 10, 2012 9:50 am
Location: Switzerland
Contact:

Re: SPI on STM32F4

Postby Tectu » Thu Jun 20, 2013 8:55 am

Can you please use the code tags --> [code] your code here [ /code] or add larger files as an attachment to your post? This ensures that nobody breaks his finger when scrolling to the bottom :)


~ Tectu


Return to “STM32 Support”

Who is online

Users browsing this forum: No registered users and 2 guests