smartpin questions (was: how to capture time on pin change)
ManAtWork
Posts: 2,082
Let's say I want to count position of a step/dir signal pair. That's easy, smart pin mode %01101 does "accumulate A-input positive edges with B-input supplying increment (B=1) or decrement (B=0)".
For a servo it would be useful to also measure velocity. The control loop samples the position counter at a rate of serveral 1000 times a second. At low speeds the velocity (position delta) dithers between 0 and 1 for positive or 0 and -1 for negative velocity. This is very coarse and results in a stepper motor like noise.
If I additionally recorded a time-stamp of the last step signal edge I could calculate velocity as (delta position)/(delta time) which gives a very high resolution even for speeds below 1 step per loop period.
I haven't found a smart pin mode for capturing (absolute) time. There are modes for measuring time between edges but I think they are not ideal for this purpose because I don't know in advance how many edges are to be counted/measured in the next period. Maybe the best method would be to trigger an interrupt on each positive edge of the step signal and record the current time with a GETCT instruction. Does anybody have a better idea?
Maximum step frequency is 1MHz or a bit higher. If the interrupt needs only one single instruction it won't load the cog too much. An incremental encoder works the same way just with a quadrature signal instead of a step/dir pair (mode %01011 instead of %01101). Input filtering can be used to avoid interrupt overload caused by a high frequency oscillation when the optical sensor of the encoder is close to the edge of a codewheel line. For capturing time-stamps of a quadrature signal change the interrupt has to be triggered on both edges of both A and B inputs.
For a servo it would be useful to also measure velocity. The control loop samples the position counter at a rate of serveral 1000 times a second. At low speeds the velocity (position delta) dithers between 0 and 1 for positive or 0 and -1 for negative velocity. This is very coarse and results in a stepper motor like noise.
If I additionally recorded a time-stamp of the last step signal edge I could calculate velocity as (delta position)/(delta time) which gives a very high resolution even for speeds below 1 step per loop period.
I haven't found a smart pin mode for capturing (absolute) time. There are modes for measuring time between edges but I think they are not ideal for this purpose because I don't know in advance how many edges are to be counted/measured in the next period. Maybe the best method would be to trigger an interrupt on each positive edge of the step signal and record the current time with a GETCT instruction. Does anybody have a better idea?
Maximum step frequency is 1MHz or a bit higher. If the interrupt needs only one single instruction it won't load the cog too much. An incremental encoder works the same way just with a quadrature signal instead of a step/dir pair (mode %01011 instead of %01101). Input filtering can be used to avoid interrupt overload caused by a high frequency oscillation when the optical sensor of the encoder is close to the edge of a codewheel line. For capturing time-stamps of a quadrature signal change the interrupt has to be triggered on both edges of both A and B inputs.
Comments
The problem is that I don't have a stable, repeating input frequency. The encoder position or step/dir command can stop at any moment or even reverse direction in the middle of a measurement period. Er, period is probably the wrong word. The P2 docs use "period" for the time between A/B input edges.
If the current period doesn't complete (step sequence stops) then no result is stored if I understand correctly. I'll draw a timing diagram to illustrate it...
For the fourth sample velocity is (2-1)/(336_789-243567)=1.073 counts/ms.
If the step pulses stop after the fourth sample then the fifth sample would give dp and dt both zero. Division by zero is undefined but as no pulses arrived velocity can be assumed to be zero.
If you are sure you can process each step one by one then you can measure just the duration of each step - mode %10000_0. But most likely you'll be wanting to also smoothly handle multiple steps per update, in that case, as Chip indicated, you'll be wanting to know both the step count and the duration over which they occurred. This requires two smartpins to give the two measurements - modes %10111_0 and %10101_0 respectively.
P2 can capture sysclks on either/both edges, and can do that for single, or over many (X) edges.
The issue may be around your wide dynamic range :
Single edges would work fine for lowest speeds (let's say to ~10kHz / 100us report rates), and you could run another pin cell in parallel, that captures every X events.
That second cell will be an average, and will not precisely catch a stall, but would be used for > 10kHz ( eg X = 1000, would read up to 10MHz at 100us report rate )
If you know the appx step rates at any ms, you could vary X to dynamically scale.
Addit: P2 will capture-and-auto-clear, so it will always give an edge-to-(Xth)edge result.
I'm rusty on how P2 manages overflows : ie if a) the first reading is given to users (later ones ignored), or if b) the most recent reading is given ?
If you poll it often enough, velocity will not change much
Low pass filters have a disadvantage: phase delay. Delays are critical in a motion control application. Delays in the feedback loop limit the gain or can cause overshot. Delays in the command path are no problem as long as they are constant. Variable delay distorts the toolpath trajectory and has to be avoided. My solution has the advantage that delta time is always as close to the sampling period as possible. So phase delay is not perfectly constant but as close as it could.
Of course, if there are no or very few pulses you have no information about velocity until the next edge arrives. Maybe the best solution is to caclulate a lower and upper limit based on the information available and make a guess that's somewhere in between when there is no exact value (last position info is outdated).
So the interval measurement modes of the smart pins are not really necessary. I could simply wait for a counter-change event of the quadrature or step/dir decoder and capture time with a GETCT. As the P2 supports waiting with timeout I could handle the stall case conveniently. If there were no pulses during the timeout duration T then I know that velocity must be less than 1/T. So I can adjust the measured velocity to the "best guess" even when no pulses/edges arrive.
High performance resolvers that emulate an encoder, maybe at the drive, have to use interpolation at the very least. And probably extrapolation too. The resolver frequency is only in the kHz whereas encoders have to be good for low MHz at least. In both cases, of interpolation and extrapolation, they should be using filtering techniques to make the emulation more accurate.
Yes, that should work and if there were no other possibility I'd have to do it that way. However, I'd like to avoid dynamical adaption if possible. You had to handle special cases as direction changes very carefully. Case-switching or dynamical parameter adaption could cause clicks and jerks or non-linear behaviour if not carefully designed and debugged.
And yes, my proposal also involves some case-switching but I think it's easy to prove that the "conditional corrections" applied always make the measurement better and not worse.
Ah thanks. This is a bit more understandable as the original documentation. I still don't understand every detail. But that's the good thing about the propeller. On other processors it's "eat or die". With the propeller you always have the choice. Peripheral hardware can help to make some things more efficiently but your're not bound to use it. You could always do it in software (bitbang) if the hardware doesn't fit.
Suddenly, I had random crashes depending on the number of instructions I inserted or removed. I took a look at the p2asm listing and found out that the compiler took me literally and put the actual address of the cntLoop label as immediate parameter instead of what I expected: #(cntLoop-PC)
I replaced the jmprel with a jmp and it all works, now.
Next problem: waitse1 doesn't work, it waits forever. To check if my setse1 is wrong I replaced waitse1 with a testp...wz + if_nz jmp loop. It also waits forever. So I think the problem is that the IN register bit does not become high when the counter is updated.
In the smartpin docs I read: "The IN bit serves as a flag to indicate to the cog(s) that the smart pin has completed some function or an event has occurred, and acknowledgment is perhaps needed." In lack of detailed information I assumed that the IN bit gets set automatically for the mode "%01011 = A/B-input quadrature encoder". Probably this is not the case. Do I have to set something in the lowlevel pin mode bits so that the event-flag is routed to IN?
If you want to wait for a encoder change, you can always do something like that:
In encoder mode the lowlevel pin mode is useful to set a pullup, or a schmitt-triger input, or to enable the glitch filters.
Andy
EDIT: If you're using another timer mechanism then setting X=0 and polling works well.
BTW... from what I understand how the glitch filters work they also have a negative effect on timing resolution. A counter tap feeds the clock input of the flipflops so they get updated only every 2^n sysclks. For example, if I select filt1 the default is 1:32 tap and 3 flipflops. So instead of a constant delay of 96 clocks the signal is only updated every 32nd clock cutting resolution down to 1/32.
Of course, the way the filters are implemented now is cheaper regarding silicon area. A shift register with hundreds of flipflops would be too expensive so it had to be implemented with a loadable counter which counts down while the input stays the same. This would still require at least a 16 bit counter for each pin.
I think I quit the whole smartpin stuff and return to manually decoding the quadrature signal as I did with the P1. Apart from reducing code size a bit the smartpins have only disadvantges in this case. Waiting for a pin change (what is the P2 instruction for waitpne?) gives full resolution to one sysclk. The extra time the decoding in software takes even has the side-effect of adding a dead-time in which further pin changes are ignored. This has the same effect as a hardware glitch filter.
PS: The deglitch "filter" hardware is intended for mechanical switches, namely push-buttons. Don't use it for real filtering.
> This has the same nearly the same effect as a hardware glitch filter.
The dead-time prevents the counter from changing faster than the dead-time but a glitch is not fully supressed. We had to check if the pin states are still the same after the dead-time and undo the counter update if not.
Yes, set the FFF field for wrpin to %011 and no smartpin (mode = %00000)