cancel
Showing results for 
Search instead for 
Did you mean: 

SSI and Circular DMA

sb_st
Associate III

Hello!

I am writing a driver for the mt6701ct rotary magnetic encoder, using cubeIDE and an stm32f405 MCU. This sensor communicates via SSI, which is to say that it's read-only (MISO-only; there is no physical connection to MOSI). 

Using a simple polling strategy, I can communicate fine with this sensor using HAL_SPI_Receive().

I'd like to learn more about using DMA for this though, and am interested in trying to get circular DMA working. 

My SPI is configured like so:

Screenshot 2025-01-14 at 8.17.05 PM.png

Screenshot 2025-01-14 at 8.21.15 PM.png

The HAL Reference Manual notes:  

Screenshot 2025-01-14 at 8.15.52 PM.png

To try to sidestep issue #1 with my SSI setup here, I do this in my code to start the circular DMA:

typedef struct
{
  SPI_HandleTypeDef *spi_handle;
  uint16_t cs_pin;
  GPIO_TypeDef *cs_pin_port;
  uint8_t sensor_receive_dma_buffer[3];
} SMT6701CT_HandleTypeDef;

// IMPORTANT! On Page 1033 of the HAL Reference Manual,
// there's a note that says we can't use circular DMA
// with SPI with only RX data (which is what we want).
// To get around this, what I'm doing is creating a
// dummy TX buffer, and then using HAL_SPI_TransmitReceive()
// to simultaneously send and receive data. There is no
// physical TX connection here, so this does nothing really,
// it's just a workaround to allow us to do this DMA trick.
uint8_t tx_dummy[3] = {0x00, 0x00, 0x00};

// Pull cs low for the sensor.
// Note that we only activate this, we don't
// deactivate it here.
MT6701CT_enable_cs(sensor);

// Now, start the DMA read
hal_status = HAL_SPI_TransmitReceive_DMA(sensor->spi_handle, tx_dummy, sensor->sensor_receive_dma_buffer, 3);

Then, I have an interrupt handler like so:

void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi) {
    if (hspi == &hspi1) {
    	HAL_StatusTypeDef hal_status;
	hal_status = HAL_SPI_DMAPause(sensor->spi_handle);

	// ...
	// do a bunch of stuff to calculate the angle
	// ...

	// resume the DMA reader
	hal_status = HAL_SPI_DMAResume(sensor->spi_handle);
    }
}

I can see, via stepping through the code with the debugger in CubeIDE, that the DMA seems to be started ok, and the interrupt handler is indeed being called periodically. However, the data inside my sensor->sensor_receive_dma_buffer seems to be junk - it updates periodically as I expect, but just seems to be noise or other nonsensical data. 

I know it's hard to pinpoint the issue based on these limited code snippets, but I'm curious how I can troubleshoot what might be going wrong here? I think signs point to my hardware behaving correctly, and that I'm just dealing with a code problem. But, this is my first go-around with DMA, so I'm sure I'm overlooking something here.

 

Thank you!

2 REPLIES 2

> HAL_SPI_DMAPause

Just don't.

JW

sb_st
Associate III

To try to add bit more info:

I thought to try using HAL_SPI_DMAPause()/Resume() because this sensor sends a 24-bit chunk of data, 6 bits of which are a CRC that I need to manually decode before doing some math to turn the remaining 18 bits into a floating-point angle. All of this seemed arduous enough that pausing the DMA while I was doing that seemed prudent, but maybe not. 

But, setting that aside for the moment: I'm currently trying to simplify thing by pulling all of that out. Currently, I simply do:

uint8_t tx_dummy[3] = {0x00, 0x00, 0x00};
uint8_t rx_buf[3];

HAL_GPIO_WritePin(SPI1_CSN_GPIO_Port, SPI1_CSN_Pin, GPIO_PIN_RESET);

// Now, start the DMA read
HAL_StatusTypeDef hal_status;
hal_status = HAL_SPI_TransmitReceive_DMA(&hspi1, tx_dummy, rx_buf, 3);

while(1) {
  osDelay(pdMS_TO_TICKS(10));
}

 Then I enter the debugger and monitor rx_buf: 

dma_buffer.gif

Gif compression aside (the values change more rapidly than what is seen here), this doesn't look like meaningful information to me - the values only switch between 0 and 255, e.g. 

I wonder if it is relevant to highlight that I'm doing this from within a freeRTOS task? rx_buf is currently declared a global within one of my tasks. It feels as though I am making a mistake with correctly writing to a memory location or something, but this is where I'm bumping up against my inexperience.