cancel
Showing results for 
Search instead for 
Did you mean: 

SPI + DMA using LL Library

Srinath_03
Senior

Hi,

I'm using stm32h7, currently working with SPI + DMA in HAL library, because of HAL overhead I want to move to LL library,

where can I get the SPI+DMA using LL library examples,

regards,

Srinath

1 ACCEPTED SOLUTION

Accepted Solutions
lobna
ST Employee

Dear @Srinath_03 

You can find one example using SPI and DMA LL:  "SPI_OneBoard_HalfDuplex_DMA_Init"

this git hub link:

BR

Lobna

View solution in original post

5 REPLIES 5
lobna
ST Employee

Dear @Srinath_03 

You can find one example using SPI and DMA LL:  "SPI_OneBoard_HalfDuplex_DMA_Init"

this git hub link:

BR

Lobna

Hi @lobna  thanks

is SPI+DMA circular mode using LL library is available.

and I have a doubt, as of now I'm doing SPI+DMA in normal mode, and using two SPI, i want to run both the SPI parallelly. so after every transfer im clearing the flag and reenabling again for spi transfer in normal. this process is taking alomst 9 to 10us, how to reduce this process. so im starting SPI transfer at every 100us with tim7 interrupt.

Srinath_03_0-1766577486199.png

you can see the image yellow is start of spi , blue and pink is two spi clocks, both the spi almost start at same time with some ns delay.

so you can see in the image after calling activate spi function to SPI clock starting it is taking almost 10us, below i have attached the code for activate spi. so how to reduce this start time in normal mode

below i have attached the code, so to reduce the time to 2us, 

in spi circular mode overall it is 7.7us , including the SPI transfer complete callback. 

actually in the below code circular mode configuration are enabled and normal are disabled

 

/*

/* USER CODE BEGIN Header */

/**

 ******************************************************************************

 * @file : main.c

 * @brief : Main program body

 ******************************************************************************

 * @attention

 *

 * Copyright (c) 2025 STMicroelectronics.

 * All rights reserved.

 *

 * This software is licensed under terms that can be found in the LICENSE file

 * in the root directory of this software component.

 * If no LICENSE file comes with this software, it is provided AS-IS.

 *

 ******************************************************************************

 */

/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/

#include "main.h"

#include "dma.h"

#include "spi.h"

#include "tim.h"

#include "gpio.h"



/* Private includes ----------------------------------------------------------*/

/* USER CODE BEGIN Includes */

#include "stm32h7xx.h"

#include "stm32h7xx_ll_dmamux.h"

#include <string.h>

/* USER CODE END Includes */



/* Private typedef -----------------------------------------------------------*/

/* USER CODE BEGIN PTD */



/* USER CODE END PTD */



/* Private define ------------------------------------------------------------*/

/* USER CODE BEGIN PD */

#define ADS_DATA_SIZE 16U

/* DUAL_CORE_BOOT_SYNC_SEQUENCE: Define for dual core boot synchronization */

/* demonstration code based on hardware semaphore */

/* This define is present in both CM7/CM4 projects */

/* To comment when developping/debugging on a single core */

#define DUAL_CORE_BOOT_SYNC_SEQUENCE



#if defined(DUAL_CORE_BOOT_SYNC_SEQUENCE)

#ifndef HSEM_ID_0

#define HSEM_ID_0 (0U) /* HW semaphore 0*/

#endif

#endif /* DUAL_CORE_BOOT_SYNC_SEQUENCE */



/* USER CODE END PD */



/* Private macro -------------------------------------------------------------*/

/* USER CODE BEGIN PM */



/* USER CODE END PM */



/* Private variables ---------------------------------------------------------*/



/* USER CODE BEGIN PV */

uint8_t ADS_NULL_VOLT_TX[ADS_DATA_SIZE] ={ \

 0x12, 0x12, 0x12, 0x12,

 0x12, 0x12, 0x12, 0x12,

 0x12, 0x12, 0x12, 0x12,

 0x12, 0x12, 0x12, 0x12

};



uint8_t ADS_DATA_VOLT_RX[ADS_DATA_SIZE];



uint8_t ADS_NULL_CURR_TX[ADS_DATA_SIZE] = {

 0x12, 0x12, 0x12, 0x12,

 0x12, 0x12, 0x12, 0x12,

 0x12, 0x12, 0x12, 0x12,

 0x12, 0x12, 0x12, 0x12

};



uint8_t ADS_DATA_CURR_RX[ADS_DATA_SIZE];

//static uint8_t copy[16];





volatile uint8_t spi2_done = 1;

volatile uint8_t spi3_done = 0;

