Skip to main content
kn7
Associate
January 10, 2011
Question

Receiving SPI data through DMA - STM32 internal hardware error ?

  • January 10, 2011
  • 16 replies
  • 3165 views
Posted on January 10, 2011 at 22:55

Receiving SPI data through DMA - STM32 internal hardware error ?

#spi-dma
This topic has been closed for replies.

16 replies

kn7
kn7Author
Associate
May 17, 2011
Posted on May 17, 2011 at 14:21

You should use return SPIx->DR, not tmp8 return to global variable.

The tmp8 global variable consumes only one byte so this is not a problem for 20KB memory. Besides if tmp8 is declared as a local variable the compiler removes the code for the instruction: tmp8 = SPIx->DR because it detects the tmp8 is never used again in the function. This is due to optimization compiler does when compiling a program.

leszek2
Associate
May 17, 2011
Posted on May 17, 2011 at 14:21

You should use return SPIx->DR, not tmp8 return to global variable. Its not efficient and the global variable consumes memory for whole program run. Local variable are better because they are pushed on stack only for the needed time and then poped.

nanayakkaraan
Associate III
May 17, 2011
Posted on May 17, 2011 at 14:21

Thanks Robert.

Will look into it.

Tesla DeLorean
Guru
May 17, 2011
Posted on May 17, 2011 at 14:21

Not really enough information to work with here.

What are you connecting it too, and how are you initializing the system?

Have you attached a scope/analyzer to the bus to confirm it's not sending zeros? If it is then the DMA is not the problem, but rather the peripheral.

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
jpa
Associate II
May 17, 2011
Posted on May 17, 2011 at 14:21

I am also having trouble with DMA and SPI, on STM32F100. First time I receive a data block after reset, I get only 0x00. The second time I get the correct data except one byte missing from beginning.

Here is my code:

// Transmit 0xFF and receive to buf.

static void dma_rx(BYTE *buf, UINT count)

{

    char txvalue = 0xff;

   

    // Transmit channel

    DMA1_Channel3->CPAR = (int) &(SPI1->DR);

    DMA1_Channel3->CMAR = (int) &txvalue;

    DMA1_Channel3->CNDTR = count;

    DMA1_Channel3->CCR = (1 << 8) | DMA_CCR1_DIR; // Low priority

   

    // Receive channel

    DMA1->IFCR = DMA_IFCR_CGIF2;

    DMA1->IFCR = 0;

    DMA1_Channel2->CPAR = (int) &(SPI1->DR);

    DMA1_Channel2->CMAR = (int) buf;

    DMA1_Channel2->CNDTR = count;

    DMA1_Channel2->CCR = (1 << 12) | (1 << 8) | DMA_CCR1_MINC | DMA_CCR1_TCIE; // Medium priority

   

    NVIC_EnableIRQ(DMA1_Channel2_IRQn);

    NVIC_SetPriority(DMA1_Channel2_IRQn, 14);

   

    always_read(SPI1->DR);

    always_read(SPI1->SR);

    DMA1_Channel2->CCR |= DMA_CCR1_EN;

    DMA1_Channel3->CCR |= DMA_CCR1_EN;

    SPI1->CR2 |= SPI_CR2_TXDMAEN | SPI_CR2_RXDMAEN;

   

    vTaskDelay(1);

    xSemaphoreTake(mmc_dma_semaphore, 10000);

   

    SPI1->CR2 &= ~(SPI_CR2_TXDMAEN | SPI_CR2_RXDMAEN);

    DMA1_Channel3->CCR &= ~DMA_CCR1_EN;

    DMA1_Channel2->CCR &= ~DMA_CCR1_EN;

}

jpa
Associate II
May 17, 2011
Posted on May 17, 2011 at 14:21

Never mind, got it fixed after all. It was a bunch of overlapping problems. Most importantly, I wasn't reading back the data after transmission-only requests, leaving one byte in DR.

For anyone else who might need it: To clear the SPI RXNE and overflow flags before starting the DMA transfer, I use this:

#define always_read(x) asm(''''::''r''(x))

while (!(SPI1->SR & SPI_SR_TXE)); // Wait for bus free

while (SPI1->SR & SPI_SR_BSY);

always_read(SPI1->DR); // Clear RX flags

always_read(SPI1->SR);