Author Topic: STM32 ADC conversion triggering with the falling/rising edge of the PWM signal  (Read 11860 times)

0 Members and 1 Guest are viewing this topic.

Offline VanitarNordicTopic starter

  • Frequent Contributor
  • **
  • Posts: 277
  • Country: 00
Hi.

I want to generate a PWM pulse which might vary in terms of its frequency and duty cycle.
It's easy to make it But I want to start reading ADC values using DMA (for example 100 samples) just after the pulse finished or started (falling/rising edge of the PWM signal).

In the ideal case, I want to start reading 20uS after the falling edge of the PWM.

is it possible to make it?

I use CubeMX
 

Offline mbless

  • Regular Contributor
  • *
  • Posts: 227
  • Country: 00
Depending on the MCU and which ADC you're using, you can use timer trigger events or an external interrupt to start ADC conversion in DMA mode. You'll have to go to the Configuration tab in CubeMX and select the ADC to see which trigger options exist for your setup.

As far as a 20 us delay, there's no built-in delay on the ADC side, so you'd have to delay the trigger some how. Personally, I would just throw away x number of data at the beginning of the conversion that accounts for 20 us based on the sampling time for each conversion.
 
The following users thanked this post: VanitarNordic

Offline VanitarNordicTopic starter

  • Frequent Contributor
  • **
  • Posts: 277
  • Country: 00
Depending on the MCU and which ADC you're using, you can use timer trigger events or an external interrupt to start ADC conversion in DMA mode. You'll have to go to the Configuration tab in CubeMX and select the ADC to see which trigger options exist for your setup.

As far as a 20 us delay, there's no built-in delay on the ADC side, so you'd have to delay the trigger some how. Personally, I would just throw away x number of data at the beginning of the conversion that accounts for 20 us based on the sampling time for each conversion.

I am using STM32F407, therefore it contains all sorts of timers, advanced timers and ADCs. Yes, in the meantime I just triggered the ADC with another timer trigger out event and for that 20uS I just did the same as you mentioned, throwing the beginning of DMA acquired data in the array.

I have couple of questions which have remained unsolved.

1) How can I enable the ADC conversion using an external interrupt? The only triggering options I see in the list, are timer trigger or timer capture.

2) is it possible to fire the ADC DMA conversion from alternative routine? I mean triggering it in the code by a command or something.
« Last Edit: July 09, 2018, 09:57:13 am by VanitarNordic »
 

Offline VanitarNordicTopic starter

  • Frequent Contributor
  • **
  • Posts: 277
  • Country: 00
I have another problem also. I put the timer trigger on 100mS. it means it triggers its interrupt and ADC every 100mS. Below is the configuration of the ADC and Timer2.

I checked the TIM2 interrupt by a GPIO toggle and it gets fired every 100mS or 50Hz which is correct.
BUT the ADC DMA gets fired 2 times per second, it means 2Hz  :horse: . it is weird because I just put 100 for the buffer and whole sampling to fire the ADC DMA interrupt must not take more than 100 * 0.5uS  = 50uS , because each ADC channel can handle the speed of 2Msps. This speed is correct if the ADC works in the continuous conversion mode, but I could not achieve this when I trigger it externally.  :-\

The triggering is slow and it should not make any timing conflict, it means the conversion finishes sooner before the next trigger comes in




« Last Edit: July 09, 2018, 12:05:58 pm by VanitarNordic »
 

Offline mbless

  • Regular Contributor
  • *
  • Posts: 227
  • Country: 00
1) How can I enable the ADC conversion using an external interrupt? The only triggering options I see in the list, are timer trigger or timer capture.

According to Figure 51 of the reference manual, ADC1 should be able to use EXTI 11 as a trigger source. I don't have CubeMX in front of me to try it out myself.


2) is it possible to fire the ADC DMA conversion from alternative routine? I mean triggering it in the code by a command or something.

I use HAL_ADC_Start_DMA