volatile uint8_t both_spi_done = 1;

volatile uint8_t spi_start_req = 0;



static volatile uint32_t HW_timer_counter_32us;

static volatile uint32_t CNT1,CNT =0;

/* USER CODE END PV */



/* Private function prototypes -----------------------------------------------*/

/* USER CODE BEGIN PFP */

void DMA_CONFIGURE(void);

void Activate_SPI(void);

void Activate_SPI_once(void);

/* USER CODE END PFP */



/* Private user code ---------------------------------------------------------*/

/* USER CODE BEGIN 0 */



/* USER CODE END 0 */



/**

 * @brief The application entry point.

 * @retval int

 */

int main(void)

{



/* USER CODE BEGIN 1 */



/* USER CODE END 1 */



/* USER CODE BEGIN Boot_Mode_Sequence_1 */

#if defined(DUAL_CORE_BOOT_SYNC_SEQUENCE)

/*HW semaphore Clock enable*/

 __HAL_RCC_HSEM_CLK_ENABLE();

/* Activate HSEM notification for Cortex-M4*/

HAL_HSEM_ActivateNotification(__HAL_HSEM_SEMID_TO_MASK(HSEM_ID_0));

/*

 Domain D2 goes to STOP mode (Cortex-M4 in deep-sleep) waiting for Cortex-M7 to

 perform system initialization (system clock config, external memory configuration.. )

 */

HAL_PWREx_ClearPendingEvent();

HAL_PWREx_EnterSTOPMode(PWR_MAINREGULATOR_ON, PWR_STOPENTRY_WFE, PWR_D2_DOMAIN);

/* Clear HSEM flag */

 __HAL_HSEM_CLEAR_FLAG(__HAL_HSEM_SEMID_TO_MASK(HSEM_ID_0));



#endif /* DUAL_CORE_BOOT_SYNC_SEQUENCE */

/* USER CODE END Boot_Mode_Sequence_1 */

/* MCU Configuration--------------------------------------------------------*/



/* Reset of all peripherals, Initializes the Flash interface and the Systick. */

HAL_Init();



/* USER CODE BEGIN Init */



/* USER CODE END Init */



/* USER CODE BEGIN SysInit */



/* USER CODE END SysInit */



/* Initialize all configured peripherals */

 MX_GPIO_Init();

 MX_DMA_Init();

 MX_SPI2_Init();

 MX_TIM7_Init();

 MX_SPI3_Init();

/* USER CODE BEGIN 2 */



 DMA_CONFIGURE();

// Activate_SPI_once();

HAL_Delay(1);

HAL_TIM_Base_Start_IT(&htim7);

/* USER CODE END 2 */



/* Infinite loop */

/* USER CODE BEGIN WHILE */

while (1)

 {

/* USER CODE END WHILE */



/* USER CODE BEGIN 3 */

// if (spi_start_req)

// {

// spi_start_req = 0;

// Activate_SPI();

// }

 }

/* USER CODE END 3 */

}



/* USER CODE BEGIN 4 */

void DMA_CONFIGURE(void)

