InputCapture vs. PulseIn w/CallTask

Discussion about the ZBasic language including the System Library. If you're not sure where to post your message, do it here. However, do not make test posts here; that's the purpose of the Sandbox.
liam.zbasic
Posts: 163
Joined: 24 March 2008, 23:33 PM
Location: Southern California (Blue)

InputCapture vs. PulseIn w/CallTask

Post by liam.zbasic »

My new ground bot features a high rate feedback control system to track close objects with IR range sensors. Now I want to add an ultrasonic range sensor for long distances, however the measurement update rate is slow and highly variable. The InputCapture function seems ideal for the sonic ranger because it runs in the background, but I'm concerned the data array argument will take too much RAM (I'm using a ZX-40n device). So that leaves the PulseIn function, but the bot program has to wait for PulseIn to return results. App. note AN-210 ("Sharing Data between Tasks") makes me believe that I can use "CallTask" to call a separate subroutine to calculate distance from the sonic ranger as an independent background task. Will this work? Will PulseIn clash with my PWM functions?
dkinzer
Site Admin
Posts: 3120
Joined: 03 September 2005, 13:53 PM
Location: Portland, OR

Re: InputCapture vs. PulseIn w/CallTask

Post by dkinzer »

liam.zbasic wrote:Will this work?
Probably not. The problem is that PulseIn disables interrupts so no other task will be allowed to run until the pulse is seen.

As for using InputCapture() you may be able to get by with shorter sequences. Another alternative is to switch to the ZX-40s which has 16K of RAM.
- Don Kinzer
liam.zbasic
Posts: 163
Joined: 24 March 2008, 23:33 PM
Location: Southern California (Blue)

Post by liam.zbasic »

Yes, the ZX-40s is very enticing. For now, I want to make due with what I already own. I have a bunch of ZX-40a and ZX-328n chips. I'm thinking of using one of those to process the sonic range sensor, then output the result as a voltage with the DAC function. Then I'll read that voltage with an ADC from the ZX-40n device running the main bot program. Will DAC to ADC from separate chips work? And for the matter, will high/low states transfer between chips? Thanks.
dkinzer
Site Admin
Posts: 3120
Joined: 03 September 2005, 13:53 PM
Location: Portland, OR

Post by dkinzer »

liam.zbasic wrote:Will DAC to ADC from separate chips work? And for the matter, will high/low states transfer between chips?
Yes to both provided that they share a common ground connection.

Rather than using the PutDAC function you may be better served by using a PWM output on the slave device. I say this because, once set up, the PWM runs continuously with no further attention needed by the processor. In contrast, PutDAC needs to be called regularly to reduce "droop" on the generated analog level.

Another possibility is to use SPI or I2C and set up the device as a slave. If you already have other SPI or I2C devices the additional pin count required is minimal.
- Don Kinzer
liam.zbasic
Posts: 163
Joined: 24 March 2008, 23:33 PM
Location: Southern California (Blue)

Post by liam.zbasic »

Yes, all devices will share the same ground connection. So I plan to use an ADC pin from the master to read an "analog" voltage from the slave. If the slave outputs a PWM signal, will the master ADC interpret that as an "analog" signal? I suppose the PWM frequency will need to be very high, otherwise the master will "see" a square signal.
dkinzer
Site Admin
Posts: 3120
Joined: 03 September 2005, 13:53 PM
Location: Portland, OR

Post by dkinzer »

liam.zbasic wrote:If the slave outputs a PWM signal, will the master ADC interpret that as an "analog" signal?
Only if you add an RC filter to "average" the PWM signal. The cutoff frequency of the RC filter needs to be perhaps an order of magnitude lower than the PWM frequency. Of course, the lower the cutoff frequency of the filter, the slower the filtered voltage will respond to changes in the PWM duty cycle.

The cutoff frequency of a simple low pass R-C filter is 1/(2*pi*R*C) where R is in ohms and C is in Farads. A 1K resistor and a 100nF capacitor will yield a cutoff frequency of about 1600Hz.
- Don Kinzer
liam.zbasic
Posts: 163
Joined: 24 March 2008, 23:33 PM
Location: Southern California (Blue)

Post by liam.zbasic »

dbkinzer - appreciate your comments. I'll set the PWM frequency to 20khz and I'll do a 2nd order low-pass filter with a cutoff at 500hz.

Is it correct to say that the "averaged" output voltage from the slave will be 16bit resolution? When passed to the master ADC, the reading will be knocked back down to 10bit (which is adequate for my application). If I want to retain 16bit resolution, SPI or I2C is better, but at the cost of speed, more code and more pin connections.

Separate question, I'm having a tough time finding an ultrasonic range finder with a separate burst frequency so as to not interfere with my standard ~40khz device. Any links?
dkinzer
Site Admin
Posts: 3120
Joined: 03 September 2005, 13:53 PM
Location: Portland, OR

Post by dkinzer »

liam.zbasic wrote:I'll do a 2nd order low-pass filter with a cutoff at 500hz.
I suspect that a simple RC filter would suffice, e.g. 220nF/1.5K.
liam.zbasic wrote:Is it correct to say that the "averaged" output voltage from the slave will be 16bit resolution?
Yes, assuming 16-bit PWM is used.
- Don Kinzer
liam.zbasic
Posts: 163
Joined: 24 March 2008, 23:33 PM
Location: Southern California (Blue)

Post by liam.zbasic »

