Author Topic: Pulse generation using STM32  (Read 12622 times)

0 Members and 1 Guest are viewing this topic.

Offline VanitarNordicTopic starter

  • Frequent Contributor
  • **
  • Posts: 277
  • Country: 00
Pulse generation using STM32
« on: July 15, 2018, 08:48:56 pm »
Hi,

I want to generate a pulse something like this and use it as a trigger internally, I mean I don't want to have this pulse on MCU pins and therefore I should use Timers. I want to use it as an ADC trigger. What should I do?

 

Offline mbless

  • Regular Contributor
  • *
  • Posts: 227
  • Country: 00
Re: Pulse generation using STM32
« Reply #1 on: July 15, 2018, 11:37:41 pm »
One option is a timer in circular dma mode to fill the CCRx register.
 

Offline VanitarNordicTopic starter

  • Frequent Contributor
  • **
  • Posts: 277
  • Country: 00
Re: Pulse generation using STM32
« Reply #2 on: July 16, 2018, 03:51:47 am »
One option is a timer in circular dma mode to fill the CCRx register.

How can I check that the configurations work? toggling a PIN inside DMA interrupt?
 

Offline mbless

  • Regular Contributor
  • *
  • Posts: 227
  • Country: 00
Re: Pulse generation using STM32
« Reply #3 on: July 16, 2018, 12:53:26 pm »
Scratch that. I don't think you can use my method for internal triggering. It is used to drive variable duty cycle PWM, so you'd have to route an output pin to the ADC external interrupt.
 

Online newbrain

  • Super Contributor
  • ***
  • Posts: 1719
  • Country: se
Re: Pulse generation using STM32
« Reply #4 on: July 16, 2018, 01:24:18 pm »
A way to generate repeating bursts is using two timers: the first one triggers the second, set in one pulse mode with a repeat count equal to the number of pulses in the burst.
See the timer cookbook, at chapter 6.2.

The ADC should be triggered by the second timer CCR events, no need to use an actual output pin (using the EXTSEL bits in the ADC configuration registers)