{

// LL_DMA_ConfigTransfer(DMA2,

// LL_DMA_STREAM_1,

// LL_DMA_DIRECTION_MEMORY_TO_PERIPH | LL_DMA_PRIORITY_VERYHIGH | LL_DMA_MODE_NORMAL |

// LL_DMA_PERIPH_NOINCREMENT | LL_DMA_MEMORY_INCREMENT |

// LL_DMA_PDATAALIGN_BYTE | LL_DMA_MDATAALIGN_BYTE);

// LL_DMA_ConfigAddresses(DMA2,

// LL_DMA_STREAM_1,

// (uint32_t)ADS_NULL_VOLT_TX, (uint32_t) &(SPI2->TXDR),

// LL_DMA_GetDataTransferDirection(DMA2, LL_DMA_STREAM_1));

// LL_DMA_SetDataLength(DMA2, LL_DMA_STREAM_1, ADS_DATA_SIZE);

//

//

// LL_DMA_SetPeriphRequest(DMA2, LL_DMA_STREAM_1, LL_DMAMUX1_REQ_SPI2_TX);

//

//

// /* Configure the DMA1_Channel1 functional parameters */

// LL_DMA_ConfigTransfer(DMA2,

// LL_DMA_STREAM_0,

// LL_DMA_DIRECTION_PERIPH_TO_MEMORY | LL_DMA_PRIORITY_VERYHIGH | LL_DMA_MODE_NORMAL |

// LL_DMA_PERIPH_NOINCREMENT | LL_DMA_MEMORY_INCREMENT |

// LL_DMA_PDATAALIGN_BYTE | LL_DMA_MDATAALIGN_BYTE);

// LL_DMA_ConfigAddresses(DMA2, LL_DMA_STREAM_0,(uint32_t) &(SPI2->RXDR), (uint32_t)ADS_DATA_VOLT_RX,

// LL_DMA_GetDataTransferDirection(DMA2, LL_DMA_STREAM_0));

// LL_DMA_SetDataLength(DMA2, LL_DMA_STREAM_0, ADS_DATA_SIZE);

// LL_DMA_SetPeriphRequest(DMA2, LL_DMA_STREAM_0, LL_DMAMUX1_REQ_SPI2_RX);

//

//

// /* Enable DMA interrupts complete/error */

// LL_DMA_EnableIT_TC(DMA2, LL_DMA_STREAM_0);

// LL_DMA_EnableIT_TE(DMA2, LL_DMA_STREAM_0);

//// LL_DMA_EnableIT_TC(DMA2, LL_DMA_STREAM_1);

//// LL_DMA_EnableIT_TE(DMA2, LL_DMA_STREAM_1);

//

// /* Initialize FFIFO Threshold */

//

//

// /* Configure SPI1 DMA transfer interrupts */

// /* Enable DMA TX Interrupt */

// LL_SPI_EnableDMAReq_TX(SPI2);

//

// /* Configure SPI1 DMA transfer interrupts */

// /* Enable DMA RX Interrupt */

// LL_SPI_EnableDMAReq_RX(SPI2);

//

////SPI3

// LL_DMA_ConfigTransfer(DMA2,

// LL_DMA_STREAM_3,

// LL_DMA_DIRECTION_MEMORY_TO_PERIPH | LL_DMA_PRIORITY_VERYHIGH | LL_DMA_MODE_NORMAL |

// LL_DMA_PERIPH_NOINCREMENT | LL_DMA_MEMORY_INCREMENT |

// LL_DMA_PDATAALIGN_BYTE | LL_DMA_MDATAALIGN_BYTE);

// LL_DMA_ConfigAddresses(DMA2,

// LL_DMA_STREAM_3,

// (uint32_t)ADS_NULL_CURR_TX, (uint32_t) &(SPI3->TXDR),

// LL_DMA_GetDataTransferDirection(DMA2, LL_DMA_STREAM_3));

// LL_DMA_SetDataLength(DMA2, LL_DMA_STREAM_3, ADS_DATA_SIZE);

//

//

// LL_DMA_SetPeriphRequest(DMA2, LL_DMA_STREAM_3, LL_DMAMUX1_REQ_SPI3_TX);

//

//

// /* Configure the DMA1_Channel1 functional parameters */

// LL_DMA_ConfigTransfer(DMA2,

// LL_DMA_STREAM_2,

// LL_DMA_DIRECTION_PERIPH_TO_MEMORY | LL_DMA_PRIORITY_VERYHIGH | LL_DMA_MODE_NORMAL |

// LL_DMA_PERIPH_NOINCREMENT | LL_DMA_MEMORY_INCREMENT |

// LL_DMA_PDATAALIGN_BYTE | LL_DMA_MDATAALIGN_BYTE);

// LL_DMA_ConfigAddresses(DMA2, LL_DMA_STREAM_2,(uint32_t) &(SPI3->RXDR), (uint32_t)ADS_DATA_CURR_RX,

// LL_DMA_GetDataTransferDirection(DMA2, LL_DMA_STREAM_2));

// LL_DMA_SetDataLength(DMA2, LL_DMA_STREAM_2, ADS_DATA_SIZE);

// LL_DMA_SetPeriphRequest(DMA2, LL_DMA_STREAM_2, LL_DMAMUX1_REQ_SPI3_RX);

//

//

// /* Enable DMA interrupts complete/error */

// LL_DMA_EnableIT_TC(DMA2, LL_DMA_STREAM_2);

// LL_DMA_EnableIT_TE(DMA2, LL_DMA_STREAM_2);

// // LL_DMA_EnableIT_TC(DMA2, LL_DMA_STREAM_1);

// // LL_DMA_EnableIT_TE(DMA2, LL_DMA_STREAM_1);

//

// /* Initialize FFIFO Threshold */

//

//

// /* Configure SPI1 DMA transfer interrupts */

// /* Enable DMA TX Interrupt */

// LL_SPI_EnableDMAReq_TX(SPI3);

//

// /* Configure SPI1 DMA transfer interrupts */

// /* Enable DMA RX Interrupt */

// LL_SPI_EnableDMAReq_RX(SPI3);

//





/* circulAR mode */

 LL_DMA_ConfigTransfer(DMA2,

 LL_DMA_STREAM_1,

 LL_DMA_DIRECTION_MEMORY_TO_PERIPH | LL_DMA_PRIORITY_VERYHIGH | LL_DMA_MODE_CIRCULAR |

 LL_DMA_PERIPH_NOINCREMENT | LL_DMA_MEMORY_INCREMENT |

 LL_DMA_PDATAALIGN_BYTE | LL_DMA_MDATAALIGN_BYTE);

 LL_DMA_ConfigAddresses(DMA2,

 LL_DMA_STREAM_1,

 (uint32_t)ADS_NULL_VOLT_TX, (uint32_t) &(SPI2->TXDR),

 LL_DMA_GetDataTransferDirection(DMA2, LL_DMA_STREAM_1));

 LL_DMA_SetDataLength(DMA2, LL_DMA_STREAM_1, ADS_DATA_SIZE);





 LL_DMA_SetPeriphRequest(DMA2, LL_DMA_STREAM_1, LL_DMAMUX1_REQ_SPI2_TX);





/* Configure the DMA1_Channel1 functional parameters */

 LL_DMA_ConfigTransfer(DMA2,

 LL_DMA_STREAM_0,

 LL_DMA_DIRECTION_PERIPH_TO_MEMORY | LL_DMA_PRIORITY_VERYHIGH | LL_DMA_MODE_CIRCULAR |

 LL_DMA_PERIPH_NOINCREMENT | LL_DMA_MEMORY_INCREMENT |

 LL_DMA_PDATAALIGN_BYTE | LL_DMA_MDATAALIGN_BYTE);

 LL_DMA_ConfigAddresses(DMA2, LL_DMA_STREAM_0,(uint32_t) &(SPI2->RXDR), (uint32_t)ADS_DATA_VOLT_RX,

 LL_DMA_GetDataTransferDirection(DMA2, LL_DMA_STREAM_0));

 LL_DMA_SetDataLength(DMA2, LL_DMA_STREAM_0, ADS_DATA_SIZE);

 LL_DMA_SetPeriphRequest(DMA2, LL_DMA_STREAM_0, LL_DMAMUX1_REQ_SPI2_RX);





/* Enable DMA interrupts complete/error */

 LL_DMA_EnableIT_TC(DMA2, LL_DMA_STREAM_0);

 LL_DMA_EnableIT_TE(DMA2, LL_DMA_STREAM_0);

// LL_DMA_EnableIT_TC(DMA2, LL_DMA_STREAM_1);

// LL_DMA_EnableIT_TE(DMA2, LL_DMA_STREAM_1);



/* Initialize FFIFO Threshold */





/* Configure SPI1 DMA transfer interrupts */

/* Enable DMA TX Interrupt */

 LL_SPI_EnableDMAReq_TX(SPI2);



/* Configure SPI1 DMA transfer interrupts */

/* Enable DMA RX Interrupt */

 LL_SPI_EnableDMAReq_RX(SPI2);



 LL_DMA_EnableStream(DMA2, LL_DMA_STREAM_0); // RX

 LL_DMA_EnableStream(DMA2, LL_DMA_STREAM_1); // TX





 LL_DMA_ConfigTransfer(DMA2,

 LL_DMA_STREAM_3,

 LL_DMA_DIRECTION_MEMORY_TO_PERIPH | LL_DMA_PRIORITY_VERYHIGH | LL_DMA_MODE_CIRCULAR |

 LL_DMA_PERIPH_NOINCREMENT | LL_DMA_MEMORY_INCREMENT |

 LL_DMA_PDATAALIGN_BYTE | LL_DMA_MDATAALIGN_BYTE);

 LL_DMA_ConfigAddresses(DMA2,

 LL_DMA_STREAM_3,

 (uint32_t)ADS_NULL_CURR_TX, (uint32_t) &(SPI3->TXDR),

 LL_DMA_GetDataTransferDirection(DMA2, LL_DMA_STREAM_3));

 LL_DMA_SetDataLength(DMA2, LL_DMA_STREAM_3, ADS_DATA_SIZE);





 LL_DMA_SetPeriphRequest(DMA2, LL_DMA_STREAM_3, LL_DMAMUX1_REQ_SPI3_TX);





/* Configure the DMA1_Channel1 functional parameters */

 LL_DMA_ConfigTransfer(DMA2,

 LL_DMA_STREAM_2,

 LL_DMA_DIRECTION_PERIPH_TO_MEMORY | LL_DMA_PRIORITY_VERYHIGH | LL_DMA_MODE_CIRCULAR |

 LL_DMA_PERIPH_NOINCREMENT | LL_DMA_MEMORY_INCREMENT |

 LL_DMA_PDATAALIGN_BYTE | LL_DMA_MDATAALIGN_BYTE);

 LL_DMA_ConfigAddresses(DMA2, LL_DMA_STREAM_2,(uint32_t) &(SPI3->RXDR), (uint32_t)ADS_DATA_CURR_RX,

 LL_DMA_GetDataTransferDirection(DMA2, LL_DMA_STREAM_2));

 LL_DMA_SetDataLength(DMA2, LL_DMA_STREAM_2, ADS_DATA_SIZE);

 LL_DMA_SetPeriphRequest(DMA2, LL_DMA_STREAM_2, LL_DMAMUX1_REQ_SPI3_RX);





/* Enable DMA interrupts complete/error */

 LL_DMA_EnableIT_TC(DMA2, LL_DMA_STREAM_2);

 LL_DMA_EnableIT_TE(DMA2, LL_DMA_STREAM_2);

// LL_DMA_EnableIT_TC(DMA2, LL_DMA_STREAM_1);

// LL_DMA_EnableIT_TE(DMA2, LL_DMA_STREAM_1);



/* Initialize FFIFO Threshold */





/* Configure SPI1 DMA transfer interrupts */

/* Enable DMA TX Interrupt */

 LL_SPI_EnableDMAReq_TX(SPI3);



/* Configure SPI1 DMA transfer interrupts */

/* Enable DMA RX Interrupt */

 LL_SPI_EnableDMAReq_RX(SPI3);



 LL_DMA_EnableStream(DMA2, LL_DMA_STREAM_2); // RX

 LL_DMA_EnableStream(DMA2, LL_DMA_STREAM_3); // TX







}



