AnsweredAssumed Answered

DMA returns wrong SPI data

Question asked by Sebastian Aslund on Dec 8, 2017

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

Outcomes