cancel
Showing results for 
Search instead for 
Did you mean: 

I can't work SPI Transmit with DMA by LL Library

HNish.1
Associate

Hi Seniors.

I am a beginner who started to implement in the LL library.

I would appreciate it if you could help me.

What I want to do is very simple, I want to transfer one buffer divided into front and back by SPI (Slave) using DMA every second.

The implementation in HAL is like this, and it is output alternately without any problem.

#define BUF_SIZE 16384
uint8_t buf[BUF_SIZE] = { };
 
 
int main(void) {
	/* USER CODE BEGIN 1 */
 
	/* USER CODE END 1 */
 
	/* MCU Configuration--------------------------------------------------------*/
 
	/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
	HAL_Init();
 
	/* USER CODE BEGIN Init */
 
	/* USER CODE END Init */
 
	/* Configure the system clock */
	SystemClock_Config();
 
	/* USER CODE BEGIN SysInit */
 
	/* USER CODE END SysInit */
 
	/* Initialize all configured peripherals */
	MX_GPIO_Init();
	MX_DMA_Init();
	MX_USART2_UART_Init();
	MX_SPI2_Init();
	MX_USART1_UART_Init();
	/* USER CODE BEGIN 2 */
 
	for (int i = 0; i < sizeof(buf) / 2; i++)
		buf[i] = (i * 2 + 1) % 256;
 
	for (int i = sizeof(buf) / 2; i < sizeof(buf); i++)
		buf[i] = (i * 2) % 256;
 
	/* USER CODE END 2 */
 
	/* Infinite loop */
	/* USER CODE BEGIN WHILE */
	while (1) {
 
		HAL_SPI_Transmit_DMA(&hspi2, buf, sizeof(buf) / 2);
		HAL_Delay(1000);
 
		HAL_SPI_Transmit_DMA(&hspi2, buf + sizeof(buf) / 2 , sizeof(buf) / 2);
		HAL_Delay(1000);
		/* USER CODE END WHILE */
 
		/* USER CODE BEGIN 3 */
	}
	/* USER CODE END 3 */
}

After confirming the operation with HAL, I changed the SPI and DMA drivers from HAL to LL in [Project Manager]> [Advanced Setting] of CubeIDE, and obtained the following initialization code.

static void MX_SPI2_Init(void) {
 
	/* USER CODE BEGIN SPI2_Init 0 */
 
	/* USER CODE END SPI2_Init 0 */
 
	LL_SPI_InitTypeDef SPI_InitStruct = { 0 };
 
	LL_GPIO_InitTypeDef GPIO_InitStruct = { 0 };
 
	/* Peripheral clock enable */
	LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_SPI2);
 
	LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOC);
	LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOB);
	/**SPI2 GPIO Configuration
	 PC2   ------> SPI2_MISO
	 PB10   ------> SPI2_SCK
	 PB4   ------> SPI2_NSS
	 */
	GPIO_InitStruct.Pin = LL_GPIO_PIN_2;
	GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
	GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
	GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
	GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
	GPIO_InitStruct.Alternate = LL_GPIO_AF_5;
	LL_GPIO_Init(GPIOC, &GPIO_InitStruct);
 
	GPIO_InitStruct.Pin = LL_GPIO_PIN_10;
	GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
	GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
	GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
	GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
	GPIO_InitStruct.Alternate = LL_GPIO_AF_5;
	LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
 
	GPIO_InitStruct.Pin = LL_GPIO_PIN_4;
	GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
	GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
	GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
	GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
	GPIO_InitStruct.Alternate = LL_GPIO_AF_7;
	LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
 
	/* SPI2 DMA Init */
 
	/* SPI2_TX Init */
	LL_DMA_SetChannelSelection(DMA1, LL_DMA_STREAM_4, LL_DMA_CHANNEL_0);
 
	LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_STREAM_4,
			LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
 
	LL_DMA_SetStreamPriorityLevel(DMA1, LL_DMA_STREAM_4, LL_DMA_PRIORITY_LOW);
 
	LL_DMA_SetMode(DMA1, LL_DMA_STREAM_4, LL_DMA_MODE_NORMAL);
 
	LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_STREAM_4, LL_DMA_PERIPH_NOINCREMENT);
 
	LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_STREAM_4, LL_DMA_MEMORY_INCREMENT);
 
	LL_DMA_SetPeriphSize(DMA1, LL_DMA_STREAM_4, LL_DMA_PDATAALIGN_BYTE);
 
	LL_DMA_SetMemorySize(DMA1, LL_DMA_STREAM_4, LL_DMA_MDATAALIGN_BYTE);
 
	LL_DMA_DisableFifoMode(DMA1, LL_DMA_STREAM_4);
 
	/* USER CODE BEGIN SPI2_Init 1 */
 
	/* USER CODE END SPI2_Init 1 */
	/* SPI2 parameter configuration*/
	SPI_InitStruct.TransferDirection = LL_SPI_FULL_DUPLEX;
	SPI_InitStruct.Mode = LL_SPI_MODE_SLAVE;
	SPI_InitStruct.DataWidth = LL_SPI_DATAWIDTH_8BIT;
	SPI_InitStruct.ClockPolarity = LL_SPI_POLARITY_LOW;
	SPI_InitStruct.ClockPhase = LL_SPI_PHASE_1EDGE;
	SPI_InitStruct.NSS = LL_SPI_NSS_HARD_INPUT;
	SPI_InitStruct.BitOrder = LL_SPI_MSB_FIRST;
	SPI_InitStruct.CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE;
	SPI_InitStruct.CRCPoly = 10;
	LL_SPI_Init(SPI2, &SPI_InitStruct);
	LL_SPI_SetStandard(SPI2, LL_SPI_PROTOCOL_MOTOROLA);
	/* USER CODE BEGIN SPI2_Init 2 */
 
	/* USER CODE END SPI2_Init 2 */
 
}

After that, the following implementation was performed with reference to the reference manual.

However, this implementation outputs only "FFFF ..." after outputting the contents of the buffer in the first half once. Far from alternating, the contents of the buffer in the latter half are never output.

#define BUF_SIZE 16384
uint8_t buf[BUF_SIZE] = { };
 
 
int main(void) {
	/* USER CODE BEGIN 1 */
 
	/* USER CODE END 1 */
 
	/* MCU Configuration--------------------------------------------------------*/
 
	/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
	HAL_Init();
 
	/* USER CODE BEGIN Init */
 
	/* USER CODE END Init */
 
	/* Configure the system clock */
	SystemClock_Config();
 
	/* USER CODE BEGIN SysInit */
 
	/* USER CODE END SysInit */
 
	/* Initialize all configured peripherals */
	MX_GPIO_Init();
	MX_DMA_Init();
	MX_USART2_UART_Init();
	MX_SPI2_Init();
	MX_USART1_UART_Init();
	/* USER CODE BEGIN 2 */
 
	for (int i = 0; i < sizeof(buf) / 2; i++)
		buf[i] = (i * 2 + 1) % 256;
 
	for (int i = sizeof(buf) / 2; i < sizeof(buf); i++)
		buf[i] = (i * 2) % 256;
 
	/* USER CODE END 2 */
 
	/* Infinite loop */
	/* USER CODE BEGIN WHILE */
 
	while (1) {
 
		while (LL_DMA_IsEnabledStream(DMA1, LL_DMA_STREAM_4)) {
		};
 
		LL_DMA_ConfigAddresses(DMA1, LL_DMA_STREAM_4, (uint32_t) &buf,
				LL_SPI_DMA_GetRegAddr(SPI2), LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
 
		LL_DMA_SetDataLength(DMA1, LL_DMA_STREAM_4, sizeof(buf) / 2);
 
		if (LL_DMA_IsEnabledStream(DMA1, LL_DMA_STREAM_4) == 0)
			LL_DMA_EnableStream(DMA1, LL_DMA_STREAM_4);
 
		if (LL_SPI_IsEnabledDMAReq_TX(SPI2) == 0)
			LL_SPI_EnableDMAReq_TX(SPI2);
 
		if (LL_SPI_IsEnabled(SPI2) == 0)
			LL_SPI_Enable(SPI2);
 
		HAL_Delay(1000);
 
		LL_DMA_DisableStream(DMA1, LL_DMA_STREAM_4);
 
		while (!LL_SPI_IsActiveFlag_TXE(SPI2)) {
		};
		while (LL_SPI_IsActiveFlag_BSY(SPI2)) {
		};
 
		LL_SPI_Disable(SPI2);
		LL_SPI_DisableDMAReq_TX(SPI2);
 
		while (LL_DMA_IsEnabledStream(DMA1, LL_DMA_STREAM_4)) {
		};
 
		LL_DMA_ConfigAddresses(DMA1, LL_DMA_STREAM_4,
				(uint32_t) &buf + sizeof(buf) / 2, LL_SPI_DMA_GetRegAddr(SPI2),
				LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
 
		LL_DMA_SetDataLength(DMA1, LL_DMA_STREAM_4, sizeof(buf) / 2);
 
		if (LL_DMA_IsEnabledStream(DMA1, LL_DMA_STREAM_4) == 0)
			LL_DMA_EnableStream(DMA1, LL_DMA_STREAM_4);
 
		if (LL_SPI_IsEnabledDMAReq_TX(SPI2) == 0)
			LL_SPI_EnableDMAReq_TX(SPI2);
 
		if (LL_SPI_IsEnabled(SPI2) == 0)
			LL_SPI_Enable(SPI2);
 
		HAL_Delay(1000);
 
		LL_DMA_DisableStream(DMA1, LL_DMA_STREAM_4);
 
		while (!LL_SPI_IsActiveFlag_TXE(SPI2)) {
		};
		while (LL_SPI_IsActiveFlag_BSY(SPI2)) {
		};
 
		LL_SPI_Disable(SPI2);
		LL_SPI_DisableDMAReq_TX(SPI2);
 
		/* USER CODE END WHILE */
 
		/* USER CODE BEGIN 3 */
	}
	/* USER CODE END 3 */
}

When I checked it with the debugger of CubeIDE, I found that there was no infinite loop in the while statement in the middle, but one loop every 2 seconds.

I also referred to the implementation of the HAL SPI function, but what I was doing looked the same and I couldn't find a solution.

I can't think of a solution anymore. I would like to help you.

0 REPLIES 0