cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F767 - Problems with the SPI communication

mof182
Associate II

Hi,

I started now programming the STM32F767ZI MCU and do not have any experience with 32bit uController.

I have to programm a project, which includes a SPI communication to an external ADC. It must be programmed with the LL library and I'd like to do this by DMA.

My problem is, that my programm sends out only one byte at the first frame although it is four bytes long (I checked the datalength register: 4 bytes). Additionally the last bit will not be send correctly, because the clock falls at the same time the MOSI signal falls to zero (see attachment).

The two graph shows the signals after sending two frames ('0x41' , '0x55', '0x55'). The second frame starts after the ready interrupt of the DMA.

0693W000001qeYBQAY.png

0693W000001qeYLQAY.png

I think, that both problems causes in the initialization:

/* Configure the 2.DMA functional parameters (write)*/

      LL_DMA_SetChannelSelection(m_Param.pDMAx_TX, m_Param.u32DMAStream_TX, m_Param.u32DMAChannel_TX);

      LL_DMA_ConfigTransfer(m_Param.pDMAx_TX, m_Param.u32DMAStream_TX, LL_DMA_DIRECTION_MEMORY_TO_PERIPH | LL_DMA_PRIORITY_HIGH | LL_DMA_MODE_NORMAL | LL_DMA_PERIPH_NOINCREMENT | LL_DMA_MEMORY_INCREMENT | LL_DMA_PDATAALIGN_BYTE | LL_DMA_MDATAALIGN_BYTE);

      LL_DMA_ConfigAddresses(m_Param.pDMAx_TX, m_Param.u32DMAStream_TX, (uint32_t)m_Results.au8TxBuffer, LL_SPI_DMA_GetRegAddr(m_Param.pSPIx), LL_DMA_GetDataTransferDirection(m_Param.pDMAx_TX, m_Param.u32DMAStream_TX));

      LL_DMA_ConfigFifo(m_Param.pDMAx_TX, m_Param.u32DMAStream_TX, LL_DMA_FIFOMODE_ENABLE, LL_DMA_FIFOTHRESHOLD_1_4);

      LL_DMA_SetMemoryBurstxfer(m_Param.pDMAx_TX, m_Param.u32DMAStream_TX, LL_DMA_MBURST_SINGLE);

      LL_DMA_SetPeriphBurstxfer(m_Param.pDMAx_RX, m_Param.u32DMAStream_TX, LL_DMA_PBURST_SINGLE);

      LL_DMA_SetDataLength(m_Param.pDMAx_TX, m_Param.u32DMAStream_TX, 0);

//      LL_DMA_DisableFifoMode(m_Param.pDMAx_RX, m_Param.u32DMAStream_TX);

/* (5) Enable DMA interrupts complete/error */

      LL_DMA_EnableIT_TC(m_Param.pDMAx_RX, m_Param.u32DMAStream_RX);

      LL_DMA_EnableIT_TE(m_Param.pDMAx_RX, m_Param.u32DMAStream_RX);

      LL_DMA_EnableIT_TC(m_Param.pDMAx_TX, m_Param.u32DMAStream_TX);

      LL_DMA_EnableIT_TE(m_Param.pDMAx_TX, m_Param.u32DMAStream_TX);

It would be very kind, if somebody would like to help me solving my problem.

9 REPLIES 9
TDK
Guru

DMA initialization seems fine. How are you starting/stopping the transfer? I wouldn't recommend using the FIFO unless you are only sending data which is a multiple of the FIFO length you're using.

If you feel a post has answered your question, please click "Accept as Solution".
mof182
Associate II

Hi TDK,

thanks for your reply.

The sending function is:

uint32_t CSpi::Send(uint8_t *pData, uint32_t u32Bytes)