I'm perplexed. My 328n device seems to either skip the PulseOut echo to my ultrasonic range sensor or perhaps the PulseIn statement is not waiting for the return echo. However, if I un-comment the debug.print statement, the code works fine. Is the native device too fast?

Code: Select all

option base 1
option TargetDevice zx328n

public const ping_pin   as byte   = 14             ' Ping sonar sensor output (zx328n)
public const ping_level as byte   = 1
public const sos        as single = 13397.2441     ' Speed of sound (in/sec)
public const runtime    as single = 10.0

sub main()

   dim hour as byte, minute as byte, sec as single
   dim t as single, told as single, dt as single
   dim ping_tau as single, ping_dx as single
 
   t    = 0.0
   dt   = 0.0
   told = 0.0
  
   while t < runtime
   
      call GetTime&#40;hour, minute, sec&#41;
	  
         t    = CSng&#40;minute&#41;*60.0 + sec
         dt   = t - told
         told = t
 	  
	  
	  ' PROCESS PING SENSOR
	  '----------------------------------
	  call pulseout&#40;ping_pin, 9, 1&#41;        ' A single pulse is 1.085 us; want 10us for ping sensor	  
	  call PulseIn&#40;ping_pin, ping_level, ping_tau&#41;
	  
	  ping_dx  = ping_tau * sos / 2.0      ' Distance divided by two for one-way distance 
	       
	  'debug.print  "time = " & t & "   " & "one-way = " & ping_dx & " dt= " & dt
   wend
   
end sub
dkinzer
Site Admin
Posts: 3120
Joined: 03 September 2005, 13:53 PM
Location: Portland, OR

Post by dkinzer »

liam.zbasic wrote:Is the native device too fast?
Perhaps the sonar device has a minimum cycle time or has a recovery time requirement. The datasheet for the device may give some guidance in that regard.

I suspect that it is not the Debug.Print, per se, that is allowing it to work but the delay introduced by it. You could test this hypothesis by replacing the Debug.Print with a Sleep() call that produces the equivalent delay (number-of-characters * 10 / baud-rate). If that works, you could reduce that delay gradually until it stops working.
- Don Kinzer
liam.zbasic
Posts: 163
Joined: 24 March 2008, 23:33 PM
Location: Southern California (Blue)

Post by liam.zbasic »

Yes, I figured the ultrasonic sensor worked because the debug.print statement added a small delay. And yes, last night I tried the "sleep" command and it worked. My confusion is that I understood PulseIn would provide the necessary delay because it make everything wait until it "returns". Not sure what's happening here.
dkinzer
Site Admin
Posts: 3120
Joined: 03 September 2005, 13:53 PM
Location: Portland, OR

Post by dkinzer »

liam.zbasic wrote:I understood PulseIn would provide the necessary delay because it make everything wait until it "returns".
PulseIn() only guarantees a wait until the pulse is returned. It doesn't guarantee an additional delay before asking for the next pulse to be sent. I don't know if your ultrasonic device requires such a delay but the results suggest that it does. What is the make/model of the U/S device?
- Don Kinzer
liam.zbasic
Posts: 163
Joined: 24 March 2008, 23:33 PM
Location: Southern California (Blue)

Post by liam.zbasic »

It's the parallax Ping distance sensor:

http://www.parallax.com/dl/docs/prod/ac ... G-v1.3.pdf

To bring you up to date, I'm setting up the zx328 device as a slave dedicated to measuring distance, and I'm considering using I2C for communication with the master zx40n device. If I include a "sleep" delay in the slave to make the ping sensor work, will that force the delay on the master?
dkinzer
Site Admin
Posts: 3120
Joined: 03 September 2005, 13:53 PM
Location: Portland, OR

Post by dkinzer »

liam.zbasic wrote:It's the parallax Ping distance sensor:
According to the datasheet, it requires a delay between measurements (see attachment). The required 200uS delay comprises about 3000 CPU cycles for a device running at 14.7MHz. I doubt that that requirement is met in your code without an explicit delay call after the measurement.
liam.zbasic wrote:If I include a "sleep" delay in the slave to make the ping sensor work, will that force the delay on the master?
The TWI slave mode is interrupt driven so the slave should respond as long as you don't make calls that disable interrupts for long periods of time. In this respect, it is probably not a good idea to use PulseIn() since it does disable interrupts until the trailing edge of the pulse is seen.

PulseOut() also disables interrupts but the duration is short enough that it may not matter. You could use PutPin() in combination with Pause() to generate the pulse to the PING sensor.

Code: Select all

Call PutPin&#40;ping_pin, 1&#41;
Call Pause&#40;1&#41;  ' delays about 4uS
Call PutPin&#40;ping_pin, 0&#41;
Attachments
ping.jpg
ping.jpg (29.05 KiB) Viewed 3932 times
- Don Kinzer
liam.zbasic
Posts: 163
Joined: 24 March 2008, 23:33 PM
Location: Southern California (Blue)

Post by liam.zbasic »

Now I'm sand-trapped. I added a "Pause" delay for 0.02sec to account for a max possible delay of 18.5 msec (per spec) associated with longest measurable distance. The code runs fine and calculates the correct distance. However, when I add PWM statements to output voltage proportional to distance, the PULSEIN command fails - the returned pulse width is always zero. I set the "Pause" delay to 1.0sec, but no luck. Seems there is a Timer conflict between PWM and PULSEIN. I'm using a ZX-328n device. I tried both PWM channels and made sure to include OpenPWM at beginning of program. Could it by that PWM and PULSEIN will not work together in the same program and 328n device? Thank you.
Post Reply