Shop OBEX P1 Docs P2 Docs Learn Events
Can someone help me figure out why my code is inconsistent? — Parallax Forums

Can someone help me figure out why my code is inconsistent?

turbosupraturbosupra Posts: 1,088
edited 2014-11-02 14:24 in Propeller 1
Attached is my object with a pulse generator and a pulse reader method. On the bench the reader works perfect, but in real life I am getting inconsistent results as shown in the terminal screen capture posted below. I've went through my code for the past week about 50 times, tried everything I know to troubleshoot and I can't figure out what I'm doing wrong so it is time to ask for help. The code always reads a lower value, never reads a higher value, and because of that I do not think it is chatter on the pin?

If anyone has any ideas/suggestions/troubleshooting techniques, I'm looking to learn. Thank you.


Numbers.spin

Float32Full.spin

rpmTest7.spin

FullDuplexSerial64.spin


rpm_Code_Fail1.jpg

Comments

  • JonnyMacJonnyMac Posts: 9,105
    edited 2014-10-26 20:04
    I don't know this will help, but one thing I've notice is that you embed a lot of debug statements into your working code. I would suggest that you build you projects in small sections and use a separate cog to send debug information to the terminal. I do this all the time. The great thing is you can setup different debugging cogs as you go -- since they're in a separate method, you don't have to worry about striping them from an active program later.
  • evanhevanh Posts: 15,921
    edited 2014-10-27 03:56
    I'm no Spin expert but: A) Don't use CNT more than once within a calculating loop - each time it's used it has a different value. This is the basis of synchronous design. Capture once into a holding variable and use that for the entirety of the loop.

    B) Too many IFs! Brain hurts. They look like they are dealing with roll-over, correct? The common trick is replace value1 > value2 with (value1 - value2) > 0. The subtraction before compare allows the naturally clean adder roll-over to produce a number with respect to zero, with which a compare will function cleanly. No need to have any exceptions.
  • Dave HeinDave Hein Posts: 6,347
    edited 2014-10-27 10:33
    Turbo, it appears that you are measuring 5 consecutive time intervals, and then averaging them. You could just measure the start and stop times between 5 intervals instead. Your code would simplify to something like this:
          repeat until ina[I_Rpm] ' Wait for high
          repeat while ina[I_Rpm] ' Wait for low
          rpmTimeStart := cnt
          repeat 5
            repeat until ina[I_Rpm] ' Wait for high
            repeat while ina[I_Rpm] ' Wait for low
          rpmTime5 := cnt - rpmTimeStart ' Compute time for 5 intervals  
    
  • turbosupraturbosupra Posts: 1,088
    edited 2014-10-27 11:56
    JonnyMac wrote: »
    I don't know this will help, but one thing I've notice is that you embed a lot of debug statements into your working code. I would suggest that you build you projects in small sections and use a separate cog to send debug information to the terminal. I do this all the time. The great thing is you can setup different debugging cogs as you go -- since they're in a separate method, you don't have to worry about striping them from an active program later.

    Sadly enough, I thought my debug setup was pretty slick, haha ... but I'm always wanting to learn from the wise, so I will try to implement what you've discussed. How would you implement the debug code saying "I'm here right now" at any specific location, with the method you've proposed? Thank you.

    Dave Hein wrote: »
    Turbo, it appears that you are measuring 5 consecutive time intervals, and then averaging them. You could just measure the start and stop times between 5 intervals instead. Your code would simplify to something like this:
          repeat until ina[I_Rpm] ' Wait for high
          repeat while ina[I_Rpm] ' Wait for low
          rpmTimeStart := cnt
          repeat 5
            repeat until ina[I_Rpm] ' Wait for high
            repeat while ina[I_Rpm] ' Wait for low
          rpmTime5 := cnt - rpmTimeStart ' Compute time for 5 intervals  
    

    Does this in essence pause the cog? I wanted to have the routine free to run other things if necessary. The frequency is very low at 2hz per (rpm/60) so it would basically disable the cog if I read this correctly.
  • Dave HeinDave Hein Posts: 6,347
    edited 2014-10-27 12:30
    The code I posted would run in the "calculateRpm" cog. It will not block your main cog, which will be free to do other things.
  • ChrisGaddChrisGadd Posts: 310
    edited 2014-10-27 12:51
    Your code is somewhat difficult to follow, but if I were to guess I'd say the glitchiness is due to the sampling rate, which is slowed considerably from all of those debug statements.

    Indeed, using a function generator, your code reports a linear increase from 1Hz (30rpm) up to 28Hz (840rpm), then at 29Hz it glitches to ~435rpm.
    Commenting out all of the debug statements, except the final one that shows the average, and it can show up to 9000rpm at 300Hz input.
    Best advice there is to follow Jon's advice and use a dedicated debug cog.

    Have you considered using the built in counters? Either an edge detector to count the number of transitions, or a level detector to count the number of clock ticks that the signal remains high or low.
    Here're a few ideas:
    PUB Main
    
      debug.start(31,30,0,115200)
      waitcnt(cnt + clkfreq)
    
    ' posedge_counter
      pos_counter
    ' pos_demo
    
    PUB posedge_counter | ticks
    {
     Use the posedge counter mode to count the number of positive transitions in one second.
     Fails when dealing fractional frequencies - 2.5Hz should be 75rpm
     Display alternates between 60 and 90
    }
    
      ctra := %01010 << 26 | I_RPM                          ' Configure counter A to increment phsa on every positive transition
      frqa := 1                                             ' Increment phsa by 1 on each transition
    
      repeat
        phsa := 0                                           ' Clear phsa
        waitcnt(cnt + clkfreq)                              ' Wait one second
        ticks := phsa                                       ' Copy phsa into ticks
        debug.dec(ticks * 60 / 2)                           ' Convert ticks into rpm
        debug.tx($0D)
    
    PUB pos_counter | ticks
    {
     Use the pos counter mode to count the number of ticks that the input remains high
     Divide by the clock frequency
    }
    
      ctra := %01000 << 26 | I_RPM                          ' Configure counter A to increment phsa on every clock that the input is high
      frqa := 1                                             ' Increment phsa by 1 on each clock that the input is high               
                                                                                                                                     
      repeat                                                                                                                         
        phsa := 0                                           ' Clear phsa                                                             
        repeat until ina[I_RPM]                             ' Wait for the input to go high                                          
        repeat until not ina[I_RPM]                         ' Wait for the input to go low                                           
        ticks := phsa                                       ' Copy phsa into ticks                                                   
        debug.dec(clkfreq / ticks * 15)                     ' Convert ticks into rpm
        debug.tx($0D)
    
    PUB pos_demo | i, av0, av1, av2, av3, av4, average
    
      ctra := %01000 << 26 | I_RPM                          ' Configure counter A to increment phsa on every clock that the input is high
      frqa := 1                                             ' Increment phsa by 1 on each clock that the input is high
    
      repeat
        repeat i from 0 to 4
          av0[i] := (clkfreq / counter * 15)
        average := (av0 + av1 + av2 + av3 + av4) / 5
        debug.dec(average)
        debug.tx($0D)
        
    PRI counter : ticks
    {
     Return the number of ticks that input was high
    }
      repeat until not ina[I_RPM]                           ' Wait for the input to go low                          
      phsa := 0                                             ' Clear phsa                                                             
      repeat until ina[I_RPM]                               ' Wait for the input to go high                                          
      repeat until not ina[I_RPM]                           ' Wait for the input to go low                                           
      ticks := phsa                                         ' Copy phsa into ticks                                                   
    
  • DavidZemonDavidZemon Posts: 2,973
    edited 2014-10-27 12:53
    Re: Debug print statements

    Because printing to the console is sloowww, when I have precisely timed projects, I will do all of my logging in a single cog. When I need to log a value, I assign it to a global variable. My debug cog then prints the value in that variable at a pre-determined frequency.

    As for the "I'm at line ___ now" type of statement... that's slightly harder. You might need two variables for that: previous and current. Initialize both to 0 (does Spin have "null"?). When you hit a point that you want to log, assign `current` to some unique value. Your debug cog then checks the value of `previous` and `current` and, when not equal, prints `current` (or some string related to the value in `current`).
  • turbosupraturbosupra Posts: 1,088
    edited 2014-10-27 19:20
    Thank you everyone, I thought I had commented everything out and still saw the glitch, but I will try that and I will also change to having a cog for debugging. I don't have a free cog at the moment, so that make take some juggling but I will do so.
  • DavidZemonDavidZemon Posts: 2,973
    edited 2014-10-27 19:51
    Something that may free up some cogs: use a cheap, secondary chip (with interrupts) to measure periodic and analog items such as air flow/pressure, throttle position, and others. For such simple tasks, interrupts enable a very small chip like Atmega 328, MSP430, 8051 to handle far more than a single propeller cog. So a single Prop cog communicates with the secondary chip and that chip can free up 2, 3 or even more cogs. I decided the ADC on the MSP430 was accurate enough (possible a foolish choice... never got far enough to know) for my purposes so I didn't even need a standalone ADC at that point.
  • turbosupraturbosupra Posts: 1,088
    edited 2014-10-28 19:48
    This worked well with a slight tweak (I believe the square wave signal is not 50/50 so I changed the modifier "15" to "25"), I will continue to read up on the counters as I had forgotten about them. Thank you.

    ChrisGadd wrote: »
    Your code is somewhat difficult to follow, but if I were to guess I'd say the glitchiness is due to the sampling rate, which is slowed considerably from all of those debug statements.

    Indeed, using a function generator, your code reports a linear increase from 1Hz (30rpm) up to 28Hz (840rpm), then at 29Hz it glitches to ~435rpm.
    Commenting out all of the debug statements, except the final one that shows the average, and it can show up to 9000rpm at 300Hz input.
    Best advice there is to follow Jon's advice and use a dedicated debug cog.

    Have you considered using the built in counters? Either an edge detector to count the number of transitions, or a level detector to count the number of clock ticks that the signal remains high or low.
    Here're a few ideas:
    PUB Main
    
      debug.start(31,30,0,115200)
      waitcnt(cnt + clkfreq)
    
    ' posedge_counter
      pos_counter
    ' pos_demo
    
    PUB posedge_counter | ticks
    {
     Use the posedge counter mode to count the number of positive transitions in one second.
     Fails when dealing fractional frequencies - 2.5Hz should be 75rpm
     Display alternates between 60 and 90
    }
    
      ctra := %01010 << 26 | I_RPM                          ' Configure counter A to increment phsa on every positive transition
      frqa := 1                                             ' Increment phsa by 1 on each transition
    
      repeat
        phsa := 0                                           ' Clear phsa
        waitcnt(cnt + clkfreq)                              ' Wait one second
        ticks := phsa                                       ' Copy phsa into ticks
        debug.dec(ticks * 60 / 2)                           ' Convert ticks into rpm
        debug.tx($0D)
    
    PUB pos_counter | ticks
    {
     Use the pos counter mode to count the number of ticks that the input remains high
     Divide by the clock frequency
    }
    
      ctra := %01000 << 26 | I_RPM                          ' Configure counter A to increment phsa on every clock that the input is high
      frqa := 1                                             ' Increment phsa by 1 on each clock that the input is high               
                                                                                                                                     
      repeat                                                                                                                         
        phsa := 0                                           ' Clear phsa                                                             
        repeat until ina[I_RPM]                             ' Wait for the input to go high                                          
        repeat until not ina[I_RPM]                         ' Wait for the input to go low                                           
        ticks := phsa                                       ' Copy phsa into ticks                                                   
        debug.dec(clkfreq / ticks * 15)                     ' Convert ticks into rpm
        debug.tx($0D)
    
    PUB pos_demo | i, av0, av1, av2, av3, av4, average
    
      ctra := %01000 << 26 | I_RPM                          ' Configure counter A to increment phsa on every clock that the input is high
      frqa := 1                                             ' Increment phsa by 1 on each clock that the input is high
    
      repeat
        repeat i from 0 to 4
          av0[i] := (clkfreq / counter * 15)
        average := (av0 + av1 + av2 + av3 + av4) / 5
        debug.dec(average)
        debug.tx($0D)
        
    PRI counter : ticks
    {
     Return the number of ticks that input was high
    }
      repeat until not ina[I_RPM]                           ' Wait for the input to go low                          
      phsa := 0                                             ' Clear phsa                                                             
      repeat until ina[I_RPM]                               ' Wait for the input to go high                                          
      repeat until not ina[I_RPM]                           ' Wait for the input to go low                                           
      ticks := phsa                                         ' Copy phsa into ticks                                                   
    
  • ChrisGaddChrisGadd Posts: 310
    edited 2014-10-29 08:31
    Rather than guesstimating the duty-cycle constant for the high pulse width, use the second counter to measure the low pulse width, and add the two together to get the period. Divide the clock frequency by the period to get the number of periods per second, and convert that to your rpm.
    CON 
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000
      I_RPM = 1                   
    
    VAR
      long  rpm_stack[10]
      long  rpm
      
    OBJ
      debug : "FullDuplexSerial"                              
    
    PUB Main
      debug.start(31,30,0,115_200)
      waitcnt(cnt + clkfreq)
      cognew(sample_rpm,@rpm_stack)
    
      repeat
        waitcnt(cnt + clkfreq / 20)
        debug.dec(rpm)
        debug.tx($0D)
    
    PUB sample_rpm | total, high, low
    {{
      Runs in a new cog, 
      Stores a rolling average in rpm, rpm must be declared in a VAR block
      Glitches between 5KHz and 6KHz at 50% duty cycle
      Glitches around 175Hz with a 1% or 99% duty cycle
    }}
      ctra := %01000 << 26 | I_RPM                          ' Configure counter A to increment phsa on every clock that the input is high
      ctrb := %01100 << 26 | I_RPM                          ' Configure counter B to increment phsb on every clock that the input is low
      frqa := 1                                             ' Increment phsa by 1 on each clock that the input is high
      frqb := 1                                             ' Increment phsb by 1 on each clock that the input is low
      total := 0                                            ' Initialize total
                                                            
      repeat                                                
        repeat until not ina[I_RPM]                         ' Wait for the input to go low (high pulse finished)
        high := phsa                                        ' Store high pulse width in high
        total := total - rpm                                '  Subtract the average from the total
        total := total + clkfreq / ((high + low) / 30)      '  Add the new period to the total
        rpm := total / 5                                    '  Divide the total by the sample size
        phsa := 0                                           ' Reset high time accumulator
        
        repeat until ina[I_RPM]                             ' Wait for the input to go high (low pulse finished)
        low := phsb                                         ' Repeating the calculations and using separate registers for high and low
        total := total - rpm                                '  allows for updating the rpm twice each period 
        total := total + clkfreq / ((high + low) / 30)      '  (faster response time to small changes in slow frequencies)
        rpm := total / 5                                    '  
        phsb := 0                                           '
    
  • turbosupraturbosupra Posts: 1,088
    edited 2014-10-29 18:50
    Brilliant! :D

    rpm_Code_Success1.jpg

    ChrisGadd wrote: »
    Rather than guesstimating the duty-cycle constant for the high pulse width, use the second counter to measure the low pulse width, and add the two together to get the period. Divide the clock frequency by the period to get the number of periods per second, and convert that to your rpm.
    CON 
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000
      I_RPM = 1                   
    
    VAR
      long  rpm_stack[10]
      long  rpm
      
    OBJ
      debug : "FullDuplexSerial"                              
    
    PUB Main
      debug.start(31,30,0,115_200)
      waitcnt(cnt + clkfreq)
      cognew(sample_rpm,@rpm_stack)
    
      repeat
        waitcnt(cnt + clkfreq / 20)
        debug.dec(rpm)
        debug.tx($0D)
    
    PUB sample_rpm | total, high, low
    {{
      Runs in a new cog, 
      Stores a rolling average in rpm, rpm must be declared in a VAR block
      Glitches between 5KHz and 6KHz at 50% duty cycle
      Glitches around 175Hz with a 1% or 99% duty cycle
    }}
      ctra := %01000 << 26 | I_RPM                          ' Configure counter A to increment phsa on every clock that the input is high
      ctrb := %01100 << 26 | I_RPM                          ' Configure counter B to increment phsb on every clock that the input is low
      frqa := 1                                             ' Increment phsa by 1 on each clock that the input is high
      frqb := 1                                             ' Increment phsb by 1 on each clock that the input is low
      total := 0                                            ' Initialize total
                                                            
      repeat                                                
        repeat until not ina[I_RPM]                         ' Wait for the input to go low (high pulse finished)
        high := phsa                                        ' Store high pulse width in high
        total := total - rpm                                '  Subtract the average from the total
        total := total + clkfreq / ((high + low) / 30)      '  Add the new period to the total
        rpm := total / 5                                    '  Divide the total by the sample size
        phsa := 0                                           ' Reset high time accumulator
        
        repeat until ina[I_RPM]                             ' Wait for the input to go high (low pulse finished)
        low := phsb                                         ' Repeating the calculations and using separate registers for high and low
        total := total - rpm                                '  allows for updating the rpm twice each period 
        total := total + clkfreq / ((high + low) / 30)      '  (faster response time to small changes in slow frequencies)
        rpm := total / 5                                    '  
        phsb := 0                                           '
    
  • ElectrodudeElectrodude Posts: 1,658
    edited 2014-10-29 19:21
    ChrisGadd wrote: »
    CON 
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000
      I_RPM = 1                   
    
    VAR
      long  rpm_stack[10]
      long  rpm
      
    OBJ
      debug : "FullDuplexSerial"                              
    
    PUB Main
      debug.start(31,30,0,115_200)
      waitcnt(cnt + clkfreq)
      cognew(sample_rpm,@rpm_stack)
    
      repeat
        waitcnt(cnt + clkfreq / 20)
        debug.dec(rpm)
        debug.tx($0D)
    
    PUB sample_rpm | total, high, low
    {{
      Runs in a new cog, 
      Stores a rolling average in rpm, rpm must be declared in a VAR block
      Glitches between 5KHz and 6KHz at 50% duty cycle
      Glitches around 175Hz with a 1% or 99% duty cycle
    }}
      ctra := %01000 << 26 | I_RPM                          ' Configure counter A to increment phsa on every clock that the input is high
      ctrb := %01100 << 26 | I_RPM                          ' Configure counter B to increment phsb on every clock that the input is low
      frqa := 1                                             ' Increment phsa by 1 on each clock that the input is high
      frqb := 1                                             ' Increment phsb by 1 on each clock that the input is low
      total := 0                                            ' Initialize total
                                                            
      repeat                                                
        repeat until not ina[I_RPM]                         ' Wait for the input to go low (high pulse finished)
        high := phsa                                        ' Store high pulse width in high
        total := total - rpm                                '  Subtract the average from the total
        total := total + clkfreq / ((high + low) / 30)      '  Add the new period to the total
        rpm := total / 5                                    '  Divide the total by the sample size
        phsa := 0                                           ' Reset high time accumulator
        
        repeat until ina[I_RPM]                             ' Wait for the input to go high (low pulse finished)
        low := phsb                                         ' Repeating the calculations and using separate registers for high and low
        total := total - rpm                                '  allows for updating the rpm twice each period 
        total := total + clkfreq / ((high + low) / 30)      '  (faster response time to small changes in slow frequencies)
        rpm := total / 5                                    '  
        phsb := 0                                           '
    

    It would be more (I have no idea how much more) accurate to clear phs[ab] immediately after you read it using the post-clear operator x~, instead of after 3 slow divides.
    CON 
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000
      I_RPM = 1                   
    
    VAR
      long  rpm_stack[10]
      long  rpm
      
    OBJ
      debug : "FullDuplexSerial"                              
    
    PUB Main
      debug.start(31,30,0,115_200)
      waitcnt(cnt + clkfreq)
      cognew(sample_rpm,@rpm_stack)
    
      repeat
        waitcnt(cnt + clkfreq / 20)
        debug.dec(rpm)
        debug.tx($0D)
    
    PUB sample_rpm | total, high, low
    {{
      Runs in a new cog, 
      Stores a rolling average in rpm, rpm must be declared in a VAR block
      Glitches between 5KHz and 6KHz at 50% duty cycle
      Glitches around 175Hz with a 1% or 99% duty cycle
    }}
      ctra := %01000 << 26 | I_RPM                          '  Configure counter A to increment phsa on every clock that the input is  high
      ctrb := %01100 << 26 | I_RPM                          '  Configure counter B to increment phsb on every clock that the input is  low
      frqa := 1                                             ' Increment phsa by 1 on each clock that the input is high
      frqb := 1                                             ' Increment phsb by 1 on each clock that the input is low
      total := 0                                            ' Initialize total
                                                            
      repeat                                                
        repeat until not ina[I_RPM]                         ' Wait for the input to go low (high pulse finished)
        [B]high := phsa~[/B]                                        ' Store high pulse width in high[B] - post-clear[/B]
        total := total - rpm                                '  Subtract the average from the total
        total := total + clkfreq / ((high + low) / 30)      '  Add the new period to the total
        rpm := total / 5                                    '  Divide the total by the sample size
        
        repeat until ina[I_RPM]                             ' Wait for the input to go high (low pulse finished)
        [B]low := phsb~[/B]                                        ' Repeating the  calculations and using separate registers for high and low[B] - post-clear[/B]
        total := total - rpm                                '  allows for updating the rpm twice each period 
        total := total + clkfreq / ((high + low) / 30)      '  (faster response time to small changes in slow frequencies)
        rpm := total / 5                                    '  
    
  • ChrisGaddChrisGadd Posts: 310
    edited 2014-10-29 19:31
    Hadn't thought of that, though it shouldn't make a difference in this case. Counter A is set to measure the high pulse width, and the value is copied and phsa is re-initialized during the low pulse. Counter B measures the low pulse, and phsb is re-initialized during the high pulse. Re-initializing earlier in the code would merely have them sit at 0 for a few extra ticks.

    Edited for a second thought.
    The above is true if the pulse is symetrical (50% duty) where the calculations not being finished before the next pulse width would glitch regardless of when phsx was re-initialized, however it makes a significant difference at a 1% duty cycle. The signal only has to be high long enough for phsb to be copied and cleared, as it doesn't matter if the signal goes low during the calculations.

    With the original code, the readings get glitchy around 175Hz, with Electrodude's modification the readings are stable up to 500Hz.
  • turbosupraturbosupra Posts: 1,088
    edited 2014-10-31 09:46
    How were you able to get this code to glitch using a function generator? I could only get it to glitch in testing in the car and never on the bench and I'd like to learn how you did that?

    ChrisGadd wrote: »
    Your code is somewhat difficult to follow, but if I were to guess I'd say the glitchiness is due to the sampling rate, which is slowed considerably from all of those debug statements.

    Indeed, using a function generator, your code reports a linear increase from 1Hz (30rpm) up to 28Hz (840rpm), then at 29Hz it glitches to ~435rpm.
    Commenting out all of the debug statements, except the final one that shows the average, and it can show up to 9000rpm at 300Hz input.
    Best advice there is to follow Jon's advice and use a dedicated debug cog.

    Have you considered using the built in counters? Either an edge detector to count the number of transitions, or a level detector to count the number of clock ticks that the signal remains high or low.
    Here're a few ideas:
  • ChrisGaddChrisGadd Posts: 310
    edited 2014-10-31 14:54
    Ah, I might have misunderstood which problem you were asking about. With the I_KeyOn pulled high and a signal generator with a 0 - 3.3V output connected to I_Rpm, the readings on the serial terminal show a linear increase from 1Hz (30rpm) up to 28Hz (840rpm).
    There's some flickering above 20Hz where the readings might be +/- 3, but aside from that it is stable.
    At 29Hz, however, the readings should be 870rpm, are instead being read as 435rpm.

    I took another look at it, and it seems you must have a counter rolling over somewhere. It actually does read correctly for about 12 seconds, then it reads low for about 42 seconds.
    2^32 x 12.5ns = 53.687 seconds
    good readings for ~12 seconds         bad readings for ~42 seconds           
    rpmTimeStamp5 !< rpmTimeStamp6        rpmTimeStamp5 !< rpmTimeStamp6         rpmTimeStamp5 !< rpmTimeStamp6     rpmTimeStamp5 !< rpmTimeStamp6       
    1056197782 - 1053445622 = 2752160     1058963478 - 1056197782 = 2765696      4374155 - 251899 = 4122256         7108587 - 4374155 = 2734432          
    rpmTimeStamp4 !< rpmTimeStamp5        rpmTimeStamp4 !< rpmTimeStamp5         rpmTimeStamp4 !< rpmTimeStamp5     rpmTimeStamp4 !< rpmTimeStamp5       
    1058963478 - 1056197782 = 2765696     1061722390 - 1058963478 = 2758912      7108587 - 4374155 = 2734432        9840267 - 7108587 = 2731680          
    rpmTimeStamp3 !< rpmTimeStamp4        rpmTimeStamp3 !< rpmTimeStamp4         rpmTimeStamp3 !< rpmTimeStamp4     rpmTimeStamp3 !< rpmTimeStamp4       
    1061722390 - 1058963478 = 2758912     1064484758 - 1061722390 = 2762368      9840267 - 7108587 = 2731680        12579147 - 9840267 = 2738880         
    rpmTimeStamp2 !< rpmTimeStamp3        rpmTimeStamp2 !< rpmTimeStamp3         rpmTimeStamp2 !< rpmTimeStamp3     rpmTimeStamp2 !< rpmTimeStamp3       
    1064484758 - 1061722390 = 2762368     1067264502 - 1064484758 = 2779744      12579147 - 9840267 = 2738880       15327435 - 12579147 = 2748288        
    rpmTimeStamp1 !< rpmTimeStamp2        rpmTimeStamp1 !< rpmTimeStamp2         rpmTimeStamp1 !< rpmTimeStamp2     rpmTimeStamp1 !< rpmTimeStamp2       
    1067264502 - 1064484758 = 2779744     1071421750 - 1067264502 = 4157248      15327435 - 12579147 = 2748288      18107627 - 15327435 = 2780192        
    Calculated rpm is: 867                Calculated rpm is: 786                 Calculated rpm is: 795             Calculated rpm is: 873               
                                           ***** < 600 *****                      ***** < 600 *****            
                           Here's where it starts glitching                                        Here's where it stops glitching
    
    At 30Hz and up, it is always misreading. Commenting out all of the debug statements up to the "Calculated RPM is:" line allows it to read correctly... within reason.
    100Hz produces readings from 2997 to 3003. 300Hz gives 8937 to 9057.
    Even with the debugs commented out, this object starts running into problems at about 361Hz - should be 10830rpm, reading 9042 to 10767.

    I replaced the function generator with the freq_synth object from the Propeller library demo so you can see what I see.


    Your simulateRpm method does indeed appear to give good readings from 24Hz (720rpm) to 76Hz(2280rpm). I suspect that the reason we don't see it glitch is due to the way it is constantly varying, which somehow isn't giving the counters the opportunity of rolling over, or whatever's going wrong. Try a steady signal instead.

    rpmTest7a.spin
  • turbosupraturbosupra Posts: 1,088
    edited 2014-11-01 09:22
    With Synth("A",I_Rpm, 361), I would see it glitch, but with Synth("A",I_Rpm, 29) it reads a constant 867rpm and with Synth("A",I_Rpm, 30) it will fluctuate between 897 and 900. If I understood what you wrote correctly, you would get a glitch at a frequency of 29, correct? And it would glitch to 435rpm? I ask specifically because this is exactly the rpm I was seeing in the vehicle when it would glitch and it was driving me nuts.

    Another flaw I found today and a hard lesson to learn, which was assuredly causing me issues is that I_Rpm is based on voltage into a voltage divider of 10k and 2.7k, so voltage should be anywhere from 2.34vDc to 2.98vDc with a 11 to 14v input. This was the case when the car was not running, but when it runs the alternator does some craziness to the electrical system. Unknowingly until today, I was plagued by I_Rpm == 0 every once in a while, which puts the code in a lower power state of 1hz per loop and outputs are turned off. This was hosing my timing calculations for a frequency generator (among other things) and I've been chasing this for a few weeks now. Finally driving around with the laptop, the com window open, some additional commenting and my scope I was able to identify it. I mention all of this, because the calculateRpm was also dependent on I_Rpm == 1.

    I thought about trying to solve this by using a 3k/10k resistor ladder, but decided to put a 100uF cap inline with the resistor ladder. Do you think this was the best solution? How do you normally tackle these type of automotive issues?
  • ChrisGaddChrisGadd Posts: 310
    edited 2014-11-02 14:24
    It was only glitching at 29Hz with the debugs un-commented, without the debugs it seems to be good up to ~361.

    As for connecting to a 14 volt signal, there are level shifters, buffers, optocouplers, current limiters, voltage dividers... whatever works.

    See this thread for interfacing to 5V.
Sign In or Register to comment.