{

/* Variable declarations */

   uint32_t u32RetVal;

   static uint16_t u16State = 0;

/* End - Variable declarations */

/* Variable initialisations */

   u32RetVal = __SAFETY_NO_ERROR__;

/* End - Variable initialisations */

/* Start user code here */

   CHECK_INIT(__CSPI_FCT_SEND__);

   if(u32Bytes <= CSPI_BUFFERSIZE_TX)

   {

      if(memcpy(m_Results.au8TxBuffer, pData,u32Bytes) != 0U)

      {

         m_Param.u32DataToTransmit = u32Bytes;

         m_Param.u32DataToReceive = u32Bytes;

         LL_DMA_SetDataLength(m_Param.pDMAx_TX, m_Param.u32DMAStream_TX, m_Param.u32DataToTransmit);

         LL_DMA_SetDataLength(m_Param.pDMAx_RX, m_Param.u32DMAStream_RX, m_Param.u32DataToReceive);

         Start();

/*

         while(m_Results.bDataSent == false)

         {

            ;

         }

*/

      }

      else

      {

         u32RetVal = SAFETYERROR(__CSPI_FCT_SEND__,__CSPI_MEMCPY__);

      }

   }

   else

   {

      u32RetVal = SAFETYERROR(__CSPI_FCT_SEND__,__CSPI_DATA_SIZE__);

   }

/* End user code */

/* Return section */

   SAFETY_RETURN(u32RetVal);

/* End return section */

}

I tried to disable the Fifo by 'LL_DMA_DisableFifoMode(DMA2, LL_DMA_STREAM_0);' but nothing changed.

mof182
Associate II

uint32_t CSpi::Start(void)

{

/* Variable declarations */

   uint32_t u32RetVal;

/* End - Variable declarations */

/* Variable initialisations */

   u32RetVal = __SAFETY_NO_ERROR__;

/* End - Variable initialisations */

/* Start user code here */

   CHECK_INIT(__CSPI_FCT_START__);

   m_Results.bDataReceived = false;

   m_Results.bDataSent = false;

   assert_param(m_Param.u32DataToTransmit == LL_DMA_GetDataLength(m_Param.pDMAx_TX, m_Param.u32DMAStream_TX));

/* Enable SPI1 */

   LL_SPI_Enable(m_Param.pSPIx);

/* Enable DMA Channels */

   LL_DMA_EnableStream(m_Param.pDMAx_RX, m_Param.u32DMAStream_RX);

   LL_DMA_EnableStream(m_Param.pDMAx_TX, m_Param.u32DMAStream_TX);

/* End user code */

/* Return section */

   SAFETY_RETURN(u32RetVal);

/* End return section */

}

TDK
Guru

Well, a few things:

Since you have CPHA=1, there is no delay between when the last bit is sent (falling edge) and when the transmission completes. If you want a delay there, you'll need to add it.

I don't ever see you calling LL_SPI_EnableDMAReq_TX or LL_SPI_EnableDMAReq_RX, but since it's working, presumably you are doing this somewhere.

It looks like you can send a frame of 1 byte and 2 bytes. I see no reason why a frame of 4 bytes wouldn't work based on the code you showed.

If you feel a post has answered your question, please click "Accept as Solution".
mof182
Associate II

Hi TDK,

  1. How can I insert a delay? Please call me the LL function name.
  2. LL_SPI_EnableDMAReq_xX: I do this here:

uint32_t CSpi::InitSPI(void)