void Activate_SPI(void)

{

// /* Disable SPI */

// LL_SPI_Disable(SPI2);

// LL_SPI_Disable(SPI3);

//

// /* Disable DMA */

// LL_DMA_DisableStream(DMA2, LL_DMA_STREAM_0); // RX

// LL_DMA_DisableStream(DMA2, LL_DMA_STREAM_1); // TX

// LL_DMA_DisableStream(DMA2, LL_DMA_STREAM_2); // RX

// LL_DMA_DisableStream(DMA2, LL_DMA_STREAM_3); // TX

//

// /* WAIT for DMA disable (CRITICAL on H7) */

// while (LL_DMA_IsEnabledStream(DMA2, LL_DMA_STREAM_0))

// {

// __NOP();

// }

// while (LL_DMA_IsEnabledStream(DMA2, LL_DMA_STREAM_1))

// {

// __NOP();

// }

//

// while (LL_DMA_IsEnabledStream(DMA2, LL_DMA_STREAM_2))

// {

// __NOP();

// }

// while (LL_DMA_IsEnabledStream(DMA2, LL_DMA_STREAM_3))

// {

// __NOP();

// }

//

// /* Clear DMA flags */

// LL_DMA_ClearFlag_TC0(DMA2);

// LL_DMA_ClearFlag_TE0(DMA2);

// LL_DMA_ClearFlag_TC1(DMA2);

// LL_DMA_ClearFlag_TE1(DMA2);

// LL_DMA_ClearFlag_TC2(DMA2);

// LL_DMA_ClearFlag_TE2(DMA2);

// LL_DMA_ClearFlag_TC3(DMA2);

// LL_DMA_ClearFlag_TE3(DMA2);

//

// /* Clear DMAMUX overrun */

// LL_DMAMUX_ClearFlag_SO15(DMAMUX1);

//

// /* Reload NDTR */

// LL_DMA_SetDataLength(DMA2, LL_DMA_STREAM_0, ADS_DATA_SIZE);

// LL_DMA_SetDataLength(DMA2, LL_DMA_STREAM_1, ADS_DATA_SIZE);

// LL_DMA_SetDataLength(DMA2, LL_DMA_STREAM_2, ADS_DATA_SIZE);

// LL_DMA_SetDataLength(DMA2, LL_DMA_STREAM_3, ADS_DATA_SIZE);

//

// /* Enable DMA streams */

// LL_DMA_EnableStream(DMA2, LL_DMA_STREAM_0);

// LL_DMA_EnableStream(DMA2, LL_DMA_STREAM_1);

// LL_DMA_EnableStream(DMA2, LL_DMA_STREAM_2);

// LL_DMA_EnableStream(DMA2, LL_DMA_STREAM_3);

//

// /* Enable SPI DMA requests */

// LL_SPI_EnableDMAReq_RX(SPI2);

// LL_SPI_EnableDMAReq_TX(SPI2);

// LL_SPI_EnableDMAReq_RX(SPI3);

// LL_SPI_EnableDMAReq_TX(SPI3);

//

//

// /* Enable SPI */

// LL_SPI_Enable(SPI2);

// LL_SPI_Enable(SPI3);

//

// /* Start transfer */

// LL_SPI_StartMasterTransfer(SPI2);

// LL_SPI_StartMasterTransfer(SPI3);

//







// CIRCULAR MODE//

// /* Enable SPI DMA requests (safe every time) */

 LL_SPI_EnableDMAReq_RX(SPI2);

 LL_SPI_EnableDMAReq_TX(SPI2);

 LL_SPI_EnableDMAReq_RX(SPI3);

 LL_SPI_EnableDMAReq_TX(SPI3);

/* Enable SPI */

 LL_SPI_Enable(SPI2);

 LL_SPI_Enable(SPI3);



/* Start clocking */

 LL_SPI_StartMasterTransfer(SPI2);

 LL_SPI_StartMasterTransfer(SPI3);

}



