Skip to main content
Visitor II
October 3, 2023
Question

Using timer to trigered SPI DMA Rx could not be received data

  • October 3, 2023
  • 8 replies
  • 2808 views

I want to share my related code and photo here. The program runs on an STM32F746 Nucleo Board.  It uses timer 2 to trigger DMA1 stream 0 causing fixed-length transmission of data via SPI 1 to an external ADC without interrupts on the transmission side. Timer 2 confüguration is settled at 25600Hz this is used as a sample rate. Therefore data must be received with SPI3 every 25600Hz. I created a test pin to understand that the sampling process is finished. The sample size is 64. The complete time is  64 x 1/25600 = 400Hz. I can see this period with diligent oscilloscope but the received data is empty. Can you show me where I'm doing wrong?

Code:

 

SPI_HandleTypeDef hspi3;
DMA_HandleTypeDef hdma_spi3_rx;

TIM_HandleTypeDef htim2;

DMA_HandleTypeDef hdma_tim2_up_ch4;

#define fs (25600)
#define RX_BUFFER_LENGTH (64)

memset(rxBuffer, 0, sizeof(rxBuffer));
txBuffer = 0xFFFF;

// Start SPI RX DMA
hspi3.hdmarx->XferCpltCallback = mySPI_DMAReceiveCplt;
SET_BIT(hspi3.Instance->CR2, SPI_RXFIFO_THRESHOLD);
HAL_GPIO_WritePin(ADC_CS_Pin_GPIO_Port, ADC_CS_Pin_Pin, RESET);
HAL_DMA_Start_IT(hspi3.hdmarx, (uint32_t)&hspi3.Instance->DR, (uint32_t)rxBuffer, RX_BUFFER_LENGTH);
SET_BIT(hspi3.Instance->CR2, SPI_CR2_RXDMAEN);
__HAL_SPI_ENABLE(&hspi3);


// Prepare TIM DMA to SPI_DR

HAL_DMA_Start(htim2.hdma[TIM_DMA_ID_UPDATE], (uint32_t)&txBuffer, (uint32_t)&hspi3.Instance->DR, 1);
__HAL_TIM_ENABLE_DMA(&htim2, TIM_DMA_UPDATE);

// Start the timer
__HAL_TIM_ENABLE(&htim2);

while (1)
{

}

 

static void mySPI_DMAReceiveCplt(DMA_HandleTypeDef *hdma)
{
 
if( hdma == &hdma_spi3_rx )
{
    HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_6);    // IO test pin
}
}
 
