cancel
Showing results for 
Search instead for 
Did you mean: 

Hardware-triggered spi?

sb_st
Senior

Hi!

I’m working on a motor controller design that utilizes an stm32f4 and a magnetic angular position sensor which communicates via spi.

My design currently performs current sensing; I use channel4 of timer1 to trigger ADC reads near the center of my center-aligned UVW PWM period.

This works great so far, but now I’m trying to think through how/when to schedule SPI reads of my angular sensor. I can straightforwardly perform an spi read when the ADC conversion completes, as part of my inner torque control loop. Is this reasonable to do? Is there a better way? It seems like the best time to touch off such a read is at the same time as when I trigger my ADCs. But I can’t quite figure out how I might do this.

Thanks!

2 REPLIES 2
TDK
Super User

If SPI is in two-way mode, you can trigger a transaction by a write to SPIx_DR. Any DMA trigger can do this, such as a timer channel or ADC complete. You may need to chain multiple triggers if the transaction is more than one word.

For example, set up a transfer from memory to SPIx_DR when TIM1->CH4 gets hit. Might need a different timer channel since you can only do one thing per trigger, but that's the idea.

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

Thanks so much! This is a new idea to me, and it seems pretty neat. I'll try to say that all back to you to make sure I understand:

  • DMA is enabled on a timer, and one of the channels can be configured to, say, perform a "memory to peripheral" transaction when the channel's OC gets hit. 
  • SPI itself can be set up to use DMA, so that when the Timer DMA writes, say, a read command to the SPI_DR register, it 'kicks off' an SPI transaction. 
  • The SPI DMA can write the received data to a location in memory. 

With some help from an AI I think I understand the ins and outs of doing this, but I am struggling to implement it correctly. I'm curious if an example exists that I could refer to for this?

What I'm doing:

  • I set up a separate timer, timer4, as a slave timer to timer1. Channels 1 and 2 are set to generate a PWM "pulse" when this timer is triggered. There is a slight delay between the two pulses (which I'll explain in a moment). 
  • SPI is configured to 16-bit mode full duplex
  • SPI and TIM DMA are all set to circular mode, no memory increment. 
  • On the Channel1 PWM pulse, I have an interrupt callback that pulls my sensor CS pin low
  • Then, I configure this DMA trickery as follows:

 

uint32_t angle_sensor_read_cmd = 0x0000;
uint32_t sensor_data;

// Arm the SPI Rx DMA
HAL_DMA_Start(&hdma_spi1_rx,
              (uint32_t)&hspi1.Instance->DR,               
              (uint32_t)&sensor_data, 1);

__HAL_DMA_ENABLE_IT(&hdma_spi1_rx, DMA_IT_TC);

// Arm the timer channel2 DMA
HAL_DMA_Start(&hdma_tim4_ch2,
              (uint32_t)&angle_sensor_read_cmd,
              (uint32_t)&hspi1.Instance->DR, 1);

SET_BIT(&hspi1.Instance->CR2, SPI_CR2_TXDMAEN | SPI_CR2_RXDMAEN);
__HAL_SPI_ENABLE(&hspi1);
__HAL_TIM_ENABLE_DMA(&htim4, TIM_DMA_CC2);

HAL_TIM_PWM_Start_IT(&htim4, TIM_CHANNEL_1); // First, pull down CS
HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_2);    // Second, start the SPI transaction via DMA

When I run this code, I can see my HAL_TIM_PWM_PulseFinishedCallback() being called (which pulls CS low), and I can see what appears to be a reasonable value show up in SPI1->DR. But my HAL_SPI_RxCpltCallback() is never called, and the value I see in SPI1->DR never seems to be transferred back out to my sensor_data buffer.

I've tried checking for DMA overflow or error bits, none are set. I will keep banging on this to see if I can make it work, because it does seem like quite a useful technique to be able to leverage. But I worry I am strolling deep into the unnecessarily-complicated troubleshooting weeds and might be overlooking something simple here, so if anyone spots something I'm doing that's obviously wrong or has an example I can check out, I would be very grateful!