void Activate_SPI_once(void)

{

/* Ensure SPI disabled */

 LL_SPI_Disable(SPI2);

 LL_SPI_Disable(SPI3);



/* Clear DMA flags ONCE */

 LL_DMA_ClearFlag_TC0(DMA2);

 LL_DMA_ClearFlag_TC1(DMA2);

 LL_DMA_ClearFlag_TC2(DMA2);

 LL_DMA_ClearFlag_TC3(DMA2);



/* Set initial NDTR */

 LL_DMA_SetDataLength(DMA2, LL_DMA_STREAM_0, ADS_DATA_SIZE);

 LL_DMA_SetDataLength(DMA2, LL_DMA_STREAM_1, ADS_DATA_SIZE);

 LL_DMA_SetDataLength(DMA2, LL_DMA_STREAM_2, ADS_DATA_SIZE);

 LL_DMA_SetDataLength(DMA2, LL_DMA_STREAM_3, ADS_DATA_SIZE);



/* Enable SPI DMA requests ONCE */

 LL_SPI_EnableDMAReq_RX(SPI2);

 LL_SPI_EnableDMAReq_TX(SPI2);

 LL_SPI_EnableDMAReq_RX(SPI3);

 LL_SPI_EnableDMAReq_TX(SPI3);



/* Enable SPI ONCE */

 LL_SPI_Enable(SPI2);

 LL_SPI_Enable(SPI3);

}

