PDA

View Full Version : Multiple Pulsin Measurements

FinchPJ
- 28th October 2011, 20:24
Does anyone have any experience of multiple PULSIN measurements - ie simultaneous on more than one pin - obviously would need to sample for a full sample period - 65535 cycles to be sure no pulses received on any other pin even if received on one pin. Also would need to handle a partially measured (ie ongoing beyond the sample period) pulse. So I am thinking of a full port pulse sample, result to an word array (Period[7]), where Period[n] = 0 if no pulse, 65535 if an incomplete pulse and a result otherwise. I am planning to write if no one has done already - any interest?

FinchPJ
- 31st October 2011, 18:49
OK - I have written a PicBasic routine to do mPULSIN - a bit slow as you would expect, but works

for i = 0 to 7 : Period[i] = 0 : next
pCount = 65535 ' PULSIN_MAX
cycle0: j = mPort & k 'Port AND Mask
for i = 0 to 7
if (j & dcd i) = dcd i then 'Bit i set - Pulse found
Period[i] = Period[i] + 1
else 'Pulse ended or no pulse
k = k & (~dcd i) 'Clear i'th bit in mask
endif
endif
next
if k = 0 then return
pCount = pCount - 1
if pCount <> 0 then cycle0
return

I have also written in assembler but need to test before posting....
Peter

FinchPJ
- 31st October 2011, 23:36
OK - here it is in Assembler - disappointingly not that much faster!

'**** mPULSIN defines ***
Period var word[7]
mPort var PortB
i var byte
j var byte
k var byte
pCount var word
sample var byte
CALL mPULSIN
END

asm
_mPULSIN: CLRF _Period ;Period[0] = 0
CLRF _Period + 1
CLRF _Period + 2 ;Period[1] = 0
CLRF _Period + 3
CLRF _Period + 4 ;Period[2] = 0
CLRF _Period + 5
CLRF _Period + 6 ;Period[3] = 0
CLRF _Period + 7
CLRF _Period + 8 ;Period[4] = 0
CLRF _Period + 9
CLRF _Period + 10 ;Period[5] = 0
CLRF _Period + 11
CLRF _Period + 12 ;Period[6] = 0
CLRF _Period + 13
CLRF _Period + 14 ;Period[7] = 0
CLRF _Period + 15

MOVLW 0xFF
MOVWF _pCount
MOVLW 0x0F
MOVWF _pCount + 1 ;pCount = \$FFF = 4095
CLRF _sample ;clear sample flag

cycle: MOVF _mPort, W ;Sample the Port
ANDWF _k, W
MOVWF _j ;j = Port AND Mask

B0: BTFSS _j,0 ;Bit set? Pulse high
GOTO B0Clear
BSF _sample,0 ;flag that now sampling
INCFSZ _Period ;Period[0] = Period[0] + 1
GOTO B1
INCF _Period + 1
GOTO B1
B0Clear: BTFSS _sample,0 ;Pulse low - already sampling?
GOTO B1
BCF _k,0 ;Clear Bit in Mask
B1: BTFSS _j,1 ;Bit set? Pulse high
GOTO B1Clear
BSF _sample,1 ;flag that now sampling
INCFSZ _Period + 2 ;Period[1] = Period[1] + 1
GOTO B2
INCF _Period + 3
GOTO B2
B1Clear: BTFSS _sample,1 ;Pulse low - already sampling?
GOTO B2
BCF _k,1 ;Clear Bit in Mask
B2: BTFSS _j,2 ;Bit set? Pulse high
GOTO B2Clear
BSF _sample,2 ;flag that now sampling
INCFSZ _Period + 4 ;Period[2] = Period[2] + 1
GOTO B3
INCF _Period + 5
GOTO B3
B2Clear: BTFSS _sample,2 ;Pulse low - already sampling?
GOTO B3
BCF _k,2 ;Clear Bit in Mask

B3: BTFSS _j,3 ;Bit set? Pulse high
GOTO B3Clear
BSF _sample,3 ;flag that now sampling
INCFSZ _Period + 6 ;Period[3] = Period[3] + 1
GOTO B4
INCF _Period + 7
GOTO B4
B3Clear: BTFSS _sample,3 ;Pulse low - already sampling?
GOTO B4
BCF _k,3 ;Clear Bit in Mask

