cancel
Showing results for 
Search instead for 
Did you mean: 

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

armco
Associate II

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
10 REPLIES 10
TDK
Guru

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.

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

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).

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

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

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

armco
Associate II

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);

 

 

armco
Associate II

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.

> 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

armco
Associate II
 
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);
}

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