void DMA1_ReceiveComplete_Callback(void)

{

 spi2_done = 1;

if (spi3_done)

 {

 both_spi_done = 1;

 }



 CNT++;





}



void DMA2_ReceiveComplete_Callback(void)

{



 spi3_done = 1;

if (spi2_done)

 {

 both_spi_done = 1;

 }

//memcpy(copy, ADS_DATA_VOLT_RX, 16);

HAL_GPIO_WritePin(TIMER_GPIO_Port,TIMER_Pin ,0);

 CNT1++;



}



void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)

{

 HW_timer_counter_32us++;





if(htim == &htim7)

 {

//HAL_GPIO_TogglePin(TIMER_GPIO_Port, TIMER_Pin);

HAL_GPIO_WritePin(TIMER_GPIO_Port,TIMER_Pin ,1);



if(both_spi_done == 1)

 {



 spi2_done = 0;

 spi3_done = 0;

 both_spi_done =0;



 Activate_SPI();

//spi_start_req = 1;

 }



 }



}

/* USER CODE END 4 */



/**

 * @brief This function is executed in case of error occurrence.

 * @retval None

 */

void Error_Handler(void)

{

/* USER CODE BEGIN Error_Handler_Debug */

/* User can add his own implementation to report the HAL error return state */

 __disable_irq();

while (1)

 {

 }

/* USER CODE END Error_Handler_Debug */

}

#ifdef USE_FULL_ASSERT

/**

 * @brief Reports the name of the source file and the source line number

 * where the assert_param error has occurred.

 * @param file: pointer to the source file name

 * @param line: assert_param error line source number

 * @retval None

 */

void assert_failed(uint8_t *file, uint32_t line)

{

/* USER CODE BEGIN 6 */

/* User can add his own implementation to report the file name and line number,

ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */

/* USER CODE END 6 */

}

#endif /* USE_FULL_ASSERT */

void DMA2_Stream0_IRQHandler(void)

