cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F303 - SPI1/DMA1 ch2 receiving only one byte

LukasPetrus
Associate II

Hi all,

I have trouble with receiving one byte on SPI1-DMA1. All is working if I set more bytes to transmit/receive (2 and more) but when I try to send only one byte it do not trigger interrupt on Rx channel (DMA1 channel 2).

I can see transmitted bytes on logic analyser. Transmitting is without problem and one byte is correct too and triggering Tx interrupt (on DMA1 Cchannel 3).

Interesting is that when I set receive one byte (spi1.rxLength = 1) and transmit two (spi1.txLength = 2) so Rx interrupt rise after one byte received.

I do not found any detail description about trigger DMA channel from SPI and counting received bytes. Could you help me with to found where problem is?

Here is preparig struct:

//------------------------------

       spi1.rxLength = 1; //for DMA_SetCurrDataCounter

       spi1.txLength = 1; //for DMA_SetCurrDataCounter

       for (int i = 0; i < 10; i++) //some test bytes

       { spi1.txBuffer[i] = i+1;}

       SPI_DMA_StartTransaction(&spi1); // my function for set data length and adresses

//--- function SPI_DMA_StartTransaction

bool SPI_DMA_StartTransaction(Spi_t *spi)

{

   // Assert the CS

   GPIO_ResetBits(GPIO_PORT_SPI_RF, RF_CS_PIN);

   DMA_Cmd(spi->dmaRxChannelPtr, DISABLE);

   DMA_Cmd(spi->dmaTxChannelPtr, DISABLE);

   DMA_SetCurrDataCounter(spi->dmaTxChannelPtr, spi->txLength);

   DMA_SetCurrDataCounter(spi->dmaRxChannelPtr, spi->rxLength);

   // Configure the peripheral base address

   spi->dmaTxChannelPtr->CMAR = &spi->txBuffer[0];

   spi->dmaRxChannelPtr->CMAR = &spi->rxBuffer[0];

   DMA_ClearITPendingBit(DMA1_IT_TC2);

   DMA_ClearITPendingBit(DMA1_IT_TC3);

rxStatus = SPI_RUN;

   //---run

   DMA_Cmd(spi->dmaTxChannelPtr, ENABLE);

   DMA_Cmd(spi->dmaRxChannelPtr, ENABLE);

   return true;

}

//--- IRQs

void DMA1_Channel2_IRQHandler(void)

{

   trace_printf("\n\rDMA1_IRQ CH2 %d, %d\n\r", DMA_GetCurrDataCounter(spi1.dmaTxChannelPtr),

   if(DMA_GetITStatus(DMA1_IT_TE2) != RESET)

   {

      DMA_ClearITPendingBit(DMA1_IT_TE2);

      trace_printf("\n\rDMA1_IRQ CH2 - ERROR\n\r");

   }

   if(DMA_GetITStatus(DMA1_IT_TC2) != RESET)

   {

      DMA_ClearITPendingBit(DMA1_IT_TC2);

      rxStatus = SPI_READY;

       /* Disable DMA SPI RX Stream */

       DMA_Cmd(SPI1_DMA_RX_CHANNEL, DISABLE);

         GPIO_SetBits(GPIO_PORT_SPI_RF, RF_CS_PIN);

   }

}

void DMA1_Channel3_IRQHandler(void)

{

   //--- vysilani na SPI1 (SPI1 Tx)

   trace_printf("\n\rDMA1_IRQ CH3 %d, %d\n\r", DMA_GetCurrDataCounter(spi1.dmaTxChannelPtr), DMA_GetCurrDataCounter(spi1.dmaRxChannelPtr));

   if(DMA_GetITStatus(DMA1_IT_TE3) != RESET)

   {

      DMA_ClearITPendingBit(DMA1_IT_TE3);

      trace_printf("\n\rDMA1_IRQ CH3 - ERROR\n\r");

   }

   if(DMA_GetITStatus(DMA1_IT_TC3) != RESET)

   {

      DMA_ClearITPendingBit(DMA1_IT_TC3);

       /* Disable DMA SPI TX Stream */

       DMA_Cmd(SPI1_DMA_TX_CHANNEL, DISABLE);

   }

}

Thank a lot,

Lukas

1 ACCEPTED SOLUTION

Accepted Solutions
LukasPetrus
Associate II

Hi All,

so I solve it by myself 🙂 (I just spent 3 days for to found it :( )

My SPI_Init function uses “SPI_InitTypeDef SPI_InitStructure;�? and “SPI_Init(SPI1, &SPI_InitStructure);�? from stm32f3-stdperiph. This function settings SPIx_CR1 and SPIx_CR2 registers. Unfortunately authors of this driver forgot add to the structure new bit FRXTH (from datasheet:�?This bit is used to set the threshold of the RXFIFO that triggers an RXNE event�?). This bit is cleared by default so trigger of RXNE is 16bit. For one byte I need 8bit so it has to be set.

Function “SPI_RxFIFOThresholdConfig(SPI1, SPI_RxFIFOThreshold_QF);�? solved my problem and all is working fine for me.

Regards,

Lukas

View solution in original post

4 REPLIES 4
S.Ma
Principal

First of all, transfering one byte by DMA seems wrong: DMA registers setup will cost more than direct write of SPI DR. Right?

I think the HAL has mecanism with DMA to shoot half transfer and full transfer callback... no nibble half transfer here?

Otherwise, if you use callback and interrupts, only activate it on the DMA RX because the transaction is fully completed when bytes are received, not when they are about to be sent.

LukasPetrus
Associate II

Hi .

use DMA for one byte is not wrong, because I need function where it doesn't meter how many bytes it sending.

I am not using HAL, still using ST stm32f3-stdperiph. I think it is better as HAL because I can clearly to see which registers are used.

And you are right, interrupt on Rx is sufficient. I have it there only to see if Tx working.

Thank you for your answer.

Lukas

Hi .

use DMA for one byte is not wrong, because I need function where it doesn't meter how many bytes it sending.

I am not using HAL, still using ST stm32f3-stdperiph. I think it is better as HAL because I can clearly to see which registers are used.

And you are right, interrupt on Rx is sufficient. I have it there only to see if Tx working.

Thank you for your answer.

Lukas

LukasPetrus
Associate II

Hi All,

so I solve it by myself 🙂 (I just spent 3 days for to found it :( )

My SPI_Init function uses “SPI_InitTypeDef SPI_InitStructure;�? and “SPI_Init(SPI1, &SPI_InitStructure);�? from stm32f3-stdperiph. This function settings SPIx_CR1 and SPIx_CR2 registers. Unfortunately authors of this driver forgot add to the structure new bit FRXTH (from datasheet:�?This bit is used to set the threshold of the RXFIFO that triggers an RXNE event�?). This bit is cleared by default so trigger of RXNE is 16bit. For one byte I need 8bit so it has to be set.

Function “SPI_RxFIFOThresholdConfig(SPI1, SPI_RxFIFOThreshold_QF);�? solved my problem and all is working fine for me.

Regards,

Lukas