Shop OBEX P1 Docs P2 Docs Learn Events
Counting pulses without hanging code when no pulses are available? - Page 2 — Parallax Forums

Counting pulses without hanging code when no pulses are available?

24

Comments

  • eagletalontimeagletalontim Posts: 1,399
    edited 2013-02-15 07:31
    My question is... If counting pulses between a specified time instead of counting distance between pulses, would there not be an issue with missed pulse counts? For example, if a pulse has already started and the counter begins, it will count the next low. When the counter finishes, and the pin just went low immediately before the counter stops, that would be considered 2 pulses correct? Then the next count cycle would start when the pin is low so it would have to wait till the pin goes high again, then back low again which could take the same time meaning it would only register 1 pulse. If I were on my home computer I could draw an example of what I am talking about...

    The conflict between reading pulses between a known time vs reading the distance between each pulse is an issue to me. To be accurate, I would think reading time between pulses and converting that to seconds / minutes / hour would be more precise. Maybe I am wrong though.
  • eagletalontimeagletalontim Posts: 1,399
    edited 2013-02-15 07:52
    Here is kind of what I am talking about. If you notice the "Count" lines which represent the specific time to count pulses between. If spaced evenly, the timing of the pulses could actually throw off the readings, right?
  • JonnyMacJonnyMac Posts: 9,108
    edited 2013-02-15 08:33
    I am far too dense understand out what you're trying to do, so I'll just keep throwing code at the wall until something sticks.

    This routine will report the number of system ticks between falling edges. As with the code above, this is designed to run in its own cog so it doesn't block anything else. Note, though, that this could give bad values if you are missing pulses for a very long time. If you use this you should have some other system check that says the machine is in fact running so that values reported from this cog are valid.
    pri pulse_timer(pin, p_hub) | mask, t1, t2
    
    '' Measure falling edge to falling edge in system ticks
    
      mask := 1 << pin
    
      waitpeq(mask, mask, 0)                                        ' wait for high
      waitpne(mask, mask, 0)                                        ' wait for low
      t1 := cnt                                                     ' start timer
    
      repeat
        waitpeq(mask, mask, 0)                                      ' wait for high
        waitpne(mask, mask, 0)                                      ' wait for low
        t2 := cnt                                                   ' stop timer
        long[p_hub] := t2 - t1 - 544                                ' report ticks
        t1 := t2                                                    ' re-align timer
    
  • eagletalontimeagletalontim Posts: 1,399
    edited 2013-02-15 08:51
    What I am working with is a device that shifts automatic transmissions based on user input and sensor readings. If the user attempts to shift to a gear that is outside the safe range, it will reject the shift and alert the user. I am currently monitoring throttle, RPM, and what gear they are in. I am hoping to add vehicle speed to further protect the user and the vehicle. This is why I must have accurate readings for the speed.

    Using any function that "hangs" until a positive edge or negative edge could be a major problem in case the user must lock up their brakes at any speed. Since the pulses only happen when the wheels are moving, the pulses would stop until the wheels began turning again. The vspeed variable must show 0 MPH if the wheels stop moving at any point to ensure the torque converter lockup does not stay locked and that other devices controlled are set in the proper position in this kind of situation. This is the reason I am attempting to have some function that will loop no matter if there are pulses or not. If the pulses stop, I can increment a variable that will break the loop to set vspeed to 0 if the count goes past say 500ms to 1 second.

    Hopefully that explains the project a little better :)
  • StefanL38StefanL38 Posts: 2,292
    edited 2013-02-15 09:18
    I want to emphasise on the counters again.

    Each cog has two counters. Each cogs counters are completely independent from each other.

    The counters are counting regardless what else the cog does.
    Imagine the counter as a butler that has really nothing else to do than counting pulses writing the actual value into a register
    and whenever your code wants to look into the register it can do that. without disturbing the counter counting.

    If your inputsignal is not sharp edged insert a schmitttrigger between your sensor and the propeller-pin to get a sharp-edged signal.

    Please explain what are the reasons to not use a counter???

    best regards Stefan
  • eagletalontimeagletalontim Posts: 1,399
    edited 2013-02-15 09:36
    I am not quite sure I fully understand the counters since I don't understand much of the documentation on the PROP anyways. I can't quite grasp registers, cogs, stacks, ram, addresses, and quite a few other things. I fully understand IF statements, how to toggle a pin, how to use a pin as an input, and how to do math functions on the prop.

    The way I usually learn is through trial and error since reading documentation about something does not explain how to use a specific function in the exact manner I am using it in which throws me in a loop. This is why I post on here since most people can help explain what I am doing wrong and / or a better way to accomplish what I am trying to do. As I work with something more and more, I learn it much better which has gotten me to where I am now in my project. Most everything is complete other than a few small details like the speed sensor reading. I have been using my device for over 4 years with the SX and almost 2 years with the PROP. So far so good. I just need to better understand what I am working with to optimize it to the most potential.
  • JonnyMacJonnyMac Posts: 9,108
    edited 2013-02-15 10:34
    I am not quite sure I fully understand the counters since I don't understand much of the documentation on the PROP anyways.

    And yet you want to control an automobile with the Propeller, anyway? :)

    None of this is as difficult as your attitude is making it. I know that you're very sincere and trying, but making statements like "I don't understand" don't serve you -- in fact, your subconscious helps you back up your self talk. Change your statements to "I'm in the process of understanding...." so that you don't defeat yourself before you have a chance to succeed.

    Back to the topic... how frequently do you want to need to test for vehicle speed? Think of things in practical terms: how much can the vehicle speed change in one second? If we're talking Formula 1, okay, a lot. If we're talking a street vehicle, not much at all. What I'm suggesting is that you not trap yourself with words like "best" when there are many options that are equally valid. "Best" is very subjective and is often just a rabbit hole that leads to nowhere.
  • eagletalontimeagletalontim Posts: 1,399
    edited 2013-02-15 11:32
    Yeah, I do get a little frustrated when I feel like I should know what others are trying to tell me and it makes me look bad that I am working on a project that is out of my league in other people's eyes. I know how to plan on what I need to have done, and I know how to get the basics of what I need done, but when it comes to a part I don't quite understand, I have to ask to hopefully learn that specific task a little better.

    The project I have already built is working 100% currently which I have been driving with it for roughly a year now with 0 issues. I just want to add a little more to it which has got me stumped with my current knowledge of the PROP. I would love to learn more, I just feel I need to word it a little better so people know how much I actually understand :)

    So...for the frequency of the reading update, I feel that 200ms is a safe number since the vehicle I am using this on is known to run 9 to 10 seconds in 1/4 mile when built properly and tuned properly. Mine is not quite that fast yet :p The average speed in 1/4 mile is roughly 120 to 140 for the drag setup vehicles. Other users have used my product for rally racing as well. I don't know what speeds they get to.

    The point of the VSS is to add the speed to the formulas I already use which can either shift the vehicle automatically or prevent the user from shifting into the wrong gear at the wrong time. I feel vehicle speed is a better equation for this as RPM can be different for each vehicle depending on their torque converter stall.

    I am up for trying any options at this point because as you can see, I am still learning more and more about the PROP as I work through this project. The SX was not as difficult to learn since the language resembled Qbasic, PHP, or Visual Basic which are other languages I understand.


    EDIT : I have the Main function that runs all the time checking calculations against the sensor readings to block or allow shifts. I do not have the calculations running in a cog yet as I am working on the structure / process of how the program works. The more I work with it, the more I learn :)
  • JonnyMacJonnyMac Posts: 9,108
    edited 2013-02-15 11:46
    I feel that 200ms is a safe number...


    Here's how easy it is to change my first suggestion:
    pri pulse_counter(pin, p_hub) | t                               ' launch with cognew
    
    '' Count low-going edges in a 200ms window
    
      ctra := (%01110 << 26) | pin                                  ' set pin to neg edge detect
      frqa := 1
      phsa := 0
    
      t := cnt                                                      ' synchronize timing
      repeat
        waitcnt(t += (clkfreq / 5))                                 ' wait 200ms
        long[p_hub] := phsa                                         ' report to hub
        phsa := 0                                                   ' clear for next period
    


    The only change is in the waitcnt line to change the loop timing to 200ms.

    The advantage of using a counter accumulate edges is that your code can be busy doing something else and the edge will still get detected. Yes, you can do this in code, but you have to keep track of the last time through the loop and update your accumulator only when the current state is low and the previous state was high. This is handled for you with the counter using edge detect mode.

    And here's the cool bit... the counter adds the FRQx register into the PHSx register on the edge. With a bit of empirical work you _may_ be able to determine a value for FRQx that causes the output of that routine to be in the units you want (e.g., mph), eliminating or simplifying a calculation in your mainline code.

    The SX was not as difficult to learn since the language resembled Qbasic, PHP, or Visual Basic which are other languages I understand.


    Again, these kinds of statements are not helping you. Instead, change your mindset to, "Hey, I learned QBASIC, PHP, Visual BASIC, and SX/B -- I can learn Spin, too! And I can kick @ss with it as it's far more powerful than SX/B!"

    And if that doesn't work, try this: "If Jon McPhalen -- an actor -- can do it, I certainly can!!!"

    You get what you expect. As soon as you expect to master Spin and PASM you are on the road to doing. Okay, excuse me while I light some incense. :)
  • eagletalontimeagletalontim Posts: 1,399
    edited 2013-02-15 12:21
    lol, I know I can learn it :) just taking a bit longer than I am use to it taking for me...

    So the code you posted will output how many pulses happened in 200ms? If that is the case, I just need to divide the number of pulses by the time (200ms) to get the pulse distance?
  • JonnyMacJonnyMac Posts: 9,108
    edited 2013-02-15 14:29
    Divide 200ms by the number of edges to get the average edge-to-edge time; not perfect, but very close. Be sure to check for 0 first.
  • borisgborisg Posts: 39
    edited 2013-02-15 15:42
    Kuroneko, you'd be correct if I was using adds, but I'm doing an unsigned add with the add instruction. *However, you're definitely onto something.
    *Your deep comments are exactly what I need now to make sure my core code is sound. *So thanks for the inisights.
    The code above works because the cmp instruction is an unsigned subtract and, if cnt >TmTime and unsigned carry is generated. *Hence, the jmp #Timer instruction is executed after cnt has become > TmTime. *I also want it to detect when TmTime = cnt and for that I use the Z flag (as seems to have been the case throughout my digital electronics and programming career I'd fix things by adding an inverter or reversing some of my logic). *So, the updated code is:
    * * * * * * * * * Timer * * * * * * * * * * cmp TmTime, cnt wz wc
    * * * * * * * * * * * * *if_nz_and_nc *jmp #Timer

    This results in a jmp to #Timer only if cnt < TmTime. *I've changed the code and it works fine. *The jitter in the timer should just be +/- 12.5 nsec at 80 MHz. *So I still haven't figured out how you got a 6 microsecond pulse duration from a 2 microsecond pulse.

    I really need an oscilloscope. *I've been debugging using the very short pulse I put on Pin0 and my DVM frequency meter told me the frequency was 2 KHz whereas my RTC code is keeping perfect time. *Too bad all of the propscopes were sold out last time I looked.
  • borisgborisg Posts: 39
    edited 2013-02-15 15:53
    In the example you gave, you'd get 1, 0, 2 pulses for the different intervals. *My routine assumes that I detect a pulse on the rising edge and , to get the falling edge of the pulse, all you'd have to do is get the time of the falling edge is by adding together the start time of the pulse with the pulse duration.

    To find out how many pulses are in a given window, say 1 minute as 0 to 120,000,000. *Then any pulse where the sum of pulsetime + pulseduration fell within those limits, count it. *When the pulsetime > 120,000,000 you'd have to define another 1 minute window ad infinitum. *The only problem I can see is that you're dealing with signed longs in Spin whereas I have the luxury of using unsigned longs in PASM. *The math works the same except the comparisons are not as straightforward when one of the window limits is positive and the other negative. *My primary programming language now is VB6 and I have to deal with the lack of signed longs all of the time.
  • kuronekokuroneko Posts: 3,623
    edited 2013-02-15 16:04
    borisg wrote: »
    Kuroneko, you'd be correct if I was using adds, but I'm doing an unsigned add with the add instruction.
    This doesn't matter one bit. It's an add, the only difference is flag output if so desired.
    borisg wrote: »
    The code above works because the cmp instruction is an unsigned subtract and, if cnt >TmTime and unsigned carry is generated.
    OK, say cnt is 0 which means TmTime becomes a bit over TimeTick. Now you really sit there in a loop while cnt climbs up to match the target. OTOH, if we start with a negative value (cnt == -TimeTick, $FFFF_FF60) TmTime := cnt + TimeTick overflows and will end up - for the sake of this example - as 3. cnt still being negative (but treated unsigned, i.e. large positive) will be immediately greater than 3 and not wait at all. That's clearly different behaviour.
  • eagletalontimeagletalontim Posts: 1,399
    edited 2013-02-15 16:52
    I just got my oscilloscope in!!!!! I am going to go get some screenshots of the waves and let you all look at them. Hopefully what I get is worth working with! This is my first time ever using an oscilloscope, but I am reading the instructions right now :) Wish me luck!
  • borisgborisg Posts: 39
    edited 2013-02-15 17:03
    Kuroneko, quite correct - again. However, this would be a problem only with very short values of TimeClick. My 1 msec timer also runs a RTC and, when left running overnight, it lines up perfectly with my watch. Now my watch is an imperfect timing device and so what I need to do is setup an independent counter to count pulses generated by my 1msec clock to see how many extra ones exist over a day. For 1 msec, TimeClick = 80000 and I'm just too sleep deprived now to calculate analytically how often the case you describe happens. It is < once every 53687 msec ticks as if it happened every cycle, the clock would be off by 1607 msec/day (assuming a perfect 5 MHz crystal). That's easy to test and will write a VB6 program to capture the output every second and see if there's any drift over the course of a few days.

    For the 2 microsecond/loop case I'm going to have to learn how to use the Propeller counters or setup a cog with a "perfect" clock using the Waitcnt instruction to generate intervals that aren't rarely shorter. The only problem with Waitcnt is that one can't do any processing during the clock loop and that's why I wrote my current code. Will have to see whether it's even possible to write a 2 microsecond resolution sampling program as have to thrown in checks for the transition from max positive # to 0.

    That's the nice thing about having other people review your code as what seemed "perfect" when hand assembled and wetware simulated turns out to have subtle bugs when someone else looks at it. Looks like I have to install the PASM simulator on my quad core 2.9 GHz i7 machine and let it overflow cnt a few times to check for rare conditions as you've found.
  • StefanL38StefanL38 Posts: 2,292
    edited 2013-02-16 07:54
    as long as the input-signal is going up and down with each pulse for at least 100mV in the same absolut height (f.e. 1.4V to 1.5V or 4.2V to 4.3V or 0.9V to 1.9V etc. )
    an external circuit called comparator with hysteresis is able to transform any of these signals into a 0V/3.3V rectangle signal to feed into a propeller-IO-pin.

    This circuit requires just an OpAmp and some resistors.
    Here I found an online calculator for the resistor-values http://sim.okawa-denshi.jp/en/rercal.php

    But you are right - show us the screen of the oscilloscope. There is a good change to feed the signal directly into the Prop-Pin.

    best regards
    Stefan
  • eagletalontimeagletalontim Posts: 1,399
    edited 2013-02-16 08:17
    I will be going for a drive here shortly with the oscilloscope hooked up to the speed sensor. The oscilloscope I got is the MINIDSO DS203 and it does not have the best of instructions with it. I will do the best I can since I am still learning this interesting device :)
  • eagletalontimeagletalontim Posts: 1,399
    edited 2013-02-16 12:00
    I have a few screenshots, but I picked the one that I think is the most usable. Not exactly sure what all information would be needed, but hope this helps! This is the reading at around 55mph according to my dash speedometer.
    400 x 240 - 45K
  • JonnyMacJonnyMac Posts: 9,108
    edited 2013-02-16 13:01
    It would probably be useful to show several screen shots at different speeds so that everyone can see what part of the waveform changes and the relationship to speed.
  • eagletalontimeagletalontim Posts: 1,399
    edited 2013-02-16 13:20
    I only have 2 screenshots right now that worked. One of them glitched or something and is not viewable. Here are the 2 that are straight from the oscilloscope. One is at 55mph, and the other is at 60 I believe.

    I just got back from a test drive using the code you posted for the 200ms update and I was getting a HUGE number output sitting still. It was like 19015660 or something like that. It would jump around when I was moving, but would not increase or decrease when going 10MPH or 60MPH. My screen is set to show 4 numbers on the bottom right of it and the other 4 numbers automatically wrapped to line 1. I pulled over and changed the code to divide the output by 16364 which is apparently how many pulses there are in a mile for my vehicle. The new numbers when driving jumped between 509 to 615 no matter what speed I was going.

    I have a feeling the resistors I am using is not enough to pull the pin low for what the speed sensor is actually outputting. I looked at what I have set up which is a 10K from the source to the prop pin, and a 100K from ground to the prop pin. I believe I should change the 100K to something with a little less resistance. Could you help me with figuring what resistors to use?
  • JonnyMacJonnyMac Posts: 9,108
    edited 2013-02-16 14:26
    You'll help others by converting to JPG or PNG which will display in most browsers.
    I just got back from a test drive using the code you posted for the 200ms update and I was getting a HUGE number output sitting still. It was like 19015660 or something like that.


    That's odd -- I tested the original code using another counter to generate a known frequency on the input pin used by the edge counting code. It worked perfectly so I didn't bother saving the program. Today the recreation is behaving badly. I'll get the test code working and post so you can see that edge counting works.

    Problem found: There was an error in the counter setup for edge detection (you should have been able to suss this out and show me!) -- and I'm not sure why my original test worked. At any rate, the correct setup for negative edge counting is:
    ctra := (%01110 << 26) | pin
    


    The attached demo code works. I have also corrected my previous examples to prevent problems for others.
  • eagletalontimeagletalontim Posts: 1,399
    edited 2013-02-16 14:56
    What is the psha supposed to be? The number of counts in the specific period or the time between pulses? I am thinking it is supposed to be pulses counted between 200ms which I know the results I am getting cannot be correct. I also tried changing the ctra to %01000 to be a positive edge instead of negative to see if that helped. I did get a different reading, but still am getting a HUGE number. I am almost 100% sure there are not over 1000 pulses per 200ms at 55mph. If my math serves me correctly, I should see around 250 pulses per second which would be 50 pulses per 200 ms?

    (16364 * 55mph) / 60 minutes / 60 seconds

    EDIT : Also another thing I have thought of while watching the numbers display on the screen.... When moving less than 5 MPH, the pulses are spaced out really far. Some are farther than 200ms. This could be a conflict. Adjusting the time to count between (200ms) is not a good idea either since my car can go 0 to 60 in roughly 4 or 5 seconds. That is 3 gears for me. If I raise the count time, I would get less vspeed results which could cause other calculations to not work properly.
  • JonnyMacJonnyMac Posts: 9,108
    edited 2013-02-16 15:00
    The code in the demo I just uploaded counts the number of falling edges in a 200ms window. If you want to know the average time between edges in the window, divide 200ms by the count you get; this will be edge-to-edge milliseconds.
    I also tried changing the ctra to %01000


    That is not edge detection; that mode increments psha any time the input pin is high (this was the same problem I had dropping a "1" out of my setup). You need to use rising edge (%01010) or falling edge (%01110) mode -- you don't need feedback. See table 7 in AN001. Edge modes are marked with asterisks.
  • eagletalontimeagletalontim Posts: 1,399
    edited 2013-02-16 15:22
    I made the change to my program and I am still getting extremely jumpy results. Going 40 MPH, I was getting phsa results like 5800 to 8800. When I pulled back into the driveway, I inched my car forward until the speed sensor output went high and I watched the phsa result. It jumped between ~1100 to ~1400 while sitting still. What can I do to prevent this? I was thinking the resistor setup I had was not correct so I replaced the 100K with a 10K to bring the voltage down even more. It helped, but did not solve my issue.
  • StefanL38StefanL38 Posts: 2,292
    edited 2013-02-16 15:37
    the most important information is the shape of the signal. Seems to be pretty good. The voltage rises quickly up to 4-4.5V.
    But to make it real sure you should record the signal with a "higher speed".
    This means to change the horizontal speed to a higher value. In this picture you seem to use some kind of automode for timing.

    You should change to a smaller timebase 2 ms or even 1 ms or 500 µ-seconds and increase voltage sensivity to 1V per div.
    Then lower the zero-voltage-line to the lower end of the screen.

    The reason why I want to see the signal in this way is that at the rising the line is pretty big. Behind that the signal might hide
    unstability (=small rises and falls until the signal reaches its highest value)

    Through changing to a shorter timebase and increasing the voltage-sensivity you are kind of "zooming in" that more details
    are viewable. What kind of sensor is creating this signal?

    best regards
    Stefan
  • JonnyMacJonnyMac Posts: 9,108
    edited 2013-02-16 15:47
    I'm with Stephan; I'll bet your signal is far noisier that what you're seeing with your 'scope -- this is born out by the jumpy readings. If you ran my test program you see that it's rock solid with a rock solid signal.

    There are others far more clever than me that can help here, but you might consider a very small RC filter on the input (clean-up noise), followed by a Schmitt trigger (give you a clean edge). I just used a TinyLogic part in a project, and they have it available as a Schmitt trigger.

    http://www.fairchildsemi.com/ds/NC/NC7SZ14.pdf
  • eagletalontimeagletalontim Posts: 1,399
    edited 2013-02-16 18:09
    Don't worry about it, I am done. I don't have enough knowledge to work with this project anymore.
  • StefanL38StefanL38 Posts: 2,292
    edited 2013-02-17 01:53
    Hi forum members,

    I feel guilty about this development which resulted in the above post of Tim.
    I sent him a private message with my honest opinion. This was harsch and based on only a few information about Tim
    and his project. He answered on my PM with more details which changed my opinion 180 degrees.

    A publicly apologise for beeing rough and harsch in this PM. I want to offer great support for his project
    and would appreciated if some other forum-members would give Tim an encouraging pat on his shoulder
    "come on - you CAN learn it and you will learn it"

    I guess I have to learn the lesson to be mor patient asking for more details and only after that judging
    about another person still beeing polite and not harsch.

    So please Tim I stretch my hand to you - would you give me a chance to let me help you?

    friendly greetings, kind regards
    Stefan
  • borisgborisg Posts: 39
    edited 2013-02-17 02:23
    One thing I'd suggest is looking closely at noise in the circuit. Things don't behave the way you expect them to when you're dealing with the frequencies that the Propeller runs at. I was close to giving up on my Micromedic project as the Propeller kept rebooting itself and all it took to fix it was lots of decoupling capacitors. I know you've chosen to go with JonnyMac's spin code, but I was playing around with the PASM code that I posted where I just had a wire running from pin1 (my 1 msec timer) to pin5 (the input to the pulse duration measurement code) and I found out that a 2" loop of wire acted as an incredibly sensitive proximity detector. I could push a 1' length of wire into the 2" loop between the two pins and the output would go nuts with eventually the serial terminal cog going into a buffer overflow mode.

    So, I suggest is looking at your grounds and whether there might be a ground loop somewhere which is causing the extra pulses. There's no algorithmic way for fixing problems like this and I remember 20 years ago just moving a wire a few inches and solving a very perplexing debugging problem. I'm sure that JonnyMac's Spin code is sound, but you're most likely dealing with noise pickup in on the pin you're sensing. Your resistor values may be too large. You've gotten a clean signal on your scope which suggests if you look at what you've done to get that you'll probably be able to fix the problem with the Propeller. Automobiles are very noisy environments from an electrical perspective. Also look for noise communicated via power lines and that means decoupling those with a 100 microfarad, 0.22 microfarod and 0.01 microfarad capacitor to ground to try to get all of the frequencies that could be causing interference.

    It's a trial and error process, but once you've got it working just write down what you did.
Sign In or Register to comment.