cancel
Showing results for 
Search instead for 
Did you mean: 

DMA returns wrong SPI data

Sebastian Aslund
Associate
Posted on December 08, 2017 at 10:48

Hello everyone.

I have a strange problem where my SPI data seems to 'shift' and my DMA goes out of control (I do not have a clue why it is acting as it does). I am developing a program using the STM32L433CC together with my company's custom ASIC. I have earlier used the STM32L051C8 without problems.

My STM32L433CC runs at 80Mhz, also on the peripherals.

If I choose to run without DMA then I get proper values:

   /// Enable peripheral clocks for SPI

   RCC->APB2ENR     |= RCC_APB2ENR_SPI1EN;

   /// --- SPI1 configuration ---

   /// Master selection, BR: Fpclk/16, Capture on second edge

   SPI1->CR1 |= SPI_CR1_MSTR | SPI_CR1_CPHA | SPI_CR1_BR_1 | SPI_CR1_BR_0;

   /// Slave select, DMA in RX and TX- 16-bit data frame

   SPI1->CR2 |=  SPI_CR2_SSOE | SPI_CR2_DS_3 | SPI_CR2_DS_2 | SPI_CR2_DS_1 | SPI_CR2_DS_0   

   SPI1->CR2 |= SPI_CR2_RXNEIE;

   SPI1->CR1 |= SPI_CR1_SPE;

   /// Set priority for SPI1_IRQn

   NVIC_SetPriority(SPI1_IRQn, 1);

   /// Enable SPI1_IRQn

   NVIC_EnableIRQ(SPI1_IRQn);

My response for our ASIC is for 5 tries:

1110010101100001

1110010100010111

1110010101001010

1110010111010000

1110010111010111

I know for a fact that the 6 first bits should be 111001. This is show correctly for all 5 tries. It is also verified on an oscilloscope.

If I remove RX interrupt for the SPI and add DMA for TX and RX.

   /// Enable peripheral clocks for DMA

   RCC->AHB1ENR     |= RCC_AHB1ENR_DMA1EN;

   ///--- DMA1 Channel2 SPI1 RX Config ---

   /// Map DMA Channel2 selection

   DMA1_CSELR->CSELR = (DMA1_CSELR->CSELR & ~DMA_CSELR_C2S) | (1 << DMA_CSELR_C2S_Pos);

   /// Set peripheral address

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

   /// Set memory address

   DMA1_Channel2->CMAR = (uint32_t)SPI1_RX_Data;

   /// Set data size

   DMA1_Channel2->CNDTR = (uint8_t)SPI_BUFFER_SIZE;

   /// Set memory increment, peripheral to memory, 16-bit transfer

   DMA1_Channel2->CCR |=  DMA_CCR_MSIZE_0 | DMA_CCR_MINC | DMA_CCR_TCIE | DMA_CCR_EN;

   ///--- DMA1 Channel3 SPI1 TX Config ---

   /// Map DMA Channel3 selection

   DMA1_CSELR->CSELR = (DMA1_CSELR->CSELR & ~DMA_CSELR_C3S) | (1 << DMA_CSELR_C3S_Pos);

   /// Set peripheral address

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

   /// Set memory address

   DMA1_Channel3->CMAR = (uint32_t)SPI1_TX_Data;

   /// Set memory increment, memory to peripheral, 16-bit transfer,

   DMA1_Channel3->CCR |= DMA_CCR_MSIZE_0 | DMA_CCR_MINC | DMA_CCR_DIR;

   /// Set priority for DMA1_Channel2_IRQn

   NVIC_SetPriority(DMA1_Channel2_IRQn, 2);

   /// Enable DMA1_Channel2_IRQn

   NVIC_EnableIRQ(DMA1_Channel2_IRQn);

SPI_BUFFER_SIZE is just 1 so only 1 16-bit transfer is performed. I initiate transfer by using:

   /// Enable DMA on SPI RX to be ready

   /// for next transfer

   DMA1_Channel2->CCR &= ~DMA_CCR_EN;

   DMA1_Channel2->CNDTR = (uint8_t)SPI_BUFFER_SIZE;

   DMA1_Channel2->CCR |= DMA_CCR_EN;

   /// Enable DMA1 to initiate SPI transfer

   DMA1_Channel3->CCR &=~ DMA_CCR_EN;

   DMA1_Channel3->CNDTR = (uint8_t)SPI_BUFFER_SIZE;

   DMA1_Channel3->CCR |= DMA_CCR_EN;

The first 5 tries gives:

0000000001110001

0000000011100101

0000000001001011

0000000011100101

0000000001110100

If I change to 8-bit transfer and attempt to receive 2 bytes then I do not get any interrupt om the DMA_Channel2.

From the received data by DMA it looks like the data is shifted one byte. Furthermore it seems try 1, 3 and 5 are 2nd byte data while try 2 and 4 is 1st byte data. How it manages to mess it up I can not figure out.

Has anyone experienced similar problems or has any ideas how to fix it?

Regards

Sebastian Aslund

#spi-over-dma #stm32l4 #stm32l4-spi
0 REPLIES 0