HCS08 TPM "input capture"  both edges

取消
显示结果 
显示  仅  | 搜索替代 
您的意思是: 

HCS08 TPM "input capture"  both edges

9,168 次查看
EtherJones
Contributor II
I have an application where I need to read an input PWM signal that can vary from 0% to 100% duty cycle.
 
I assume that TPM "input capture" was designed for this purpose and is the cleanest way to do it?
 
If I set up the TMP channel to trigger on both edges (rising and falling),  what is the best way for my interrupt routine to determine whether it was a rising or falling edge which triggered the interrupt?   My ISR needs to be able to determine this, so it knows whether to just store the counter value (for the beginning of the pulse) or to compute the pulse width (for the end of the pulse).
 
Also, what is the best way to handle 0% and 100% duty cycles, since there would not be any interrupts generated?
 
I'm sure there are a gazillion ways to handle these situations, but I am wondering how experienced HCS08 programmers usually do it.
 
Thanks
标签 (1)
0 项奖励
回复
13 回复数

3,954 次查看
peg
Senior Contributor IV
Hi,
 
This does not come from direct experience, just thinking out loud. (Never actually used either edge trigger)
 
To determine the edge type, just read the pin as GP input in the ISR.
 
Set a compare value just bigger than the PWM period at each edge and if it triggers, you already know the level and can now call it 0 or 100%.
 
Regards
David
 
0 项奖励
回复

3,954 次查看
EtherJones
Contributor II
"Set a compare value just bigger than the PWM period at each edge and if it triggers, you already know the level and can now call it 0 or 100%."
 
David, could you flesh this out just a bit more.  I'm not sure I understand what you mean by a compare value "bigger than the PWM period".

 
0 项奖励
回复

3,954 次查看
peg
Senior Contributor IV
Hi,
 
Let's assume that the PWM is high = on (high always is 100%)
 
So the rising edges will always be the same distance apart.
So at each rising edge you load up a compare value with this time+current.
If the compare occurs you are at 0% or 100%, you know the last level so you know which.
You could also set the modulo of the counter to be a bit bigger than the period and when overflow occurs check that you had both transitions since the last overflow.
Running the modulo at other than $FFFF creates a little more work in handling the overflow in the width measuring part so as usual its a trade of between speed, available resources.
 
Regards
David
 

Message Edited by peg on 2006-11-1501:42 PM

0 项奖励
回复

3,954 次查看
bigmac
Specialist III
Hello,
 
This is my reading of what I think Peg is alluding to, for detecting the 0 and 100 percent duty cycle cases.
  1. Use another timer channel and set this up for output compare interrupt (software interrupt only).
  2. Within the input capture ISR, update the output compare setting so it corresponds to the current input capture value, plus the measured total period for the PWM signal, plus a little bit extra to allow for jitter, etc.
  3. With normal input capture interrupt operation, the output compare interrupt should never occur because the value is continuously updated before there is a matching output compare.
  4. It the input capture interrupts should cease, the output compare interrupt would occur, and the current state of the input signal would indicate whether 0 percent or 100 percent duty cycle.
Regards,
Mac
 
0 项奖励
回复

3,954 次查看
EtherJones
Contributor II
 
I do not have a spare TPM channel available.  Only one channel was allocated to the input capture option.
So... here's an alternative approach I've been considering.  It does use more processor time than an edge-detection interrupt, but it's simple and straightforward and easily handles the 0% and 100% cases seamlessly. 
 
Any thoughts?

Each TPM module is capable of generating an interrupt every time the module counter overflows.
Since we are going to use TPM1 to generate 20KHz PWM, it could also generate a 20KHz interrupt.  This is fast enough to sample the input line (input period is 2KHz); those samples could be used to calculate the pulse width.  This discussion assumes that the input period is known and fixed; the "duty cycle" is calculated by measuring the pulse width and dividing this measured width by the peiod.
 
definitions for the following discussion

IP - input pin containing input PWM we are trying to capture. The TPM channel for this pin would be disabled and the pin handled as GPIO
 
AL - lo accumulator
 
ALM - max value of AL, a constant initialized to be slightly longer than the period of the input PWM
 
AH - hi accumulator
 
AHM - max value of AH, a constant initialized to be slightly longer than the period of the input PWM
 
DC - duty cycle calculated by this service routine, available for other processes to read

A service routine for the 20KHz interrupt could do the following:
 
read the state of IP
 
depending on the previous and present state of IP, do the following:
 
previous lo, present hi:  set AL=0.  set AH=1.
 
previous hi, present lo:  use AH to calculate new value for DC (not to exceed 100%).  Then set AL=1 and set AH=0.
 