Scratch that. I don't think you can use my method for internal triggering. It is used to drive variable duty cycle PWM, so you'd have to route an output pin to the ADC external interrupt.
The solution proposed looks quite interesting, and would need just one timer (to the expense of a DMA channel, though).
Are you sure it would not work? (I'm unable to prototype it at the moment)
After all, if a CC event is generated at the right time, why shouldn't it work as a trigger?
Nandemo wa shiranai wa yo, shitteru koto dake.
 
The following users thanked this post: VanitarNordic

Offline mbless

  • Regular Contributor
  • *
  • Posts: 227
  • Country: 00
Re: Pulse generation using STM32
« Reply #5 on: July 16, 2018, 01:34:55 pm »
A way to generate repeating bursts is using two timers: the first one triggers the second, set in one pulse mode with a repeat count equal to the number of pulses in the burst.
See the timer cookbook, at chapter 6.2.

The ADC should be triggered by the second timer CCR events, no need to use an actual output pin (using the EXTSEL bits in the ADC configuration registers)

Scratch that. I don't think you can use my method for internal triggering. It is used to drive variable duty cycle PWM, so you'd have to route an output pin to the ADC external interrupt.
The solution proposed looks quite interesting, and would need just one timer (to the expense of a DMA channel, though).
Are you sure it would not work? (I'm unable to prototype it at the moment)
After all, if a CC event is generated at the right time, why shouldn't it work as a trigger?

Your two timer solution looks good.

I used my solution for a peak-hold PWM driver where it has to change the duty cycle (CCRx) for each period. The problem I see in the current case is that when you don't want to trigger the ADC, CCRx is 0 but a CC event is still generated which would trigger the ADC.
 
The following users thanked this post: VanitarNordic, newbrain

Offline VanitarNordicTopic starter

  • Frequent Contributor
  • **
  • Posts: 277
  • Country: 00
Re: Pulse generation using STM32
« Reply #6 on: July 16, 2018, 05:36:29 pm »
Quote
A way to generate repeating bursts is using two timers: the first one triggers the second, set in one pulse mode with a repeat count equal to the number of pulses in the burst.
See the timer cookbook, at chapter 6.2.

The ADC should be triggered by the second timer CCR events, no need to use an actual output pin (using the EXTSEL bits in the ADC configuration registers)

You mean Master/Slave? I mainly use CubeMX, I'll so appreciate if you explain by that. thank you
 

Offline mbless

  • Regular Contributor
  • *
  • Posts: 227
  • Country: 00
Re: Pulse generation using STM32
« Reply #7 on: July 16, 2018, 10:37:26 pm »
Quote
A way to generate repeating bursts is using two timers: the first one triggers the second, set in one pulse mode with a repeat count equal to the number of pulses in the burst.
See the timer cookbook, at chapter 6.2.

The ADC should be triggered by the second timer CCR events, no need to use an actual output pin (using the EXTSEL bits in the ADC configuration registers)

You mean Master/Slave? I mainly use CubeMX, I'll so appreciate if you explain by that. thank you

Did you read Section 6.2 of link newbrain gave? It explains what settings to use, most of which should be in CubeMX.
 

Online newbrain

  • Super Contributor
  • ***
  • Posts: 1719
  • Country: se
Re: Pulse generation using STM32
« Reply #8 on: July 17, 2018, 07:24:06 am »
You mean Master/Slave? I mainly use CubeMX, I'll so appreciate if you explain by that. thank you

Yes, you need to use one general purpose timer as Master and one advanced-control timer as Slave.
IIRC from other threads you've started, you are using an STM32F4xx so TIM1 as advanced-control and TIM2 as general purpose should be available.

The need for an advanced control slave is due to repetition counter (TIM1_RCR) support:
Code: [Select]
If the repetition counter is used, the update event (UEV) is generated
after upcounting is repeated for the number of times programmed in the
repetition counter register plus one (TIMx_RCR+1).
that, together with with the one pulse mode (OPM bit in TIM1_CR1):
Code: [Select]
Bit 3 OPM: One pulse mode
0: Counter is not stopped at update event
1: Counter stops counting at the next update event (clearing the bit CEN)
and the use of a CCR will give us exactly what you need.
Figure 37 in the link I gave is very clear.

For CubeMX, see the attached pictures: ITR1 (trigger from TIM2) has to be selected as trigger source in TIM1, One Pulse Mode set, and update event as TRGO in TIM2.
The ADC must be triggered by the CCR1 of TIM1.

Up to you to set values/pre-scalers/interrupts etc. etc...

Of course other alternative configurations can be used, e.g. with TIM8 you don't need to set a CCR register and can directly use the update event to trigger the ADC...

The STM32 timers are a bit unfriendly, but definitely flexible and powerful.

HTH
Nandemo wa shiranai wa yo, shitteru koto dake.
 
The following users thanked this post: VanitarNordic

Offline VanitarNordicTopic starter

  • Frequent Contributor
  • **
  • Posts: 277
  • Country: 00
Re: Pulse generation using STM32
« Reply #9 on: July 18, 2018, 12:03:30 pm »
my intention of doing this is to capture a specific part of the input signal by the ADC and just sample that part. I tried to mach the ADC trigger timing with that specific signal part. I don't now if it is a good method or not
 

Offline VanitarNordicTopic starter

  • Frequent Contributor
  • **
  • Posts: 277
  • Country: 00
Re: Pulse generation using STM32
« Reply #10 on: July 18, 2018, 01:06:44 pm »
Besides, I think this is not applicable as a trigger for the ADC in DMA mode and it is just for the ADC regular conversions.
 

Online newbrain

  • Super Contributor
  • ***
  • Posts: 1719
  • Country: se
Re: Pulse generation using STM32
« Reply #11 on: July 18, 2018, 01:19:08 pm »
my intention of doing this is to capture a specific part of the input signal by the ADC and just sample that part. I tried to mach the ADC trigger timing with that specific signal part. I don't now if it is a good method or not
Depending on the sampling rate and the burst repetition rate, there are many different ways.

For example, one could use DMA in circular mode (or interrupts, if the sampling rate is low enough) to continuously fill a buffer large enough for your needs (double the needed samples?), then when the "interesting" part of the signal arrives, just DMA them out of the buffer in your working memory.
If done right, latencies can be zero or even negative, and the burst trigger can be anything (timer, external pin, analogue watchdog, SW etc.): this is a bit how a DSO work.

Besides, I think this is not applicable as a trigger for the ADC in DMA mode and it is just for the ADC regular conversions.
Setting the DMA bit will generate a DMA request at the end of conversion, regardless of the ADC trigger source.
But I might have misinterpreted your statement.
Nandemo wa shiranai wa yo, shitteru koto dake.
 
The following users thanked this post: VanitarNordic

Offline VanitarNordicTopic starter

  • Frequent Contributor
  • **
  • Posts: 277
  • Country: 00
Re: Pulse generation using STM32
« Reply #12 on: July 18, 2018, 01:53:50 pm »
Quote
Depending on the sampling rate and the burst repetition rate, there are many different ways.

For example, one could use DMA in circular mode (or interrupts, if the sampling rate is low enough) to continuously fill a buffer large enough for your needs (double the needed samples?), then when the "interesting" part of the signal arrives, just DMA them out of the buffer in your working memory.
If done right, latencies can be zero or even negative, and the burst trigger can be anything (timer, external pin, analogue watchdog, SW etc.): this is a bit how a DSO work.

Actually I want the ADC in the highest sampling rate, 2.4Msps for each channel or around 0.5uS for one conversion. The question with your method is that if we run DMA continuously to fill the buffer (it will fire a DMA interrupt ant the end of all conversions), then I would not know which element of this buffer refers to the start of the interesting part or which element shows the end. for example if we have a buffer with the size of 1000, then start is which one 0..999?
I think the ADC of DSO also work continuously except we limit the conversion boundaries manually by knobs

Quote
Setting the DMA bit will generate a DMA request at the end of conversion, regardless of the ADC trigger source.
But I might have misinterpreted your statement.

I think triggering for the DMA should be something like a clock, not a rising edge to be used as a switch for conversion start, but in regular conversion, one pulse trigger will handle one conversion. I have tested these many times that the reason I reached to this conclusion that I have to provide bursts in high frequency if I want to trigger DMA conversions
 

Online newbrain

  • Super Contributor
  • ***
  • Posts: 1719
  • Country: se
Re: Pulse generation using STM32
« Reply #13 on: July 18, 2018, 02:49:59 pm »
Actually I want the ADC in the highest sampling rate, 2.4Msps for each channel or around 0.5uS for one conversion. The question with your method is that if we run DMA continuously to fill the buffer (it will fire a DMA interrupt ant the end of all conversions), then I would not know which element of this buffer refers to the start of the interesting part or which element shows the end. for example if we have a buffer with the size of 1000, then start is which one 0..999?
When the trigger arrives, one can read the DMA_SxNDTR register to know the offset to use in the circular buffer.
Of course, as you are running the ADC at the maximum speed timing is critical.

I think triggering for the DMA should be something like a clock, not a rising edge to be used as a switch for conversion start, but in regular conversion, one pulse trigger will handle one conversion. I have tested these many times that the reason I reached to this conclusion that I have to provide bursts in high frequency if I want to trigger DMA conversions
The DMA is actually triggered by the ADC, but yes, you'll get one DMA request per conversion!

Since you intend to run the ADC at the maximum rate, if the needed samples are less than or equal to 16, you could simply program a regular sequence with the needed channel repeated n<=16 times, set the SCAN bit in ADC_CR1 and collect the samples with DMA. No need for double timers or other complications, just trigger the scan when it's needed and use either the conversion complete interrupt (with EOSC set to 0) or (better, in this case) the DMA transfer complete interrupt to signal the end of the burst.

Nandemo wa shiranai wa yo, shitteru koto dake.
 
The following users thanked this post: VanitarNordic

Offline VanitarNordicTopic starter

  • Frequent Contributor
  • **
  • Posts: 277
  • Country: 00
Re: Pulse generation using STM32
« Reply #14 on: July 18, 2018, 03:25:46 pm »
Quote
When the trigger arrives, one can read the DMA_SxNDTR register to know the offset to use in the circular buffer.
Of course, as you are running the ADC at the maximum speed timing is critical.

Thank you. this method sounds the best actually no one knew about this and you are the first person who noted that. By this, I can match a timer Interrupt with the starting point of the interesting part and get the array element of the DMA buffer which refers to that. The delay of the interrupt is around 3 to 4uS which is okay for this application.

may I ask you how can I read the value of the DMA_SxNDTR register? is there any HAL function for that?
 

Online newbrain

  • Super Contributor
  • ***
  • Posts: 1719
  • Country: se
Re: Pulse generation using STM32
« Reply #15 on: July 18, 2018, 03:42:13 pm »
Quote
When the trigger arrives, one can read the DMA_SxNDTR register to know the offset to use in the circular buffer.
Of course, as you are running the ADC at the maximum speed timing is critical.

Thank you. this method sounds the best actually no one knew about this and you are the first person who noted that. By this, I can match a timer Interrupt with the starting point of the interesting part and get the array element of the DMA buffer which refers to that. The delay of the interrupt is around 3 to 4uS which is okay for this application.

may I ask you how can I read the value of the DMA_SxNDTR register? is there any HAL function for that?

In stm32f4xx_hal_dma.h:
Code: [Select]
#define __HAL_DMA_GET_COUNTER(__HANDLE__) ((__HANDLE__)->Instance->NDTR)
Or, in  stm32f4xx_ll_dma.h:
Code: [Select]
__STATIC_INLINE uint32_t LL_DMA_GetDataLength(DMA_TypeDef* DMAx, uint32_t Stream)
But, really, I would not bother!
Doing something as:
Code: [Select]
DMA2_Stream1->NDTR;is even clearer...

Don't disregard my last proposal, though: if suitable, it's the one with the simpler code and the lighter MCU load (CPU and DMA).
Nandemo wa shiranai wa yo, shitteru koto dake.
 
The following users thanked this post: VanitarNordic

Offline VanitarNordicTopic starter

  • Frequent Contributor
  • **
  • Posts: 277
  • Country: 00
Re: Pulse generation using STM32
« Reply #16 on: July 18, 2018, 04:22:36 pm »
May I ask you what should I write in the argument of
Code: [Select]
__HAL_DMA_GET_COUNTER ?

The used DMA is DMA2_Stream0

Besides, in your short-code, I assigned like this:
Code: [Select]
result = DMA2_Stream0->NDTR which result has defined as unit32_t somewhere.

is it correct?
 

Online newbrain

  • Super Contributor
  • ***
  • Posts: 1719
  • Country: se
Re: Pulse generation using STM32
« Reply #17 on: July 18, 2018, 06:08:56 pm »
You're welcome to ask!

__HAL_DMA_GET_COUNTER takes a DMA handle as argument.

If you let CubeMX generate the code for you, there's probably something either in main.c or dma.c such as:
Code: [Select]
DMA_HandleTypeDef hdma_adc?; // ? is the number of the ADC peripheral

Frankly, I always used the direct register access, as it's also faster (and here you need to be careful with timings).

As you correctly point out, you need to assign it to an uint_16 (the register is 16 bits wide) or uint_32.
Remember that NTDR gives you the number of remaining DMA transfers.


Nandemo wa shiranai wa yo, shitteru koto dake.
 
The following users thanked this post: VanitarNordic

Offline VanitarNordicTopic starter

  • Frequent Contributor
  • **
  • Posts: 277
  • Country: 00
Re: Pulse generation using STM32
« Reply #18 on: July 18, 2018, 07:18:31 pm »
Thank you very much.

the code that worked was this:

Code: [Select]
result = __HAL_DMA_GET_COUNTER(hadc1.DMA_Handle);
which handles the same results as your short-code, but as I analyze the sampled signal part, it is not in harmony with expectations. I check the timings like this: one GPIO PIN state change inside timer interrupt and another PIN state inside DMA interrupt.


Code: [Select]
void TIM3_IRQHandler(void) {

HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, 1);

HAL_TIM_IRQHandler(&htim3);

}

void DMA2_Stream0_IRQHandler(void) {

HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, 0);

HAL_DMA_IRQHandler(&hdma_adc1);

}