B4: BTFSS _j,4 ;Bit set? Pulse high
GOTO B4Clear
BSF _sample,4 ;flag that now sampling
INCFSZ _Period + 8 ;Period[4] = Period[4] + 1
GOTO B5
INCF _Period + 9
GOTO B5
B4Clear: BTFSS _sample,4 ;Pulse low - already sampling?
GOTO B5
BCF _k,4 ;Clear Bit in Mask
B5: BTFSS _j,5 ;Bit set? Pulse high
GOTO B5Clear
BSF _sample,5 ;flag that now sampling
INCFSZ _Period + 10 ;Period[5] = Period[5] + 1
GOTO B6
INCF _Period + 11
GOTO B6
B5Clear: BTFSS _sample,5 ;Pulse low - already sampling?
GOTO B6
BCF _k,5 ;Clear Bit in Mask
B6: BTFSS _j,6 ;Bit set? Pulse high
GOTO B6Clear
BSF _sample,6 ;flag that now sampling
INCFSZ _Period + 12 ;Period[6] = Period[6] + 1
GOTO B7
INCF _Period + 13
GOTO B7
B6Clear: BTFSS _sample,6 ;Pulse low - already sampling?
GOTO B7
BCF _k,6 ;Clear Bit in Mask
B7: BTFSS _j,7 ;Bit set? Pulse high
GOTO B7Clear
BSF _sample,7 ;flag that now sampling
INCFSZ _Period + 14 ;Period[7] = Period[7] + 1
GOTO Next
INCF _Period + 15
GOTO Next
B7Clear: BTFSS _sample,7 ;Pulse low - already sampling?
GOTO Next
BCF _k,7 ;Clear Bit in Mask
Next: MOVF _k, F ;Is Mask = 0?
BTFSC STATUS,Z ;Branch on No Zero
RETURN ;Finished all samples
DECFSZ _pCount
GOTO cycle
DECFSZ _pCount + 1
GOTO cycle
RETURN ;pCount reached 0 - Timeout
ENDASM

Charles Linquis
- 1st November 2011, 03:42
Can't you use the gated timers or interrupts to do what you want?

rmteo
- 1st November 2011, 04:07
Can't you use the gated timers or interrupts to do what you want?
That would be too easy. :stupid:

FinchPJ
- 1st November 2011, 11:52
I need to make 8 simultaneous (relatively) measurements of pulsewidth on 8 different input pins - is there a PIC that could handle this with timers or interrrupts?

cncmachineguy
- 1st November 2011, 13:57
Can we get just a little more info about the pulses? for instance are you trying for a Logic storage type thing or reading R/C Rx pulses. Both need to have 8 bits read, but the Logic storage needs to get the states and go back watching while the Rx has at least 2mS before the next pulses may show up. Do you have an anticipated max/min pulse width?

cncmachineguy
- 1st November 2011, 14:00
Also can you expand on the first was "slow"? Do you mean it was to slow to react to the pulses? were they accurate but offset? How much percision and resolution do you need?