WhatsApp Image 2023-10-03 at 14.29.26.jpegWhatsApp Image 2023-10-03 at 14.29.27.jpeg
    This topic has been closed for replies.

    8 replies

    Super User
    October 3, 2023

    Since mySPI_DMAReceiveCplt is being called, something is working right.

    How do you know 0 isn't the correct data in this case? Initialize it to something unique (perhaps a ramp, 0, 1, 2, 3, etc.) and see if it gets changed. (Even if 0 isn't the expected data, it could still be due to a pin misconfigured or disconnected or otherwise.)

    Could also define rxBuffer as volatile, but I doubt that's it.

    armcoAuthor
    Visitor II
    October 3, 2023

    I defined buffer as volatile but there is no change. I can see debugging mode.

    first  I configurated external adc register wrote and read the same register then set it to auto mode and started the sample with spi3.In addition ı don't use nss pin. I use software nss . Cs pin is already low(active).

    Super User
    October 3, 2023

    I don't see how any of that addresses the case where MISO=0, which would explain your results exactly.

    Super User
    October 3, 2023

    Start with polled implementation, that would clarify both MISO=0 as @TDK  said above, and also incorrectly initialized GPIO cases.

    As this is Cortex-M7, also watch out for the caching issues.

    JW

    Graduate II
    October 4, 2023

    As this is Cortex-M7, also watch out for the caching issues.


    Not only they don't read manuals, but, of course, they also ignore most of what is told them individually...

    Also, how about:

    1. Posting a code as a proper code block.
    2. Posting long pieces of code as an attached file.
    3. Posting a screenshots as an actual screenshots instead of a "photographed monitor" images.
    armcoAuthor
    Visitor II
    October 4, 2023

    I controlled initialization SPI3,DMA. 

    // SPI configuration, I check the spi with external adc doing write and read register.

    void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
    {
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    if(hspi->Instance==SPI3)
    {
    /* USER CODE BEGIN SPI3_MspInit 0 */

    /* USER CODE END SPI3_MspInit 0 */
    /* Peripheral clock enable */
    __HAL_RCC_SPI3_CLK_ENABLE();

    __HAL_RCC_GPIOB_CLK_ENABLE();
    __HAL_RCC_GPIOC_CLK_ENABLE();
    /**SPI3 GPIO Configuration
    PB2 ------> SPI3_MOSI
    PC10 ------> SPI3_SCK
    PC11 ------> SPI3_MISO
    */
    GPIO_InitStruct.Pin = GPIO_PIN_2;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF7_SPI3;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_11;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF6_SPI3;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

    /* SPI3 DMA Init */
    /* SPI3_RX Init */
    hdma_spi3_rx.Instance = DMA1_Stream0;
    hdma_spi3_rx.Init.Channel = DMA_CHANNEL_0;
    hdma_spi3_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_spi3_rx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_spi3_rx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_spi3_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
    hdma_spi3_rx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
    hdma_spi3_rx.Init.Mode = DMA_CIRCULAR;
    hdma_spi3_rx.Init.Priority = DMA_PRIORITY_LOW;
    hdma_spi3_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    if (HAL_DMA_Init(&hdma_spi3_rx) != HAL_OK)
    {
    Error_Handler();
    }

    __HAL_LINKDMA(hspi,hdmarx,hdma_spi3_rx);

    /* USER CODE BEGIN SPI3_MspInit 1 */

    /* USER CODE END SPI3_MspInit 1 */
    }

    }

    // This case is triggered the dma , it is correct because we can see the image that 405Hz toggle pin.

    void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base)
    {
    if(htim_base->Instance==TIM2)
    {
    /* USER CODE BEGIN TIM2_MspInit 0 */

    /* USER CODE END TIM2_MspInit 0 */
    /* Peripheral clock enable */
    __HAL_RCC_TIM2_CLK_ENABLE();

    /* TIM2 DMA Init */
    /* TIM2_UP_CH4 Init */
    hdma_tim2_up_ch4.Instance = DMA1_Stream7;
    hdma_tim2_up_ch4.Init.Channel = DMA_CHANNEL_3;
    hdma_tim2_up_ch4.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_tim2_up_ch4.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_tim2_up_ch4.Init.MemInc = DMA_MINC_ENABLE;
    hdma_tim2_up_ch4.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
    hdma_tim2_up_ch4.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
    hdma_tim2_up_ch4.Init.Mode = DMA_CIRCULAR;
    hdma_tim2_up_ch4.Init.Priority = DMA_PRIORITY_LOW;
    hdma_tim2_up_ch4.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    if (HAL_DMA_Init(&hdma_tim2_up_ch4) != HAL_OK)
    {
    Error_Handler();
    }

    /* Several peripheral DMA handle pointers point to the same DMA handle.
    Be aware that there is only one stream to perform all the requested DMAs. */
    __HAL_LINKDMA(htim_base,hdma[TIM_DMA_ID_UPDATE],hdma_tim2_up_ch4);
    __HAL_LINKDMA(htim_base,hdma[TIM_DMA_ID_CC4],hdma_tim2_up_ch4);

    /* USER CODE BEGIN TIM2_MspInit 1 */

    /* USER CODE END TIM2_MspInit 1 */
    }

    }

    // Startin process


    memset(rxBuffer, 0, sizeof(rxBuffer));
    txBuffer = 0xFFFF;

    // Start SPI RX DMA
    // hspi3.hdmarx->XferHalfCpltCallback = mySPI_DMAHalfReceiveCplt;
    hspi3.hdmarx->XferCpltCallback = mySPI_DMAReceiveCplt;
    SET_BIT(hspi3.Instance->CR2, SPI_RXFIFO_THRESHOLD);
    HAL_GPIO_WritePin(ADC_CS_Pin_GPIO_Port, ADC_CS_Pin_Pin, RESET);
    HAL_DMA_Start_IT(hspi3.hdmarx, (uint32_t)&hspi3.Instance->DR, (uint32_t)rxBuffer, RX_BUFFER_LENGTH);
    SET_BIT(hspi3.Instance->CR2, SPI_CR2_RXDMAEN);
    __HAL_SPI_ENABLE(&hspi3);


    // Prepare TIM DMA to SPI_DR

    HAL_DMA_Start(htim2.hdma[TIM_DMA_ID_UPDATE], (uint32_t)&txBuffer, (uint32_t)&hspi3.Instance->DR, 1);
    __HAL_TIM_ENABLE_DMA(&htim2, TIM_DMA_UPDATE);

    // Start the timer
    __HAL_TIM_ENABLE(&htim2);

     

     

    armcoAuthor
    Visitor II
    October 4, 2023

    The error comes from triggering the SPI NSS pin.
    First, I performed Hardware output Nss and saw that it did not write or read the register return value was 0. After Hardware I canceled NSS and turned it on and off with software. I wrote to the registers and read the correct data, but I could not read adc value. The problem right now is that I need to turn the CS pin on and off while receiving data via dma.

    Super User
    October 4, 2023

    > The problem right now is that I need to turn the CS pin on and off while receiving data via dma.

    How? Show some timing diagram.

    JW

    armcoAuthor
    Visitor II
    October 4, 2023
     
    ADC_Info.PNGADC_W_R_Command.PNG
     
    When i  use manual CS (SSM =1, software slave management)  i can read data that I wrote the register but i use hardware use it doesn't work. I make debugging i see received data "0" because of time out.
    I don't understand why cs not work with Hardware NSS output enabled. I will look into this issue.
     
     
     
     
    uint8_t Self_Control(uint8_t addres,uint8_t data)
    {
     
    uint16_t send_data = 0;
    uint16_t recv_data = 0;
    uint8_t tempL =0;
    uint8_t tempH =0;
    tempH = ((addres)<< 1);
    tempL = (data);
     
    send_data = (tempH<<8) | tempL;
    // Transmit
    //HAL_GPIO_WritePin(ADC_CS_Pin_GPIO_Port, ADC_CS_Pin_Pin, RESET);
    HAL_SPI_Transmit(&hspi1, (uint8_t*)&send_data, 1, 100);
    //HAL_GPIO_WritePin(ADC_CS_Pin_GPIO_Port, ADC_CS_Pin_Pin, SET);
    // Receive
     
    //HAL_Delay(100);
    tempH = 0;
    tempL = 0;
    tempH = (((addres)<< 1) | (1 << 0));
    tempL = 0x00;
    send_data = (tempH<<8) |tempL ;
     
     
     
    //HAL_GPIO_WritePin(ADC_CS_Pin_GPIO_Port, ADC_CS_Pin_Pin, RESET);
    HAL_SPI_TransmitReceive(&hspi1, (uint8_t*)&send_data, (uint8_t*)&recv_data, 1,100);
    //HAL_GPIO_WritePin(ADC_CS_Pin_GPIO_Port, ADC_CS_Pin_Pin, SET);
     
    return (uint8_t)(recv_data & 0xff);
    }
    Super User
    October 4, 2023

    Check out NSS pulse mode:

    waclawekjan_0-1696431776087.png

    Note that CPHA must be 0. Check with the slave's datasheet if this is viable.

    I don't use Cube/CubeMX so don't know how to click this in CubeMX or what Cube/HAL incantations lead to this being properly used.

    JW