« Last Edit: July 18, 2018, 07:20:53 pm by VanitarNordic »
 

Offline VanitarNordicTopic starter

  • Frequent Contributor
  • **
  • Posts: 277
  • Country: 00
Re: Pulse generation using STM32
« Reply #19 on: July 18, 2018, 07:29:08 pm »
another weird thing is that as much as change the buffer size, this DMA counter value is identical (it says 40) which I think it should not be. besides any value for the buffer which is not a coefficient of 100 (100, 200, 300 ...) makes this number and timing pulse unstable. I mean if I put 100, it is okay, but if I put 120, it makes it unstable
 

Online newbrain

  • Super Contributor
  • ***
  • Posts: 1719
  • Country: se
Re: Pulse generation using STM32
« Reply #20 on: July 19, 2018, 09:09:54 am »
another weird thing is that as much as change the buffer size, this DMA counter value is identical (it says 40) which I think it should not be. besides any value for the buffer which is not a coefficient of 100 (100, 200, 300 ...) makes this number and timing pulse unstable. I mean if I put 100, it is okay, but if I put 120, it makes it unstable
Without knowing the rest of the setup, it's a bit difficult to diagnose...

Given that the start of the sampling window is periodic, I can expect that for some values of the buffer length you'll always get the same results from NDTR, while for others lengths that are not a divisor of the total samples in one full period results will vary.
Nandemo wa shiranai wa yo, shitteru koto dake.
 
