cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F4xx InputCapture and DMA

Zt Liu
Senior III
Posted on March 29, 2017 at 12:59

MCU: STM32F446RE

BOARD: NUCLEO-64 STM32F446

STM32 CUBEMX Version:4.20.0

Library: STM43F4 1.15.0

------------------------------------------------------------------------------------------------------------------------------------------------------------

The problem here is probably hal driver. 

I am currently setting TIM1 as PWM Input mode following the examples in STM32Cube_FW_F4_V1.15.0

In the beginning, I am using IT like in the example, it works fine.

However, the pwm signal I want to measure runs at 800KHz.

This forces me to use DMA method to capture the values of TIM_CC1 and TIM_CC2.

the settings of TIM1 DMA is as followed:

0690X00000606eQQAQ.png

After generation of the project, 

I thought that the following code would start the dma data moving:

HAL_TIM_IC_Start_DMA(&htim1, TIM_CHANNEL_2, (uint32_t *)IC2_Buf, IC_PREXFER_COUNT);

HAL_TIM_IC_Start_DMA(&htim1, TIM_CHANNEL_1, (uint32_t *)IC1_Buf, IC_PREXFER_COUNT);

But it does not work as:

HAL_TIM_IC_Start_IT(&htim1, TIM_CHANNEL_1);

HAL_TIM_IC_Start_IT(&htim1, TIM_CHANNEL_2);

Because inside the HAL_TIM_IC_START_DMA(), there is some code controlling timerHandle state:

HAL_StatusTypeDef HAL_TIM_IC_Start_DMA(TIM_HandleTypeDef *htim, uint32_t Channel, uint32_t *pData, uint16_t Length)

{

   /* Check the parameters */

   assert_param(IS_TIM_CCX_INSTANCE(htim->Instance, Channel));

   assert_param(IS_TIM_DMA_CC_INSTANCE(htim->Instance));

 

  if((htim->State == HAL_TIM_STATE_BUSY))

   {

      return HAL_BUSY;

   }

  else if((htim->State == HAL_TIM_STATE_READY))

   {

      if((pData == 0U) && (Length > 0))

      {

         return HAL_ERROR;

      }

      else

      {

         htim->State = HAL_TIM_STATE_BUSY;

      }

   }

...

}

This meas that if I call HAL_TIM_IC_Start_DMA(&htim1, TIM_CHANNEL_1,...) first, the htim1 would be in HAL_BUSY state, therefore I cannot successfully call HAL_TIM_IC_Start_DMA(&htim1, TIM_CHANNEL_2,...) accordingly.

I tried to comment out those hal_state checking codes, it seems to work nicely, for I got my ICx_Buf data as expected.

So, is that a bug confirmed?

Or DMA simply can NOT work like that as I need?

Please help me!

7 REPLIES 7
Imen.D
ST Employee
Posted on March 29, 2017 at 14:20

Hi

Liu.Zhitai

,

Thank you for highlighting your issue with details.

I will check it and come back to you.

Imen

When your question is answered, please close this topic by clicking "Accept as Solution".
Thanks
Imen
Posted on March 29, 2017 at 16:28

If the period is constant, one could use a single DMA channel just to recover the pulse width. Or use Input Capture on one channel confining both edges. Where C-A is the period, and B-A is the width

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
Posted on March 29, 2017 at 16:13

Hi,

I reported this issue internally to the appropriate team for further investigation and I will keep you informed about any updates on this.

Imen

When your question is answered, please close this topic by clicking "Accept as Solution".
Thanks
Imen
Posted on March 30, 2017 at 02:48

Thanks Imen!

I'll be waiting here!

STM32 is really a great product, I'm a little bit addicted

🙂

.
Posted on March 30, 2017 at 02:56

Thanks for replying, Clive!

Unfortunately, the equipment's PWM signal we want to monitor could slightly vary, and we definitely need to monitor it.

Both edge trigger could be helpful. Just like the old time I used dsPIC running 72MHz to do the same thing, and I did remember that we were forced to use assembly (painfully) to process those C-A for period and  B-A for width. Now, we got slave mode in advanced timer in STM32, it's really lovely!
Zt Liu
Senior III
Posted on March 30, 2017 at 06:19

I just realized that I cannot just comment out those HAL_TIM_STATE codes and let DMA work asynchronously!  

So I have to manually configure the htim1 like this:

---

htim1.hdma[TIM_DMA_ID_CC1]->XferCpltCallback = TIM_DMACaptureCplt;

htim1.hdma[TIM_DMA_ID_CC2]->XferCpltCallback = TIM_DMACaptureCplt;

HAL_DMA_Start_IT(htim1.hdma[TIM_DMA_ID_CC1], (uint32_t)&(htim1.Instance->CCR1), (uint32_t)IC1_Buf,                         IC_PREXFER_COUNT);

HAL_DMA_Start_IT(htim1.hdma[TIM_DMA_ID_CC2], (uint32_t)&(htim1.Instance->CCR2), (uint32_t)IC2_Buf,                      IC_PREXFER_COUNT);

__HAL_TIM_ENABLE_DMA(&htim1, TIM_DMA_CC1);

__HAL_TIM_ENABLE_DMA(&htim1, TIM_DMA_CC2);

TIM_CCxChannelCmd(htim1.Instance, TIM_CHANNEL_1, TIM_CCx_ENABLE);

TIM_CCxChannelCmd(htim1.Instance, TIM_CHANNEL_2, TIM_CCx_ENABLE);

__HAL_TIM_ENABLE(&htim1);

---

Now I both have the ICx data and they collect synchronously.

Guess LL Drivers is getting popular now.

eziya76
Associate II

Hello All,

I met the same issues. Is it still in progress or is there a solution for this?

I also had to change timer state forcibly before calling 2nd HAL_TIM_IC_Start_DMA() like below

HAL_TIM_IC_Start_DMA(&htim1, TIM_CHANNEL_1, caputure1, 2);​

htim1.State = HAL_TIM_STATE_READY;

HAL_TIM_IC_Start_DMA(&htim1, TIM_CHANNEL_2, caputure2, 2);

Thanks