FinchPJ
- 1st November 2011, 15:11
OK - the scenario is measuring multiple (8) pulses arising from eight simple 12F675 circuits outputing pulses - I can change that to whatever I want, currently 1mSec pulse every 50 mSec, but the 12F675 has an LC circuit driving its oscillator so the pulse width is altered by the LC circuit (and any adjacent metal/tuned circuit etc.

When I say the Picbasic routine was slow I mean the precision or resolution - using PB PULSIN gives a resolution of 40/OSC uSec - ie. 0.833 uSec at 48 MHz - so a 1000 uSec pulse gives a Pulsin answer of around 1224 - using my PicBasic routine I get a measurement (ie number if cycles of sampling) of only around 300 (ie 3 uSec resolution) and using assembler a similar result, unless I only sample one bit in which case it rises to arounf 800 (ie 1.1 uSec resolution). So a PULSIN resolution of 40/OSC is pretty impressive!

Interestingly, a sequence of several PULSIN commands on each successive pin gives a much better (more precise) result - maybe I should never have started this idea and stuck to dirty successive PULSINs!

cncmachineguy
- 1st November 2011, 15:40
Sorry to be dense but here goes -
so for a 1000 uS pulse you get as a result-
1224 for pulsin
1100 for just 1 bit sampled?

You can see I don't think I have this right. If I do, they are all crap IMHO. best being off by 10%!

I am crafting up a possible solution, but these numbers are messing with me.

On to more fun stuff. So you have around 50 mS to wait for the next series of pulses correct? If so, what about this:
when the first pulse starts (or all of them at once, whatever) start a timer.
XOR the 8 bits (faster if they are all on the same port)
keep checking until one of more change.
when they do, grab the counter value and store it with the port value.
When you have done this 8 times, you will have the counter differences for each bit.

Now go process the information to determine how long each pulse lasted. Plenty of time left to get back and wait for the next series of 8 pulses. Now if you wanted to use interrupts, have all 8 on IOC pins, then when the ISR fires, grab the counter and states there. This will take a feww cycles longer though.

FinchPJ
- 1st November 2011, 16:06
Thanks for your advice - I will think about your "Fun stuff" - actually the actual timings/test results are the opposite of what you understood from my description:
so for a 1000 uS pulse you get as a result-
1224 for pulsin - correct (=~ 1000*48/40)
1300 for your routine - No I get an answer of around 300
1100 for just 1 bit sampled? - No I get an answer of around 800

Whilst using interrrupts etc as you suggest may be a purist answer, I think 8 successive PULSINs are going to be much easier - I cant guarantee the pulses will arrive synchronously, but it is the precision I am worried about, not the sample time it takes (hence the 50 mSec pause between pulses)

cncmachineguy
- 1st November 2011, 17:02
I dont know about the "purist" part, and IMHO anything needing better then 5uS accuracy is not well suited for interrupts.
Now I understand your numbers, 300 is really 300 iterations of the loop. so its as accurate as the loop takes (given 1000uS pulse, 3.333uS loop time)

I propose you can achieve 1uS with my suggestion, maybe better. But if you can get the XOR to be 2-3 instructions, 2 jumps = 4more (to the grab time and back), then a couple of instructions to save the timer count and port states. You will be right around 12 instructions I think. So not much better then the pulsein, but nicer in the respect you can get all 8 at once.

I am assuming you are using this to check the speed of the 8 uP's. something else to consider :
If they are sending the pulses every 50 mS, you could measure the low pluse (50mS long) instead of the high pulse. This will give you a much bigger window to check the the duration against. 1% is 500 uS in this case. so being off by 3 or 4 uS would then be peanuts.

FinchPJ
- 1st November 2011, 17:29
Thanks so much for your helpful thoughts - I will go away and work at your suggestion - I agree interrupts may not be accurate enough - you are quite correct I am monitoring the 8 baby PICs' oscillator speeds and I agree a longer pulse is easier (more accurate) to measure.
Peter

FinchPJ
- 4th November 2011, 17:19
I decided to try and make the assembler less ugly first by using indirect addressing to access the Period[8] array but it is no faster than my laborious method and this one will only run on an 18F4550 due to the use of the helpful POSTINC0 operator representing INDF(0) with a post Increment:

_xPULSIN MOVLW 0xFF
MOVWF _pCount
MOVLW 0x0F
MOVWF _pCount + 1 ;pCount = \$FFF = 4095
CLRF _sample ;clear sample flag

cycleX MOVF _mPort, W ;Sample the Port
ANDWF _k, W
MOVWF _j ;j = Port AND Mask
MOVLW High(_Period) ;Set up FSR to point to Period[0]
MOVWF FSR0H
MOVLW Low(_Period)
MOVWF FSR0L
MOVLW 1
MOVWF _i ;Bit Marker = 00000001
CheckJ RRCF _j
BTFSS STATUS,C ;Bit i Set
GOTO BCLR
INCFSZ POSTINC0 ;Yes - Period[i] = Period[i]+1
GOTO NoRoll
INFSNZ POSTINC0 ;=Inc and always skip - Period.Hi never Zero
NoRoll MOVF POSTINC0,F ;=NOP except inc FSR
MOVF _i,W
IORWF _sample,F ;Now sampling bit i
Nexti RLCF _i ;i = i<<1
BTFSS STATUS,C ;Carry set = 8 rotations?
GOTO CheckJ ;No - Loop round
MOVF _k,F ;Is Mask = 0?
BTFSC STATUS,Z
RETURN ;Yes - Finished all samples
DecCount DECFSZ _pCount ;No - Update counter
GOTO cycleX
DECFSZ _pCount + 1
GOTO cycleX
RETURN ;Countdown = 0 - Timeout?
BCLR MOVF POSTINC0,F ;=NOP except inc FSR
MOVF POSTINC0,F ;=NOP except inc FSR
MOVF _i,W
ANDWF _sample,W ;Pulse low - already sampling?
BTFSC STATUS,Z
GOTO Nexti ;No - do nothing
MOVF _i,W
XORWF _k,F ;Yes - Clear Bit in Mask
GOTO Nexti

;-----------------------------------------------------------------------------
_PeriodZ MOVLW High(_Period) ;Set Period[0 to 7] = 0
MOVWF FSR0H
MOVLW Low(_Period)
MOVWF FSR0L
CLRF _i ; i = 0 (counter)
clr CLRF POSTINC0 ;CLRF INDF0 then inc FSR0
INCF _i
BTFSS _i,4 ; i.4 set = 16
GOTO clr
RETURN