The following users thanked this post: VanitarNordic

Offline VanitarNordicTopic starter

  • Frequent Contributor
  • **
  • Posts: 277
  • Country: 00
Re: Pulse generation using STM32
« Reply #21 on: July 19, 2018, 10:29:52 am »
Quote
Without knowing the rest of the setup, it's a bit difficult to diagnose...

Given that the start of the sampling window is periodic, I can expect that for some values of the buffer length you'll always get the same results from NDTR, while for others lengths that are not a divisor of the total samples in one full period results will vary.

Thank you for the response.

I attached the code. it is simple. a few configurations which DMA fills the buffer and UART sends the average value to the serial in a while loop. as the GPIO pulse confirms (rising in the timer interrupt, falling in the DMA interrupt) it must read the interesting part which starts from 40 in the buffer. but in practice it does not.
« Last Edit: July 19, 2018, 10:32:46 am by VanitarNordic »
 

Offline VanitarNordicTopic starter

  • Frequent Contributor
  • **
  • Posts: 277
  • Country: 00
Re: Pulse generation using STM32
« Reply #22 on: July 19, 2018, 10:46:11 am »
if it still did not work, I have to cut the interesting part with an analog switch and run the ADC continuously which still I have to know where is the start point, but in this case, anywhere except signal will have 0 or less than 10 in ADC values, if we neglect noises. But still it is not a good solution you know. it should be easier and straightforward than this. i don't know what is the problem
 