previous lo, present lo:  if AL is less than ALM then increment AL; otherwise set DC to zero.
 
previous hi, present hi:  if AH is less than AHM then increment AH; otherwise set DC to 100.
 
0 项奖励
回复

3,954 次查看
peg
Senior Contributor IV
Hi Ether,
 
Before going down this route, I would compare the resolution of your proposed method with the possible errors generated at near 0/100% using the TPM. Also you would need to compare this with the resolution of the device generating the PWM.
 
If you are restricted to 1 channel and an overflow you can flip the edge to be detected in the ISR to keep track of which edge you are at. If you miss edges but know the period you should be able to "repair" any incorrect values. This would simply mean it might take two periods to update the value. Then use a "double period and a bit" timer modulo to detect when exactly 0/100.
 
Regards
David
 
0 项奖励
回复

3,954 次查看
peg
Senior Contributor IV
Hi all,
I am going to try to elaborate on my previous post.
The last method proposed by Ether is to attempt to sample a 2kHz waveform at 20kHz.
Now while this may keep Mr Nyquist happy it will only give a duty cycle resolution of 10%.
Not real flash!
Also to be considered but not yet revealed is the resolution of the device producing the PWM signal.
No use looking for 0.5% duty cycle if it will never occur.
Using the TPM will give a resolution of whatever you can clock the TPM module at with probably a little less due to the problems near 0/100%.
So now I am proposing that the input captures trigger edge is flipped after each capture. Now this should work fine except at the problematic 0/100% region. So what i am saying now is if we take too long to prepare for the next edge - no problem we will just keep on waiting - we will get it next time. All that is needed is to compare the result with the period and if bigger than the period, subtract 1 period.
 
The downside to this would be that:
1. we take two periods to update the value
2. any error in the period becomes an error in the value.
 
Now in order to allow for this too occur we need to load our compare register (or timer modulo) with a value that is two periods and a bit more to allow deetection of the 0 and 100% cases. Again the only downside is that it will take two periods to update.
 
These small delays in update I feel, far outweigh the lost resolution from ignoring the TPM all together.
 
Regards
David
 
0 项奖励
回复

3,954 次查看
bigmac
Specialist III
Hello Ether,
 
I am not sure of the resolution you are trying to achieve for the PWM detection, nor am I aware of the bus frequency you intend to use.  For the moment I will assume you need 1 percent resolution and are using a bus rate of 8 MHz - and let's see how the figures work out.
 
For a 2000 Hz incoming PWM signal (with a period of 500us), 1 percent resolution would correspond with 5 microseconds, or 40 bus cycles.  Is it possible to enter the TPM channel ISR, read the IC value, and clear the flag, all within 40 bus cycles?  Probably yes!  This would indicate the possibility of achieving the assumed resolution for 1% and 99% percent duty cycle , using a single TPM channel.
 
If the next instruction, after the one that cleared the flag, read the actual status of the input, and this was found to be opposite to that expected, i.e low after a positive edge IC, and vice versa, it can be assumed that a very short pulse had occurred (less than 1% or greater than 99% duty cycle).  The IC edge for the next event would not be changed in this case.
 
For those cases where the IC interrupt does not occur, you will need to adopt a process using the timer overflow, as previously outlined by Peg.  However, there is a caution - the timer overflow ISR processing cycles (and the processing cycles of any other ISR) may degrade from the desired resolution as the duty cycle approaches 0% and 100%.  You would need to minimize your use of interrupts for other purposes, and quite likely you will need to re-enable interrupts within these "other" ISRs, which will need very careful programming to avoid side effects.
 
And now for something completely different -
 
If the incoming PWM signal changes duty cycle only very slowly, you might alternatively consider filtering the signal with a suitable analog low pass filter, and then applying to an ADC channel for the measurement process.  Multiple readings could be taken to average out any ripple component.
 
Regards,
Mac
 
0 项奖励
回复

3,954 次查看
EtherJones
Contributor II
 
I think I've got an approach that addresses the 0%, 100%, near 0%, and near 100% cases, and uses the TPM input capture (one channel only) to obtain good resolution.
 
The trick is to let the input capture ISR just capture and store data, and let the task which needs the duty cycle compute it from this data.

Set up TPM2C0 for input capture, both edges, interrupt enabled, serviced by ISR_TPM
 
Set up an interrupt-driven timed task ISR_RTT executing at 2000Hz.  This is the main control task that needs the input PWM value for its computations.

ISR_RTT increments a counter.
 
ISR_TPM reads the latched TPM counter value and the logic level of the input pin, and stores them in a ring buffer.  Call these values C1 and L1, respectively.   Similarly, C2 and L2 are the previous values, and C3 and L3 are the values before that.   The ISR_RTT counter is read and stored in R1.
 
ISR_RTT contains the following logic to compute the duty cycle (DC):
 
Let R be the present value of the ISR_RTT counter.
 
if R-R1 is greater than the period of the PWM being measured, then set DC to 0% or 100% depending on the value of L1.  Otherwise, do this:
 
L1=0 and L2=1?  Compute DC using C1-C2 (but not to exceed 100%)
L1=0 and L2=0?  this is the near-zero condition.  Set DC=0%.  Sanity check by testing C1-C2.
L1=1 and L2=1?  this is the near-100 condition. Set DC=100%.  Sanity check by testing C1-C2.
L1=1 and L2=0?  you're in the middle of a pulse. do the following:
L3=1?  Compute DC using C2-C3 (but not to exceed 100%)
L3=0?  this is the near-zero condition.  Set DC=0%.  Sanity check by testing C2-C3.
 
 
0 项奖励
回复

3,954 次查看
EtherJones
Contributor II
Let's assume that the PWM is high = on (high always is 100%)
 
So the rising edges will always be the same distance apart.
So at each rising edge you load up a compare value with this time+current.
If the compare occurs you are at 0% or 100%, you know the last level so you know which.
You could also set the modulo of the counter to be a bit bigger than the period and when overflow occurs check that you had both transitions since the last overflow.
Running the modulo at other than $FFFF creates a little more work in handling the overflow in the width measuring part so as usual its a trade of between speed, available resources.
 
Just a quick "ACK" to let you know I read your latest post.    I think I get the gist of what you're saying but I'll have to ponder it a bit more.
 
Thanks.
0 项奖励
回复

3,954 次查看
EtherJones
Contributor II

here's my pseudo code:

initialization:
- set up TPM2 CH0 for input capture
- set to interrupt on both edges

here's the ISR pseudocode (bare bones):
- determine whether interrupt was caused by leading edge or trailing edge of pulse
- if leading edge (beginning of pulse), grab the timer counter and store it
- if trailing edge, grab the timer counter, and compare it to the previously stored value from the leading edge to compute a pulse width
 
The problem is, how do I determine if the interrupt was triggered by the leading edge or the trailing edge?  I don't see anywhere in the data sheet where there's a register I can read that will tell me.  Am I missing something?  Is there such a flag, but I am overlooking it?
 
Or, do I have to improvise?  I could try reading the pin level, but that's not robust because if the duty cycle is close to 0 or 100, the level could have changed again by the time my ISR gets around to reading it.
Also, even if there were a flag I could read, it still doesn't solve the problem of 0 and 100% duty cycle.  For example, if the duty cycle changes from, say, 30% to 0%, then there are no more interrupts, so my ISR stops updating the pulse width calculation, and so the calculated value gets stuck at 30% even though it's really 0%.
 
I can't be the first person to raise this question.  I'm sure there must be a tried-and-true method that the HCS08 gurus use.  I'd rather not re-invent the wheel.  Could someone could post a method or post a link to web page that addresses this issue?
 
Many many thanks.
 
0 项奖励
回复

3,954 次查看
peg
Senior Contributor IV
Hi Ether,
 
If you could limit the range of the PWM to say 5-95% this would make things easier!!!!
 
However my method will indeed fallover with high resolution PWM.
 
If you need to handle this I would suggest using two timer channels tied together with one set for falling and the other set for rising edge trigger.
 
My method for handling the full 0 and 100% cases still stands. But of course relies on the PWM frequency remaining fixed and only the duty cycle changing.
 
If anybody has any other ideas please feel free to pipe in!
 
Regards
David
0 项奖励
回复

3,954 次查看
bigmac
Specialist III
Hello,
 
Another way of tackling this issue is to use a single timer channel, but to initially set input capture for positive edge only.  Then, within the timer channel ISR, change the status so the next input capture will occur on a negative edge only.  Then repeat for a positive edge only, etc.  This way the particular edge that caused the interrupt can be readily determined.  Again, this method will fail for instances where the next input capture occurs before the previous input capture value can be read, and the flag cleared.  If this is a possibility, you would need to use two timer channels, as Peg suggested.
 
To detect the no input capture interrupt cases, you could also do this using the timer overflow interrupt.  The exact process involved would depend on the PWM period relative to the timer overflow period.  Otherwise, it would seem the method described by Peg would require yet another timer channel.  It depends on how quickly you need to detect these limit cases.
 
Regards,
Mac
 
0 项奖励
回复