cancel
Showing results for 
Search instead for 
Did you mean: 

Wrong value in rx buffer after using SPI in DMA mode

KoCT
Visitor

Hello,

I'm having trouble establishing a working SPI connection between an STM32U585 and a sensor (LIS3DHH). The transaction looks great on an oscilloscope: Clock, CS, MISO, and MOSI are behaving as expected.
This leads me to suspect that the MCU isn't receiving the data correctly. I'm using the low-level driver, but I've reproduced the same behavior with the HAL driver. It's important to note that I want to use DMA mode for performance reasons.

I suspect a bug in my DMA or SPI configuration. After a transaction, the second byte of my rx buffer contains the value 0x00. When reading the WHO-AM-I register, however, it should contain 0x11 (this value is also output via the MISO line). I would greatly appreciate any suggestions.

Here is the GPIO and SPI configuration (DMA below):

LL_GPIO_InitTypeDef gpio_init_sck_miso_mosi = {0};
gpio_init_sck_miso_mosi.Pin = LL_GPIO_PIN_14 | LL_GPIO_PIN_13 | LL_GPIO_PIN_15;
gpio_init_sck_miso_mosi.Mode =LL_GPIO_MODE_ALTERNATE;
gpio_init_sck_miso_mosi.Speed =  LL_GPIO_SPEED_FREQ_HIGH;
gpio_init_sck_miso_mosi.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
gpio_init_sck_miso_mosi.Pull = LL_GPIO_PULL_NO;
gpio_init_sck_miso_mosi.Alternate = LL_GPIO_AF_5;

LL_GPIO_InitTypeDef gpio_init_cs = {0};
gpio_init_cs.Pin = LL_GPIO_PIN_12;
gpio_init_cs.Mode = LL_GPIO_MODE_OUTPUT;
gpio_init_cs.OutputType =LL_GPIO_OUTPUT_PUSHPULL;
gpio_init_cs.Pull = LL_GPIO_PULL_NO;
gpio_init_cs.Speed = LL_GPIO_SPEED_FREQ_LOW;

LL_SPI_InitTypeDef spi_init = {0};
spi_init.TransferDirection = LL_SPI_FULL_DUPLEX;
spi_init.Mode = LL_SPI_MODE_MASTER;
spi_init.DataWidth =LL_SPI_DATAWIDTH_8BIT;
spi_init.ClockPolarity = LL_SPI_POLARITY_HIGH;
spi_init.ClockPhase = LL_SPI_PHASE_2EDGE;
spi_init.NSS =LL_SPI_NSS_SOFT;
spi_init.BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV16;			// 2 MHz
spi_init.BitOrder = LL_SPI_MSB_FIRST;
spi_init.CRCCalculation =LL_SPI_CRCCALCULATION_DISABLE;
spi_init.CRCPoly = 0x7;

Here are my initialization and communication functions:

void spi_initialization(LL_SPI_InitTypeDef *spi_init, LL_GPIO_InitTypeDef *gpio_init_sck_miso_mosi, LL_GPIO_InitTypeDef *gpio_init_cs)
{
	LL_RCC_SetSPIClockSource(LL_RCC_SPI1_CLKSOURCE_PCLK2);
	LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI1);
	LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOE);

	LL_GPIO_Init(port, gpio_init_sck_miso_mosi);
	LL_GPIO_Init(port, gpio_init_cs);
	LL_GPIO_SetOutputPin(port, gpio_init_cs->Pin);
	
	LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPDMA1);

	LL_DMA_InitTypeDef DMA_InitStruct = {0};
	// TX - Channel 1
	DMA_InitStruct.SrcAddress           		= (uint32_t)tx_buffer;
	DMA_InitStruct.DestAddress          	= LL_SPI_DMA_GetTxRegAddr(SPI1);
	DMA_InitStruct.Direction            		= LL_DMA_DIRECTION_MEMORY_TO_PERIPH;
	DMA_InitStruct.BlkHWRequest         	= LL_DMA_HWREQUEST_SINGLEBURST;
	DMA_InitStruct.DataAlignment        	= LL_DMA_DATA_ALIGN_ZEROPADD;
	DMA_InitStruct.SrcBurstLength       	= 1;
	DMA_InitStruct.DestBurstLength      	= 1;
	DMA_InitStruct.SrcDataWidth         	= LL_DMA_SRC_DATAWIDTH_BYTE;
	DMA_InitStruct.DestDataWidth        	= LL_DMA_DEST_DATAWIDTH_BYTE;
	DMA_InitStruct.SrcIncMode           	= LL_DMA_SRC_INCREMENT;
	DMA_InitStruct.DestIncMode          	= LL_DMA_DEST_FIXED;
	DMA_InitStruct.Priority            		 	= LL_DMA_LOW_PRIORITY_HIGH_WEIGHT;
	DMA_InitStruct.BlkDataLength        	= SPI_TX_BUFFER_SIZE;
	DMA_InitStruct.TriggerMode          	= LL_DMA_TRIGM_BLK_TRANSFER;
	DMA_InitStruct.TriggerPolarity      		= LL_DMA_TRIG_POLARITY_MASKED;
	DMA_InitStruct.TriggerSelection     	= 0x00000000U;
	DMA_InitStruct.Request              		= LL_GPDMA1_REQUEST_SPI1_TX;
	DMA_InitStruct.TransferEventMode  	= LL_DMA_TCEM_BLK_TRANSFER;
	DMA_InitStruct.SrcAllocatedPort     	= LL_DMA_SRC_ALLOCATED_PORT0;
	DMA_InitStruct.DestAllocatedPort   	= LL_DMA_DEST_ALLOCATED_PORT0;
	DMA_InitStruct.LinkAllocatedPort    	= LL_DMA_LINK_ALLOCATED_PORT1;
	DMA_InitStruct.LinkStepMode         	= LL_DMA_LSM_FULL_EXECUTION;
	DMA_InitStruct.LinkedListBaseAddr 	= 0x00000000U;
	DMA_InitStruct.LinkedListAddrOffset = 0x00000000U;

	if (LL_DMA_Init(GPDMA1, LL_DMA_CHANNEL_1, &DMA_InitStruct) == ERROR) return false;
	LL_DMA_EnableIT_TC(GPDMA1, LL_DMA_CHANNEL_1);
	NVIC_EnableIRQ(GPDMA1_Channel1_IRQn);

	// RX - Channel 0
	DMA_InitStruct.SrcAddress           		= LL_SPI_DMA_GetRxRegAddr(SPI1);
	DMA_InitStruct.DestAddress          	= (uint32_t)rx_buffer;
	DMA_InitStruct.Direction            		= LL_DMA_DIRECTION_PERIPH_TO_MEMORY;
	DMA_InitStruct.BlkDataLength        	= SPI_RX_BUFFER_SIZE;
	DMA_InitStruct.SrcIncMode           	= LL_DMA_SRC_FIXED;
	DMA_InitStruct.DestIncMode          	= LL_DMA_DEST_INCREMENT;
	DMA_InitStruct.Request             		 = LL_GPDMA1_REQUEST_SPI1_RX;

	if (LL_DMA_Init(GPDMA1, LL_DMA_CHANNEL_0, &DMA_InitStruct) == ERROR) return false;
	LL_DMA_EnableIT_TC(GPDMA1, LL_DMA_CHANNEL_0);
	NVIC_EnableIRQ(GPDMA1_Channel0_IRQn);
	
	LL_DMA_SetPeriphRequest(GPDMA1, LL_DMA_CHANNEL_0, LL_GPDMA1_REQUEST_SPI1_RX);
	LL_DMA_SetPeriphRequest(GPDMA1, LL_DMA_CHANNEL_0, LL_GPDMA1_REQUEST_SPI1_TX);
	
	LL_SPI_Init(SPI1, spi_init);
	LL_SPI_SetStandard(SPI1, LL_SPI_PROTOCOL_MOTOROLA);
	LL_SPI_Enable(SPI1);
	
	tx_event_flags_create(&spi_event_flags, "SPI Flags");
}	

// IRQ-Handler
void SPI_DMA_ReceiveIRQ_Handler(void)
{
	if (LL_DMA_IsActiveFlag_TC(GPDMA1, LL_DMA_CHANNEL_0))
	{
		LL_DMA_ClearFlag_TC(GPDMA1, LL_DMA_CHANNEL_0);

		// set event flag RX_COMPLETE
		tx_event_flags_set(&spi_event_flags, SPI_EVENT_RX_COMPLETE, TX_OR);
	}
}

void SPI_DMA_TransmitIRQ_Handler(void)
{
	if (LL_DMA_IsActiveFlag_TC(GPDMA1, LL_DMA_CHANNEL_1))
	{
		LL_DMA_ClearFlag_TC(GPDMA1, LL_DMA_CHANNEL_1);
	}
}

// Read register function:
uint8_t readSPI(uint8_t register)
{
	tx_buffer[0] = register;
	tx_buffer[1] = 0x00;
	
	LL_GPIO_ResetOutputPin(GPIOE, LL_GPIO_PIN_12); // CS low
	
	LL_DMA_ConfigAddresses(GPDMA1, LL_DMA_CHANNEL_0, LL_SPI_DMA_GetRxRegAddr(SPI1), (uint32_t)&rx_buffer[0]);
	LL_DMA_SetBlkDataLength(GPDMA1, LL_DMA_CHANNEL_0, 2);

	LL_DMA_ConfigAddresses(GPDMA1, LL_DMA_CHANNEL_1, (uint32_t)&tx_buffer[0], LL_SPI_DMA_GetTxRegAddr(SPI1));
	LL_DMA_SetBlkDataLength(GPDMA1, LL_DMA_CHANNEL_1, 2); 
	
	LL_SPI_EnableDMAReq_RX(SPI1);
	LL_SPI_EnableDMAReq_TX(SPI1);

	// Activate Channel
	LL_DMA_EnableChannel(GPDMA1, LL_DMA_CHANNEL_0);
	LL_DMA_EnableChannel(GPDMA1, LL_DMA_CHANNEL_1);

	// Start SPI
	LL_SPI_StartMasterTransfer(SPI1);

	// Wait for transmission termination
	uint32_t actual_flags;
	if (tx_event_flags_get(&spi_event_flags, SPI_EVENT_RX_COMPLETE, TX_OR_CLEAR, &actual_flags, 1000) != TX_SUCCESS)
	{
		LL_GPIO_SetOutputPin(GPIOE, LL_GPIO_PIN_12);
		return 0xFF;
	}

	LL_DMA_DisableChannel(GPDMA1, LL_DMA_CHANNEL_0);
	LL_DMA_DisableChannel(GPDMA1, LL_DMA_CHANNEL_1);

	LL_GPIO_SetOutputPin(GPIOE, LL_GPIO_PIN_12);
	return rx_buffer[1];							// expected 0x11, got 0x00
}

tx_buffer and rx_buffer are global uint8_t arrays.

 

Please find a picture of the oscilliscope output attached.

0 REPLIES 0