Online newbrain

  • Super Contributor
  • ***
  • Posts: 1719
  • Country: se
Re: Pulse generation using STM32
« Reply #23 on: July 20, 2018, 04:06:59 pm »
I did not have much time to check your code (you might know about this "real life" thing that tends to interfere ;D), and I'm going to be up in the mountains for a week without internet in a few hours...

Some things I noticed:
  • The loop in main() will take longer to execute than interval set on TIM3 (I assume that's your timebase).
    TIM3 interval = (60000*10)/120 us = 5000 us = 5ms
    UART transmission time (at 9600bps, even ignoring all the rest and the HAL overhead) = (5+2) / 960 s ~= 7.3ms
  • The main loop is completely missing any synchronization with TIM3, and is reading samples in a fixed position.
  • I have some problems in understanding how you intend to synchronize the sampling windows with an external waveform, but this is up to you. :-//

For the first point, increasing the UART speed is more or less the only solution: I usually find no problems with 115200bps or even higher, when transmitting. Using the HAL for receiving is an exercise in frustration. |O

For the second point, you could, in the TIM3 ISR (be wary of the possible latency that will introduce some jitter):
  • Read the NDTR register in a volatile variable (you might even use another DMA channel triggered by TIM3 to do this, to reduce/avoid the jitter)
  • Stop the ADC
  • Set a flag to tell the main loop that data is ready
In the main loop:
  • Wait for the flag
  • Read and elaborate the buffer from (buffersize - NDTR) backward for the needed number of samples (modulo buffersize)
  • Restart the ADC: according to the DS it just takes 2-3us, if you bypass the HAL
  • Reset the flag

But since the number of samples seems to be less than 256, why not use the two timers solution (and DMA) I originally proposed?
Nandemo wa shiranai wa yo, shitteru koto dake.
 
The following users thanked this post: VanitarNordic

Offline VanitarNordicTopic starter

  • Frequent Contributor
  • **
  • Posts: 277
  • Country: 00
Re: Pulse generation using STM32
« Reply #24 on: July 20, 2018, 04:25:52 pm »
Quote
I have some problems in understanding how you intend to synchronize the sampling windows with an external waveform, but this is up to you.

The TIM3 interrupt is in harmony with the start point of the input signal (start of the interesting part of the input signal). Therefore it would be the start-point for ADC conversions or ADC DMA counter checkpoint.
I have set the buffer length to cover the whole interesting part. therefore when the ADC DMA buffer gets filled, it raises a DMA interrupt. Therefore inside the DMA interrupt, I put another GPIO PIN change to verify the conversions tail. on the oscilloscope, this square pulse should match with the interesting part of the signal, therefore I can be sure timings are correct.

Quote
But since the number of samples seems to be less than 256, why not use the two timers solution (and DMA) I originally proposed?

I have to burst the ADC with 30MHz bursts (as datasheet says) to achieve its maximum channel sampling which is not possible with timer triggering and burst method. The timer works at 60MHz itself.

 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf