Shop OBEX P1 Docs P2 Docs Learn Events
Need some help with PASM portion of this Ping object — Parallax Forums

Need some help with PASM portion of this Ping object

I want to be able to use the PASM part of this object along with my main object code to be able to read x number of Pings. To be able to pass to it the pin number of a Ping and get back the distance value. What I like about this code is that it will return a 0 if there is no Ping connected and the program won't hang. So how does one package this to be an object that you can pass parameters to and receive data from?

Thanks.
{{
┌──────────────────────────────────────────┐
│ Ping_Fast.spin                           │
│ Author: Wm Dygon (pogertt@wi.rr.com)     │               
│ Copyright (c) 2012 Wm Dygon              │               
│ See end of file for terms of use.        │                
└──────────────────────────────────────────┘

 Object to read a Ping)) sensor over it's entire range as fast and as consistently as possible.

       
  ┌───────────────────┐
  │┌───┐         ┌───┐│    Connection To Propeller
  ││ ‣ │ PING))) │ ‣ ││    Remember PING))) Requires
  │└───┘         └───┘│    +5V Power Supply
  │    GND +5V SIG    │
  └─────┬───┬───┬─────┘
        │  │    3.3K
          └┘   └ Pin


 The assembly portion executes in 2_000_000 clock cycles'
 at 80_000_000 hertz clock, that gives an execution time of
 .025 seconds or 40.000 reads per second.

        
    
     │  │              │               │←───────────────→│← Next Trigger Pulse
    →│  │←Trigger Pulse│← Echo Return →│                 │ 
     │← Echo Holdoff  →│               │← Delay B4 Next →│
 

    Echo Holdoff  =    60_000
    Echo Return   = 1_924_000
    Delay B4 Next =    16_000
    Total Clocks  = 2_000_000
         
 Deivating from the Parallax data sheet:
 
 I start my Echo Holdoff time from when the trigger pulse starts, rather than when it ends.
 
 I have found the Maximum Echo Return Pulse to be between 21.6 and 21.7 milliseconds.
 By allowing 24.050 milliseconds Echo Return, I ensure the potential maximum detection distance
 has been seen.
 This value also pads exicution time so the read has a regular 25 millisecond repeat rate.
 
}}
CON
        _clkmode = xtal1 + pll16x                       'Standard clock mode * crystal frequency = 80 MHz
        _xinfreq = 5_000_000

        Ping_Pin = 0                                   '  Pin that Ping))) Sensor is wired to
        DPu = 13512
{{      DPu assumes Speed of Sound to be 1126 Feet per Second in Dry Air @ 68 °F.
        1126 * 12 = 1352 inches per second

}}        
VAR

        long          Sensor_Pin    
        long          Echo_Length
        long          Distance
        long          uSec
        long          Raw_Distance
        long          Remainder

OBJ

        pst : "Parallax Serial Terminal"
      
PUB   start  :  okay       

      pst.start(115_200)                    ' Start the Display
       
      Sensor_Pin := Ping_Pin                ' Prepare Variable
      
      cognew (@entry,@Sensor_Pin)           ' Start Assembly Routine in a new COG
      
      waitcnt(clkfreq + cnt)                ' Wait a second

      ' Prepare Display screen with Labels for data to be shown
      
      pst.str(string("          PING))) Demo",13,13))
      pst.str(string("  Raw Count in CLOCK Cycles........",13,13))
      pst.str(string("  One Way Time in CLOCK Cycles.....",13,13))  
      pst.str(string("  µSeconds to Target...............",13,13)) 
      pst.str(string("  Distance in Inches...............",13,13)) 
  
    repeat
        pst.Position(34,2)
        pst.ClearEnd      
        pst.dec(Echo_Length)      'Raw Count in CLOCK Cycles

        Distance := Echo_Length >> 1
        pst.Position(34,4)
        pst.ClearEnd
        pst.dec(Distance)         'One Way Time in CLOCK Cycles

        uSec := Distance / 80
        pst.Position(34,6)
        pst.ClearEnd
        pst.dec(uSec)             'µSeconds to Target
         
        pst.Position(34,8)
        pst.ClearEnd
        Raw_Distance := uSec * DPu  / 1_000_000
        Remainder := uSec * DPu // 1_000_000
        pst.dec(Raw_Distance)     'Distance in Inches
        pst.char(46)              'Print decimal point
        pst.dec(Remainder)        'Distance fractional portion

        waitcnt(clkfreq/4 + cnt)  'Wait to do it again


Dat

entry         org       0
              rdlong    P_Pin, par                      'Read Main Ram to find out Pin Ping)) is wired to.
              mov       Pin, #1                         'Set a 1 into "Pin"
              shl       Pin, P_Pin                      'Shift the 1 to Pin bit
              add       Trigger_Counter, P_Pin          'Add Pin into APIN of Counter
              add       Echo_Counter, P_Pin             'Add Pin into APIB of Counter
              mov       Echo_to_Main_Ram, par           'Echo_to_Main_Ram is distance to be returned.
              add       Echo_to_Main_Ram, #4            'Make it the second Variable in the list
              mov       frqa, #1                        'Set frqa to count 1 per clock
              mov       time, cnt                       'Get original time stamp

:loop         add          time, Echo_Holdoff           'Add Echo_Holdoff to time   
              mov          ctra, Trigger_Counter        'Set counter to NCO single-ended mode
              or           dira, pin                    'Set APIN to be an output
              neg          phsa, Trigger_Pulse          'Send Trigger Pulse 2 µsec pulse  
              waitcnt      time, Echo_Pulse             'Wait for Echo_Holdoff 750 µsec  
              muxc         dira, pin                    'Make Ping))) Pin into an Input    
              mov          ctra, Echo_Counter           'Time Echo Return Pulse     
              mov          phsa, #0                     'Clear the accumulator 
              waitcnt      time, Delay_B4_Next          'Wait for pulse to complete  ≈ 21.7 msec max 
              mov          Echo, phsa                   'Read Echo Return Pulse length
              wrlong       Echo, Echo_to_Main_Ram       'Write the result to Main Ram
              waitcnt      time, #0                     'Wait B4 taking another measurment
              jmp          #:loop                       'Loop forever

Trigger_Counter         long    %00100_000_00000000_000000_000_<< 6  'NCO single-ended Mode
Echo_Counter            long    %11010_000_00000000_000000_000_<< 6  'LOGIC A Mode

Trigger_Pulse           long    160                     '2 µsec Trigger Pulse Width
Echo_Holdoff            long    60_000                  '750 µsec wait B4 Measuring Echo Pulse
Echo_Pulse              long    1_924_000               '1_924_000 for 40 reads per second
Delay_B4_Next           long    16_000                  '200 µsec Delay B4 Next Cycle

Pin                     res     1
P_Pin                   res     1
time                    res     1
Echo                    res     1
Echo_to_Main_Ram        res     1


             fit

{{
┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│                                                   TERMS OF USE: MIT License                                                  │                                                            
├──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation    │ 
│files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,    │
│modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software│
│is furnished to do so, subject to the following conditions:                                                                   │
│                                                                                                                              │
│The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.│
│                                                                                                                              │
│THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE          │
│WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR         │
│COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,   │
│ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                         │
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
}}                                    

Comments

  • Don MDon M Posts: 1,652
    Maybe to be a little more clear let's say for example I had 6 pings that I want to be able to read...
  • Here's an ugly hack.
    {{
    ┌──────────────────────────────────────────┐
    │ Ping_Fast.spin                           │
    │ Author: Wm Dygon (pogertt@wi.rr.com)     │               
    │ Copyright (c) 2012 Wm Dygon              │               
    │ See end of file for terms of use.        │                
    └──────────────────────────────────────────┘
    
     Object to read a Ping)) sensor over it's entire range as fast and as consistently as possible.
    
           
      ┌───────────────────┐
      │┌───┐         ┌───┐│    Connection To Propeller
      ││ ‣ │ PING))) │ ‣ ││    Remember PING))) Requires
      │└───┘         └───┘│    +5V Power Supply
      │    GND +5V SIG    │
      └─────┬───┬───┬─────┘
            │  │    3.3K
              └┘   └ Pin
    
    
     The assembly portion executes in 2_000_000 clock cycles'
     at 80_000_000 hertz clock, that gives an execution time of
     .025 seconds or 40.000 reads per second.
    
            
        
         │  │              │               │←───────────────→│← Next Trigger Pulse
        →│  │←Trigger Pulse│← Echo Return →│                 │ 
         │← Echo Holdoff  →│               │← Delay B4 Next →│
     
    
        Echo Holdoff  =    60_000
        Echo Return   = 1_924_000
        Delay B4 Next =    16_000
        Total Clocks  = 2_000_000
             
     Deivating from the Parallax data sheet:
     
     I start my Echo Holdoff time from when the trigger pulse starts, rather than when it ends.
     
     I have found the Maximum Echo Return Pulse to be between 21.6 and 21.7 milliseconds.
     By allowing 24.050 milliseconds Echo Return, I ensure the potential maximum detection distance
     has been seen.
     This value also pads exicution time so the read has a regular 25 millisecond repeat rate.
     
    }}
    CON
            _clkmode = xtal1 + pll16x                       'Standard clock mode * crystal frequency = 80 MHz
            _xinfreq = 5_000_000
    
            Ping_Pin = 0                                   '  Pin that Ping))) Sensor is wired to
            DPu = 13512
    {{      DPu assumes Speed of Sound to be 1126 Feet per Second in Dry Air @ 68 °F.
            1126 * 12 = 1352 inches per second
    
    }}        
    VAR
    
            long          Sensor_Pin    
            long          Echo_Length
            long          Distance
            long          uSec
            long          Raw_Distance
            long          Remainder
    
    OBJ
    
            pst : "Parallax Serial Terminal"
          
    PUB   start  :  okay       
    
          pst.start(115_200)                    ' Start the Display
    
          SetPin(Ping_Pin)
          cognew (@entry,@Sensor_Pin)           ' Start Assembly Routine in a new COG
          
          waitcnt(clkfreq + cnt)                ' Wait a second
    
          ' Prepare Display screen with Labels for data to be shown
          
          pst.str(string("          PING))) Demo",13,13))
          pst.str(string("  Raw Count in CLOCK Cycles........",13,13))
          pst.str(string("  One Way Time in CLOCK Cycles.....",13,13))  
          pst.str(string("  µSeconds to Target...............",13,13)) 
          pst.str(string("  Distance in Inches...............",13,13)) 
      
        repeat
            pst.Position(34,2)
            pst.ClearEnd      
            pst.dec(Echo_Length)      'Raw Count in CLOCK Cycles
    
            Distance := Echo_Length >> 1
            pst.Position(34,4)
            pst.ClearEnd
            pst.dec(Distance)         'One Way Time in CLOCK Cycles
    
            uSec := Distance / 80
            pst.Position(34,6)
            pst.ClearEnd
            pst.dec(uSec)             'µSeconds to Target
             
            pst.Position(34,8)
            pst.ClearEnd
            Raw_Distance := uSec * DPu  / 1_000_000
            Remainder := uSec * DPu // 1_000_000
            pst.dec(Raw_Distance)     'Distance in Inches
            pst.char(46)              'Print decimal point
            pst.dec(Remainder)        'Distance fractional portion
    
            waitcnt(clkfreq/4 + cnt)  'Wait to do it again
    
    PUB SetPin(newPin)
    
      Sensor_Pin := newPin
      
    Dat
    
                  org       0
    
    entry         mov       Echo_to_Main_Ram, par           'Echo_to_Main_Ram is distance to be returned.
                  add       Echo_to_Main_Ram, #4            'Make it the second Variable in the list
                  mov       frqa, #1                        'Set frqa to count 1 per clock
                  
    loop          rdlong    P_Pin, par                      'Read Main Ram to find out Pin Ping)) is wired to.
                  mov       Pin, #1                         'Set a 1 into "Pin"
                  shl       Pin, P_Pin                      'Shift the 1 to Pin bit
                  mov       Trigger_Counter_W_Pin, Trigger_Counter
                  add       Trigger_Counter_W_Pin, P_Pin          'Add Pin into APIN of Counter
                  mov       Echo_Counter_W_Pin, Echo_Counter
                  add       Echo_Counter_W_Pin, P_Pin             'Add Pin into APIB of Counter
                  mov       time, cnt                       'Get original time stamp
    
                  add          time, Echo_Holdoff           'Add Echo_Holdoff to time   
                  mov          ctra, Trigger_Counter        'Set counter to NCO single-ended mode
                  or           dira, pin                    'Set APIN to be an output
                  neg          phsa, Trigger_Pulse          'Send Trigger Pulse 2 µsec pulse  
                  waitcnt      time, Echo_Pulse             'Wait for Echo_Holdoff 750 µsec  
                  muxc         dira, pin                    'Make Ping))) Pin into an Input    
                  mov          ctra, Echo_Counter           'Time Echo Return Pulse     
                  mov          phsa, #0                     'Clear the accumulator 
                  waitcnt      time, Delay_B4_Next          'Wait for pulse to complete  ≈ 21.7 msec max 
                  mov          Echo, phsa                   'Read Echo Return Pulse length
                  wrlong       Echo, Echo_to_Main_Ram       'Write the result to Main Ram
                  waitcnt      time, #0                     'Wait B4 taking another measurment
                  jmp          #loop                        'Loop forever
    
    Trigger_Counter         long    %00100_000_00000000_000000_000_<< 6  'NCO single-ended Mode
    Echo_Counter            long    %11010_000_00000000_000000_000_<< 6  'LOGIC A Mode
    
    Trigger_Pulse           long    160                     '2 µsec Trigger Pulse Width
    Echo_Holdoff            long    60_000                  '750 µsec wait B4 Measuring Echo Pulse
    Echo_Pulse              long    1_924_000               '1_924_000 for 40 reads per second
    Delay_B4_Next           long    16_000                  '200 µsec Delay B4 Next Cycle
    
    Pin                     res     1
    P_Pin                   res     1
    time                    res     1
    Echo                    res     1
    Echo_to_Main_Ram        res     1
    Trigger_Counter_W_Pin   res     1
    Echo_Counter_W_Pin      res     1
    
    
                 fit
    

    I haven't tested it.

    You could use "SetPin" to change which I/O is actively used.

    As I said, this is a hack. It seems like the thing to do would be to have an array of I/O pin numbers and an array of returned pulse lengths. The PASM code could cycle through each of the pins one after the other.

    As I think about this, I don't think it would be hard to program. Does something like I just described sound like a good option? How many Ping sensors are you wanting to use? It should be easy to make the number of sensors configurable but how many should I use for the example program?
  • Duane DegnDuane Degn Posts: 10,588
    edited 2016-01-10 06:51
    This version is much better.
    {{
    
       FastPingMulti.spin
       January 9, 2016
       Modified for multiple sensors by Duane Degn
    ┌──────────────────────────────────────────┐
    │ Ping_Fast.spin                           │
    │ Author: Wm Dygon (pogertt@wi.rr.com)     │               
    │ Copyright (c) 2012 Wm Dygon              │               
    │ See end of file for terms of use.        │                
    └──────────────────────────────────────────┘
    
     Object to read a Ping)) sensor over it's entire range as fast and as consistently as possible.
    
           
      ┌───────────────────┐
      │┌───┐         ┌───┐│    Connection To Propeller
      ││ ‣ │ PING))) │ ‣ ││    Remember PING))) Requires
      │└───┘         └───┘│    +5V Power Supply
      │    GND +5V SIG    │
      └─────┬───┬───┬─────┘
            │  │    3.3K
              └┘   └ Pin
    
    
     The assembly portion executes in 2_000_000 clock cycles'
     at 80_000_000 hertz clock, that gives an execution time of
     .025 seconds or 40.000 reads per second.
    
            
        
         │  │              │               │←───────────────→│← Next Trigger Pulse
        →│  │←Trigger Pulse│← Echo Return →│                 │ 
         │← Echo Holdoff  →│               │← Delay B4 Next →│
     
    
        Echo Holdoff  =    60_000
        Echo Return   = 1_924_000
        Delay B4 Next =    16_000
        Total Clocks  = 2_000_000
             
     Deviating from the Parallax data sheet:
     
     I start my Echo Holdoff time from when the trigger pulse starts, rather than when it ends.
     
     I have found the Maximum Echo Return Pulse to be between 21.6 and 21.7 milliseconds.
     By allowing 24.050 milliseconds Echo Return, I ensure the potential maximum detection distance
     has been seen.
     This value also pads execution time so the read has a regular 25 millisecond repeat rate.
     
    }}
    CON
            _clkmode = xtal1 + pll16x                       'Standard clock mode * crystal frequency = 80 MHz
            _xinfreq = 5_000_000
    
            NUMBER_OF_SENSORS = 2
            
            DPu = 13512
    {{      DPu assumes Speed of Sound to be 1126 Feet per Second in Dry Air @ 68 °F.
            1126 * 12 = 1352 inches per second
    
    }}        
    VAR
    
            
            long          Distance
            long          uSec
            long          Raw_Distance
            long          Remainder
    
    OBJ
    
            pst : "Parallax Serial Terminal"
          
    PUB   start      
    
          pst.start(115_200)                    ' Start the Display
    
          cognew (@entry, @Echo_Length)           ' Start Assembly Routine in a new COG
          
          waitcnt(clkfreq + cnt)                ' Wait a second
    
    
        repeat
          pst.ClearBelow
          pst.Home
          pst.str(string("          PING))) Demo"))
          repeat result from 0 to NUMBER_OF_SENSORS - 1 
            pst.str(string(11, 13, 11, 13, "  Raw Count in CLOCK Cycles........"))
          
            pst.dec(Echo_Length[result])      'Raw Count in CLOCK Cycles
    
            Distance := Echo_Length[result] >> 1
            pst.str(string(11, 13, "  One Way Time in CLOCK Cycles....."))
            pst.dec(Distance)         'One Way Time in CLOCK Cycles
    
            uSec := Distance / 80
            pst.str(string(11, 13, "  µSeconds to Target..............."))
            pst.dec(uSec)             'µSeconds to Target
             
            pst.str(string(11, 13, "  Distance in Inches..............."))
            DecPoint(uSec * DPu, 1_000_000)
            pst.ClearEnd
            pst.Newline
    
            waitcnt(clkfreq/4 + cnt)  'Wait to do it again
    
    PUB DecPoint(value, denominator)
    
      if value < 0
        Pst.Char("-")
        -value
          
      if value => denominator
        result := value / denominator
        Pst.Dec(result)
        value //= denominator     
      else    
        Pst.Char("0")
      Pst.Char(".")  
      repeat while denominator > 1
        denominator /= 10
        if value => denominator
          result := value / denominator
          Pst.Dec(result)
          value //= denominator
        else
          Pst.Char("0")
          
    DAT
    
    Echo_Length             long 0[NUMBER_OF_SENSORS]
    pingPinNumber           byte 0, 1 'the number of elements should match
                                        ' the NUMBER_OF_SENSORS constant
    
    DAT
    
                            org       0
    
    entry                   mov     firstPinAddress, par
                            add     firstPinAddress, pinAddressOffset
                            'mov     frqa, #1                        'Set frqa to count 1 per clock
                           
    bigLoop                 mov     sensorCountDown, numberOfSensors
                            mov     activePinAddress, firstPinAddress
                            mov     activePulseAddress, par            
    loop                    mov     frqa, #1
                            rdbyte  activePinNumber, activePinAddress  'Read Main Ram to find out Pin Ping)) is wired to.
                            mov     pinMask, #1                    'initialize pinMask
                            shl     pinMask, activePinNumber       'Shift the 1 to Pin bit
                            mov     Trigger_Counter_W_Pin, Trigger_Counter
                            add     Trigger_Counter_W_Pin, activePinNumber          'Add Pin into APIN of Counter
                            mov     Echo_Counter_W_Pin, Echo_Counter
                            add     Echo_Counter_W_Pin, activePinNumber             'Add Pin into APIB of Counter
                            mov     time, cnt                       'Get original time stamp
                             
                            add     time, Echo_Holdoff           'Add Echo_Holdoff to time   
                            mov     ctra, Trigger_Counter_W_Pin  'Set counter to NCO single-ended mode
                            or      dira, pinMask                'Set APIN to be an output
                            neg     phsa, Trigger_Pulse          'Send Trigger Pulse 2 µsec pulse  
                            waitcnt time, Echo_Pulse             'Wait for Echo_Holdoff 750 µsec  
                            andn    dira, pinMask                'Make Ping))) Pin into an Input    
                            mov     ctra, Echo_Counter_W_Pin     'Time Echo Return Pulse     
                            mov     phsa, #0                     'Clear the accumulator 
                            waitcnt time, Delay_B4_Next          'Wait for pulse to complete  ≈ 21.7 msec max 
                            mov     Echo, phsa                   'Read Echo Return Pulse length
                            wrlong  Echo, activePulseAddress     'Write the result to Main Ram
                            waitcnt time, #0                     'Wait B4 taking another measurment
                            add     activePulseAddress, #4  
                            add     activePinAddress, #1  
                            djnz    sensorCountDown, #loop
                            jmp     #bigLoop
    
    Trigger_Counter         long    %00100_000_00000000_000000_000_<< 6  'NCO single-ended Mode
    Echo_Counter            long    %11010_000_00000000_000000_000_<< 6  'LOGIC A Mode
    
    Trigger_Pulse           long    160                     '2 µsec Trigger Pulse Width
    Echo_Holdoff            long    60_000                  '750 µsec wait B4 Measuring Echo Pulse
    Echo_Pulse              long    1_924_000               '1_924_000 for 40 reads per second
    Delay_B4_Next           long    16_000                  '200 µsec Delay B4 Next Cycle
    numberOfSensors         long    NUMBER_OF_SENSORS
    pinAddressOffset        long    NUMBER_OF_SENSORS * 4
    sensorCountDown         res     1
    firstPinAddress         res     1
    activePinAddress        res     1
    activePulseAddress      res     1
    pinMask                 res     1
    activePinNumber         res     1
    time                    res     1
    Echo                    res     1
    Trigger_Counter_W_Pin   res     1
    Echo_Counter_W_Pin      res     1
    
    
                 fit
    

    I changed the way the output was sent to the serial port to make it easier to display multiple sensors.

    I added the method "DecPoint" for displaying scaled integers. The original version wouldn't display decimal values correctly if the modulus had leading zeros.

    To change the number of sensors used, change the constant "NUMBER_OF_SENSORS" and modify the array "pingPinNumber" to include the I/O pins where the sensors are connected.
  • Don,
    I did a version of Ping fast (PASM) that seemed to work well in my testing. I have attached a zip of the demo program and the working object.
    Jim
  • I'm working on a Ping object, too -- just have to order a Ping to test it with!
  • Jon, You should have picked up some of the Radio Shack specials for $2.00. (The Parallax ones, not the cheap ones they are selling now).
Sign In or Register to comment.