{

/* Variable declarations */

   uint32_t u32RetVal;

/* End - Variable declarations */

/* Variable initialisations */

   u32RetVal = __SAFETY_NO_ERROR__;

/* End - Variable initialisations */

/* Start user code here */

/* Enable the peripheral clock of SPIx */

   if(m_Param.pSPIx == SPI1)

   {

      LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI1);

   }

   else if(m_Param.pSPIx == SPI2)

   {

      LL_APB2_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_SPI2);

   }

   else if(m_Param.pSPIx == SPI3)

   {

      LL_APB2_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_SPI3);

   }

   else if(m_Param.pSPIx == SPI4)

   {

      LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI4);

   }

   else if(m_Param.pSPIx == SPI5)

   {

      LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI5);

   }

   else if(m_Param.pSPIx == SPI6)

   {

      LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI6);

   }

   else

   {

      u32RetVal = SAFETYERROR(__CSPI_FCT_INIT_SPI__,__CSPI_INDEX_INTERFACE__);

   }

   if(u32RetVal == __SAFETY_NO_ERROR__)

   {

      LL_SPI_SetBaudRatePrescaler(m_Param.pSPIx, LL_SPI_BAUDRATEPRESCALER_DIV32);

      LL_SPI_SetBaudRatePrescaler(m_Param.pSPIx, LL_SPI_BAUDRATEPRESCALER_DIV256);

      LL_SPI_SetTransferDirection(m_Param.pSPIx,LL_SPI_FULL_DUPLEX);

/*      LL_SPI_SetClockPhase(m_Param.pSPIx, LL_SPI_PHASE_1EDGE); */         /* CPOL = 1 */

      LL_SPI_SetClockPhase(m_Param.pSPIx, LL_SPI_PHASE_2EDGE);         /* CPOL = 0 */

/*      LL_SPI_SetClockPolarity(m_Param.pSPIx, LL_SPI_POLARITY_HIGH); */      /* CPHA = 0 */

      LL_SPI_SetClockPolarity(m_Param.pSPIx, LL_SPI_POLARITY_LOW);      /* CPHA = 1 */

/* Reset value is LL_SPI_MSB_FIRST */

/*      LL_SPI_SetTransferBitOrder(m_Param.pSPIx, LL_SPI_MSB_FIRST); */

      LL_SPI_SetDataWidth(m_Param.pSPIx, LL_SPI_DATAWIDTH_8BIT);

//    LL_SPI_EnableNSSPulseMgt(SPI1);

      if((m_Param.u16PortPinNSS != 0U)&&(m_Param.u16PortNSS != 0U))

      {

         if(m_Param.bMasterMode == false)

         {

            LL_SPI_SetNSSMode(m_Param.pSPIx, LL_SPI_NSS_HARD_INPUT);

         }

         else

         {

            if(m_Param.bNSSSoft == false)

            {

               LL_SPI_SetNSSMode(m_Param.pSPIx, LL_SPI_NSS_HARD_OUTPUT);

            }

            else

            {

               LL_SPI_SetNSSMode(m_Param.pSPIx, LL_SPI_NSS_SOFT);

            }

         }

         LL_SPI_EnableNSSPulseMgt(m_Param.pSPIx);

         LL_SPI_EnableNSSPulseMgt(SPI1);

      }

      LL_SPI_SetRxFIFOThreshold(m_Param.pSPIx, LL_SPI_RX_FIFO_TH_QUARTER);

      if(m_Param.bMasterMode == true)

      {

         LL_SPI_SetMode(m_Param.pSPIx, LL_SPI_MODE_MASTER);

      }

      else

      {

         LL_SPI_SetMode(m_Param.pSPIx, LL_SPI_MODE_SLAVE);

      }

/* Configure SPI1 DMA transfer interrupts */

/* Enable DMA RX Interrupt */

      LL_SPI_EnableDMAReq_RX(m_Param.pSPIx);

/* Enable DMA TX Interrupt */

      LL_SPI_EnableDMAReq_TX(m_Param.pSPIx);

      LL_SPI_EnableIT_TXE(m_Param.pSPIx);

   }

/* End user code */

/* Return section */

   SAFETY_RETURN(u32RetVal);

/* End return section */

}

3. If I add a third frame simular, it will be send completly (3bytes)

Best regards

Michael

TDK
Guru

Options:

  1. You could use LL_mDelay.
  2. You can create one yourself with a one-shot timer.
  3. You could add a number of asm("NOP") based on the system clock speed and the desired delay.
  4. Or you could (my recommendation) enable/use DWT->CYCCNT to delay a precise number of ticks.

If you feel a post has answered your question, please click "Accept as Solution".
mof182
Associate II

Okay... fine!

Does it work with the hardware controled NLL signal?

Do you have some ideas because of the missing frame data?

TDK
Guru

I don't recommend using the hardware NSS signal. I'd use a GPIO pin and toggle it manually.

> LL_SPI_EnableIT_TXE(m_Param.pSPIx);

Why are you enabling this? With DMA you shouldn't care about TXE being asserted.

Not sure on the underlying issue. Examine DMA registers to see if NDTR gets to 0 eventually, or if errors have occurred.

If you feel a post has answered your question, please click "Accept as Solution".
mof182
Associate II

Hi TDK,

I think I have found the mean problem, but do not know how to solve it in a good way.

When I get the DMA interrupt I thought that all transmissions are done and disabled the SPI. But thats wrong because the TXE flag of the SPI is still cleared and the communication not completed. So I think, the best way is to wait for the SPI_TXE interrupt to be sure, that everything is completed. But the interrupt doesn't work (???).

If you have good ideas, please post it to me. I will go on to fix this problem by my own.