I have another problem also. I put the timer trigger on 100mS. it means it triggers its interrupt and ADC every 100mS. Below is the configuration of the ADC and Timer2.

I checked the TIM2 interrupt by a GPIO toggle and it gets fired every 100mS or 50Hz which is correct.

I'm guessing you meant 5 Hz. Either way the interrupt would be occurring at 10 Hz; toggling a GPIO would make it look like 5 Hz. Also, s =  seconds, S = Siemens.


BUT the ADC DMA gets fired 2 times per second, it means 2Hz  :horse: . it is weird because I just put 100 for the buffer and whole sampling to fire the ADC DMA interrupt must not take more than 100 * 0.5uS  = 50uS , because each ADC channel can handle the speed of 2Msps. This speed is correct if the ADC works in the continuous conversion mode, but I could not achieve this when I trigger it externally.  :-\

The triggering is slow and it should not make any timing conflict, it means the conversion finishes sooner before the next trigger comes in

I believe the Master/Slave mode should be enabled in TIM2 configuration for it to output a trigger signal. It's disabled in the screenshot.
 

Offline VanitarNordicTopic starter

  • Frequent Contributor
  • **
  • Posts: 277
  • Country: 00
Quote
I'm guessing you meant 5 Hz. Either way the interrupt would be occurring at 10 Hz; toggling a GPIO would make it look like 5 Hz. Also, s =  seconds, S = Siemens.

No I mean 50Hz, Timer2 clock is 60MHz, therefore 60Mhz/ 60000 * 10 = 100Hz, but because of toggling it would be 50Hz. That's what I get when I toggle a GPIO Pin in Timer2 interrupt.

My point is the rate of timer interrupt triggering must be the same as it goes out to trigger ADC. which is not here  :-\

Quote
I believe the Master/Slave mode should be enabled in TIM2 configuration for it to output a trigger signal. It's disabled in the screenshot.

I enabled master/slave, but it did not help.

 

Online SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14447
  • Country: fr
Start the DMA transfer inside the ISR of the timer configured for the PWM generation? (CCxIF flag)
 
The following users thanked this post: VanitarNordic

Offline VanitarNordicTopic starter

  • Frequent Contributor
  • **
  • Posts: 277
  • Country: 00
Start the DMA transfer inside the ISR of the timer configured for the PWM generation? (CCxIF flag)

of course not. DMA has initialized by the HAL functions (HAL_DMA_Start_IT) inside the main function and the "conversion" is triggered by the timer. The timer triggering time must be the same as Timer ISR triggering. Timer ISR fired at the defined time and it is correct, but ADC triggering is not happen the same time as ISR and much slower.

Another timer (TIM1) generates the PWM and TIM2 generates triggers.
« Last Edit: July 09, 2018, 05:20:23 pm by VanitarNordic »
 

Online SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14447
  • Country: fr
I'm not sure why not. Unless there is something that is not clear here.

If you use HAL, the key would be to start the conversion by using HAL_ADC_Start_DMA() in the ISR, instead of starting the DMA separately. This is exactly what this function is made for. I did this in one application and it worked fine (I was triggering the acquition of a sample buffer in an EXTI ISR).
 
The following users thanked this post: VanitarNordic

Offline VanitarNordicTopic starter

  • Frequent Contributor
  • **
  • Posts: 277
  • Country: 00
I'm not sure why not. Unless there is something that is not clear here.

If you use HAL, the key would be to start the conversion by using HAL_ADC_Start_DMA() in the ISR, instead of starting the DMA separately. This is exactly what this function is made for. I did this in one application and it worked fine (I was triggering the acquition of a sample buffer in an EXTI ISR).

Yes, I can start the whole process inside the ISR but the intention of ADC DMA triggering is "just for starting the conversion" by the triggering signal, not initialization. apart from this, this function itself has around 40uS Delay which causes an unnecessary time shift and might not be suitable if we do this periodically.
 

