Shop OBEX P1 Docs P2 Docs Learn Events
smartpin questions (was: how to capture time on pin change) — Parallax Forums

smartpin questions (was: how to capture time on pin change)

ManAtWorkManAtWork Posts: 2,078
edited 2020-01-31 08:50 in Propeller 2
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.

Comments

  • cgraceycgracey Posts: 14,133
    You could always use TWO smart pins - one to track the step/dir and another to count cycle or state times. You could use more than two pins, for that matter. Each smart pin can look at its own pin, plus pins within +/-3 of itself.
  • My problem is that I don't understand how the "count time", "count states" or "count periods" modes work. I have the vague feeling that some of the "for periods in X+ cycles, count ..." might provide what I'm looking for.

    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.
    A measurement is taken across some number of A-input rise/edge to B-input rise/edge periods, until X clock cycles elapse and then any period in progress completes.

    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...
  • Let's assume a sysclock of 100MHz for easy calculation and my controll loop samples the state of the position counter every millisecond (once per 100_000 syclocks). At the second sample (time=200_000) the timestamp register reads t2=158876 and position is p2=0. The state at the previous sample was t1=56998 and p1=-2. So velocity is calculated as dp/dt = (p2-p1)/(t2-t1) = 1.963e-5 or 1.963 counts per ms.

    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.
    770 x 118 - 3K
  • evanhevanh Posts: 15,192
    edited 2020-01-28 20:59
    Have a read of the renamed list I made. It should help with categories at least. https://forums.parallax.com/discussion/comment/1482243/#Comment_1482243

    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.
  • evanhevanh Posts: 15,192
    A dynamic filter on the velocity component of the feedback might be a better solution though. When motion becomes very slow, the filter can be built up to smooth it out.
  • jmgjmg Posts: 15,148
    edited 2020-01-28 21:27
    ManAtWork wrote: »
    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 ....

    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
  • ManAtWorkManAtWork Posts: 2,078
    edited 2020-01-29 08:28
    evanh wrote: »
    A dynamic filter on the velocity component of the feedback might be a better solution though. When motion becomes very slow, the filter can be built up to smooth it out.

    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).
  • As I have to support different feedback devices (incremental encoders, resolvers, absolute encoders...) I have decided to give each position/velocity-measurement device a dedicated cog.

    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.
  • evanhevanh Posts: 15,192
    Keep it aside for the moment but don't ignore filtering as too hard a problem. Even for multi-axis CNC, if all axes have the same group delay then much of the concern with filter lag goes away. Oscillation is what you're trying to knock on the head here. Well designed filters can help do that.

    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.
  • jmg wrote: »
    If you know the appx step rates at any ms, you could vary X to dynamically scale.

    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.

  • evanh wrote: »
    Have a read of the renamed list I made. It should help with categories at least. https://forums.parallax.com/discussion/comment/1482243/#Comment_1482243

    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.

    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.
  • I still have trouble with the most basic things. I can't even get the quadrature counter running.
    CON
      pinEncA	= 0
      pinEncB	= 1 ' must be pinEncA + 1..3
    
    DAT
    ...
    		fltl	#pinEncA		' reset smartpin
    		wrpin	mode_quad,#pinEncA	' quadrature decoder
    		wxpin	#0,#pinEncA		' no period, continous
    		drvl	#pinEncA		' enable smartpin
    
    		setse1	#%110_000000 + pinEncA ' event smartPin IN=1
    cntLoop
    		'waitse1			' wait for Counter change
    		rdpin	pos,#pinEncA
    		getct	time	
    		wrlong  time,ptrb
    		wrlong  pos,ptra
    		jmprel  #cntLoop
    
    ' 			%AAAA_BBBB_FFF_PPPPPPPPPPPPP_TT_MMMMM_0
    mode_quad	long	%0000_0001_000_0000000000000_00_01011_0 ' + (pinEncB-pinEncA)<<24
    pos		long	0
    time		long	0
    
    I commented out the waitse instruction to force continous reading of the counter. Time is incremented as expected but pos stays zero no matter how I turn the shaft. I checked that P0 and P1 are toggling. I haven't understood the PPP and TT fields of the smart pin mode word. I hope that the default 0 works for this mode.
  • Oh no! :facepalm:

    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. :smiley:
  • evanhevanh Posts: 15,192
    I've forgotten what JMPREL does. Something to do with table lookups I think. It maybe isn't best name for the instruction.

  • Ok, I'm learning step by step...

    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?
  • AribaAriba Posts: 2,682
    I think IN indicates only the end of a measurement period, which you can set with a wxpin.
    If you want to wait for a encoder change, you can always do something like that:
    		...
    		mov	oldpos,pos
    .waitenc	rdpin	pos,#pinEncA
    		cmp	pos,oldpos   wz
    	if_e	jmp	#.waitenc
    		...
    

    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
  • evanhevanh Posts: 15,192
    edited 2020-01-31 10:08
    The only way IN will be raised by the quadrature counter mode is if X is set to a sampling period. If X==0 then it doesn't latch and has to be polled for active count.

    EDIT: If you're using another timer mechanism then setting X=0 and polling works well.
  • Ok, that makes sense. I hoped that IN=1 meant "new data available in Z" which was a lot more useful than simply "end of measurement period" for periodical measurement (X>0). For X>0 both cases are the same but the former would allow to use interrupts for both cases. Generating an interrupt poeriodically is trivial and could be done without smartpins.
  • Also, using a polling loop (cmp oldpos,pos) cuts resolution by a factor of 6 compared to a waitse which would be precise to one sysclk.

    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.
  • evanhevanh Posts: 15,192
    edited 2020-01-31 11:45
    Yep, setting X>0 does that too. As well as raising IN, the smartpin metronomically latches the count into Z. IN is then dropped when Z is read with RDPIN.

    PS: The deglitch "filter" hardware is intended for mechanical switches, namely push-buttons. Don't use it for real filtering.

  • WAITPEQ/PNE works with SETPAT and WAITPAT, now, correct?

    > 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.
  • Is it possible to configure a smartpin so that its IN bit is set to A xor B? I just need the XOR in the input selector without any extra "smart" function.
  • AribaAriba Posts: 2,682
    ManAtWork wrote: »
    Is it possible to configure a smartpin so that its IN bit is set to A xor B? I just need the XOR in the input selector without any extra "smart" function.

    Yes, set the FFF field for wrpin to %011 and no smartpin (mode = %00000)
      wrpin  ##%0000_0001_011_0000000000000_00_00000_0,#PIN
    '       A=PIN B=PIN+1 XOR
    
  • Ah, very good! This way I can get around the setpat/waitpat problem. I could wait for a single change event of the XORed pins.
Sign In or Register to comment.