2026-01-05 7:48 PM
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!
2026-01-05 8:34 PM
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.
2026-01-06 7:11 PM
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:
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:
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 DMAWhen 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!