{

/* USER CODE BEGIN DMA2_Stream0_IRQn 0 */



/* USER CODE END DMA2_Stream0_IRQn 0 */

/* USER CODE BEGIN DMA2_Stream0_IRQn 1 */

if (LL_DMA_IsActiveFlag_TC0(DMA2))

 {

 LL_DMA_ClearFlag_TC0(DMA2);

 LL_SPI_Disable(SPI2);



 DMA1_ReceiveComplete_Callback();

 }





if (LL_DMA_IsActiveFlag_TE0(DMA2))

 {

 LL_DMA_ClearFlag_TE0(DMA2);



 }





/* USER CODE END DMA2_Stream0_IRQn 1 */

}

void DMA2_Stream2_IRQHandler(void)

{

/* USER CODE BEGIN DMA2_Stream2_IRQn 0 */



/* USER CODE END DMA2_Stream2_IRQn 0 */

/* USER CODE BEGIN DMA2_Stream2_IRQn 1 */

if (LL_DMA_IsActiveFlag_TC2(DMA2))

 {

 LL_DMA_ClearFlag_TC2(DMA2);

 LL_SPI_Disable(SPI3);



 DMA2_ReceiveComplete_Callback();

 }





if (LL_DMA_IsActiveFlag_TE2(DMA2))

 {

 LL_DMA_ClearFlag_TE2(DMA2);



 }





/* USER CODE END DMA2_Stream2_IRQn 1 */

}




 

 

Dear @Srinath_03 

Here are some suggestions to improve the execution time:

1- In your DMA IRQ handlers (e.g., DMA2_Stream0_IRQHandler), you disable the SPI peripheral (e.g., LL_SPI_Disable(SPI2)), which is not recommended in circular mode because it introduces delays and stops the communication.
Suggestion: Do not disable SPI inside the DMA callbacks; instead, let SPI and DMA run continuously. The same applies to SPI3 in DMA2_Stream2_IRQHandler.

2- Minimize the code executed inside DMA interrupt callbacks to reduce latency. Use simple flags to indicate transfer completion without calling heavy or blocking functions.

3- Optimize buffer access by treating DMA RX buffers as read-only in the main loop or timer callback. In the timer callback, only read (e.g., using memcpy function) the DMA RX buffers (ADS_DATA_VOLT_RX, ADS_DATA_CURR_RX) into local buffers for further processing. Never write directly into the DMA RX buffers.
Process the copied data outside the interrupt context (e.g., in the main loop or a dedicated task).

Best regards,
Lobna

Srinath_03
Senior

Hi @lobna Thanks, 

with circular mode no problem, with respect to SPI speed of 25MHz for 16bytes taking almost 7. 7us. I'm asking for normal mode DMA, so in normal mode clearing the flags, data length and starting transfer again for both the spi parallelly, so this is taking almost 9us for starting of spi clock itself and finishing it is almost taking overall one complete transfer complete 15us.

so how to reduce this initial 9us starting, is there any other way to reduce this to 2us. the Activate_SPI function this calling in every 100us timer interrupt

so basically, in normal mode with LL library how to start the next transfer, with only less time, 

below again I have attached the code for normal mode DMA