Online SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14447
  • Country: fr
From what I remember, I was getting only a couple µs latency doing this, running @80 MHz, so that was fine. If your run at much lower frequencies, that may become a problem indeed.

But I think you can get much lower latency than this if you rewrite the above function tailored for your needs so that only the necessary registers are written to - HAL functions are not particularly efficient since they cover a lot of cases. Fortunately, the source code is available and not that hard to grasp.

 
The following users thanked this post: VanitarNordic

Offline VanitarNordicTopic starter

  • Frequent Contributor
  • **
  • Posts: 277
  • Country: 00
From what I remember, I was getting only a couple µs latency doing this, running @80 MHz, so that was fine. If your run at much lower frequencies, that may become a problem indeed.

But I think you can get much lower latency than this if you rewrite the above function tailored for your needs so that only the necessary registers are written to - HAL functions are not particularly efficient since they cover a lot of cases. Fortunately, the source code is available and not that hard to grasp.

Hmmm, I have no idea. The system clock is 60MHz and ADC clock is 30MHz, which is the best high clock for the ADC as datasheet says for the F407. I measured this delay using SWV trace, or maybe I'm mistaken and I have measured whole conversion time for all samples, BUT anyway in theory this triggering implementation must work as the manufacturer claims. But I will retest your suggestion, thanks
 

Offline VanitarNordicTopic starter

  • Frequent Contributor
  • **
  • Posts: 277
  • Country: 00
I realized what's the problem but I can not solve it.  :(

Let me explain. Timer2 has a correct IRQ triggering. it means the Timer2 interrupt gets triggered by a frequency of 100Hz. I just put a PIn toggle inside the interrupt routine and it generated a 50Hz square pulse.

The I put    HAL_ADC_Start_DMA(&hadc1, (uint32_t *) buffer, 100); inside the Timer2 interrupt routine to be triggered also.

then I moved the pin toggle to the ADC interrupt routine to check the conversion frequency.

the frequency is correct but for a time around 0.5 just after reset, it means just after reset the ADC triggers the interrupt with a 100Hz frequency.

But the DMA interrupt gets fired very slowly around once per second. why it should be like this?
 

Offline mbless

  • Regular Contributor
  • *
  • Posts: 227
  • Country: 00
I realized what's the problem but I can not solve it.  :(

Let me explain. Timer2 has a correct IRQ triggering. it means the Timer2 interrupt gets triggered by a frequency of 100Hz. I just put a PIn toggle inside the interrupt routine and it generated a 50Hz square pulse.

The I put    HAL_ADC_Start_DMA(&hadc1, (uint32_t *) buffer, 100); inside the Timer2 interrupt routine to be triggered also.

then I moved the pin toggle to the ADC interrupt routine to check the conversion frequency.

the frequency is correct but for a time around 0.5 just after reset, it means just after reset the ADC triggers the interrupt with a 100Hz frequency.

But the DMA interrupt gets fired very slowly around once per second. why it should be like this?

I don't know if you solved this or not, but I came across this scenario this weekend. I believe the issue is that in your ADC setup you specify 1 conversion, so it will only do 1 conversion (rank 1) per a trigger regardless of your buffer size. So with a 100Hz trigger, the buffer of 100 points will only be filled every second hence the DMA interrupt every second.
 
The following users thanked this post: VanitarNordic

Offline VanitarNordicTopic starter

  • Frequent Contributor
  • **
  • Posts: 277
  • Country: 00
Quote
I don't know if you solved this or not, but I came across this scenario this weekend. I believe the issue is that in your ADC setup you specify 1 conversion, so it will only do 1 conversion (rank 1) per a trigger regardless of your buffer size. So with a 100Hz trigger, the buffer of 100 points will only be filled every second hence the DMA interrupt every second.

Yes, I solved but it should do continuously (for whatever buffer size) after the trigger. number of conversions cannot be exceeded to more than 16
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf