Need some help with PASM portion of this Ping object
in Propeller 1
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.
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
{{ ┌──────────────────────────────────────────┐ │ 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 fitI 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?
{{ 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 fitI 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.
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