void Activate_SPI(void)
{
	 /* Disable SPI */
	    LL_SPI_Disable(SPI2);
	    LL_SPI_Disable(SPI3);

	    /* Disable DMA */
	    LL_DMA_DisableStream(DMA2, LL_DMA_STREAM_0); // RX
	    LL_DMA_DisableStream(DMA2, LL_DMA_STREAM_1); // TX
	    LL_DMA_DisableStream(DMA2, LL_DMA_STREAM_2); // RX
	    LL_DMA_DisableStream(DMA2, LL_DMA_STREAM_3); // TX

	    /* WAIT for DMA disable (CRITICAL on H7) */
	    while (LL_DMA_IsEnabledStream(DMA2, LL_DMA_STREAM_0))
	    {
	    	 __NOP();
	    }
	    while (LL_DMA_IsEnabledStream(DMA2, LL_DMA_STREAM_1))
	    {
	    	 __NOP();
	    }

	    while (LL_DMA_IsEnabledStream(DMA2, LL_DMA_STREAM_2))
	    {
	    	 __NOP();
	    }
	   	while (LL_DMA_IsEnabledStream(DMA2, LL_DMA_STREAM_3))
	   	{
	   	 __NOP();
	   	}

	    /* Clear DMA flags */
	   	LL_DMA_ClearFlag_TC0(DMA2);
	   	LL_DMA_ClearFlag_TE0(DMA2);
	   	LL_DMA_ClearFlag_TC1(DMA2);
	   	LL_DMA_ClearFlag_TE1(DMA2);
	   	LL_DMA_ClearFlag_TC2(DMA2);
	   	LL_DMA_ClearFlag_TE2(DMA2);
	   	LL_DMA_ClearFlag_TC3(DMA2);
	   	LL_DMA_ClearFlag_TE3(DMA2);

	    /* Clear DMAMUX overrun */
	    LL_DMAMUX_ClearFlag_SO15(DMAMUX1);

	    /* Reload NDTR */
	    LL_DMA_SetDataLength(DMA2, LL_DMA_STREAM_0, ADS_DATA_SIZE);
	    LL_DMA_SetDataLength(DMA2, LL_DMA_STREAM_1, ADS_DATA_SIZE);
	    LL_DMA_SetDataLength(DMA2, LL_DMA_STREAM_2, ADS_DATA_SIZE);
	    LL_DMA_SetDataLength(DMA2, LL_DMA_STREAM_3, ADS_DATA_SIZE);

	    /* Enable DMA streams */
	    LL_DMA_EnableStream(DMA2, LL_DMA_STREAM_0);
	    LL_DMA_EnableStream(DMA2, LL_DMA_STREAM_1);
	    LL_DMA_EnableStream(DMA2, LL_DMA_STREAM_2);
	    LL_DMA_EnableStream(DMA2, LL_DMA_STREAM_3);

	    /* Enable SPI DMA requests */
	    LL_SPI_EnableDMAReq_RX(SPI2);
	    LL_SPI_EnableDMAReq_TX(SPI2);
	    LL_SPI_EnableDMAReq_RX(SPI3);
	    LL_SPI_EnableDMAReq_TX(SPI3);


	    /* Enable SPI */
	    LL_SPI_Enable(SPI2);
	    LL_SPI_Enable(SPI3);

	    /* Start transfer */
	    LL_SPI_StartMasterTransfer(SPI2);
	    LL_SPI_StartMasterTransfer(SPI3);

}
void DMA1_ReceiveComplete_Callback(void)
{

	spi2_done = 1;
	if (spi3_done)
	{
		both_spi_done = 1;
	}
	//memcpy(copy, ADS_DATA_VOLT_RX, 16);
	//HAL_GPIO_WritePin(TIMER_GPIO_Port,TIMER_Pin ,0);
	CNT++;

}

void DMA2_ReceiveComplete_Callback(void)
{
	spi3_done = 1;
	if (spi2_done)
	{
		both_spi_done = 1;
	}
	//memcpy(copy, ADS_DATA_VOLT_RX, 16);
	HAL_GPIO_WritePin(TIMER_GPIO_Port,TIMER_Pin ,0);
	CNT1++;


}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	HW_timer_counter_32us++;


	if(htim ==  &htim7)
	{		
		HAL_GPIO_WritePin(TIMER_GPIO_Port,TIMER_Pin ,1);

		if(both_spi_done == 1)
		{

			spi2_done = 0;
			spi3_done = 0;
			both_spi_done =0;

			Activate_SPI();	
		}

	}

}
void DMA2_Stream0_IRQHandler(void)
{
  /* USER CODE BEGIN DMA2_Stream0_IRQn 0 */

  /* USER CODE END DMA2_Stream0_IRQn 0 */
  /* USER CODE BEGIN DMA2_Stream0_IRQn 1 */
	 if (LL_DMA_IsActiveFlag_TC0(DMA2))
	    {
	        LL_DMA_ClearFlag_TC0(DMA2);

	        DMA1_ReceiveComplete_Callback();
	    }


	    if (LL_DMA_IsActiveFlag_TE0(DMA2))
	    {
	        LL_DMA_ClearFlag_TE0(DMA2);

	    }


  /* USER CODE END DMA2_Stream0_IRQn 1 */
}
void DMA2_Stream2_IRQHandler(void)
{
  /* USER CODE BEGIN DMA2_Stream2_IRQn 0 */

  /* USER CODE END DMA2_Stream2_IRQn 0 */
  /* USER CODE BEGIN DMA2_Stream2_IRQn 1 */
	if (LL_DMA_IsActiveFlag_TC2(DMA2))
	{
		LL_DMA_ClearFlag_TC2(DMA2);

		DMA2_ReceiveComplete_Callback();
	}


	if (LL_DMA_IsActiveFlag_TE2(DMA2))
	{
		LL_DMA_ClearFlag_TE2(DMA2);

	}


  /* USER CODE END DMA2_Stream2_IRQn 1 */
}

 

 

regards,

srinath

Dear @Srinath_03 

Your current Activate_SPI() disables all DMA streams and waits for them to be fully disabled before restarting. This can be time consuming.

Another idea to consider, which can reduce time, is to use a state machine with timer-driven or interrupt-driven checks to asynchronously detect the completion of DMA disable.

BR

Lobna