Hi again,
If it were me, I would start off with simple pulsin commands to get the 4 channels that you are interested in. When I talk about 2 cycles, what I mean is that the receiver sends out the servo pulses one after each other and then there is a pause and then it does this again. It does not depend on how many of the channels you are processing, you simply have to wait until the channel you are doing a pulsin on is low and then finally goes high and then low again. If you miss the start of it you have to wait for one complete cycle before you can try again. If you are doing a pulsin command, it will sit in this command until this happens. Here is an example coming off of the spektrum receiver:
http://i416.photobucket.com/albums/pp245/Kurts_Robots/Spectrumreceiver.png
Note, I should have captured one with multiple cycles, to show this better, but I now have it set up for PS2 testing… But you should notice that we have not even started the second pass in this complete trace so if you miss a signal you may need to wait awhile.
While the Spektrum type transmitter/receivers may use digital stuff, in the end it still generates RC servo pulses like the older analog ones… What would be nice is if they had a digital receiver, which you could simply interface to, through probably I2C or the like.
There are much better hardware experts up here, but my guess is the easiest hardware solution is with a processor, which would requires some code to be written for it.
It is great that we all have features or things that interest us and many of us try to share as much as we can. This allows all of us to to pick and choose where we want to spend our time.
As for the assembly code. This is my current test program for the receiver side. Note, it is not fully tested yet. It appeared to work with my default configuration of the first 7 pins. It would be nice now to reconfigure my bot with other pins, which free up some analog pins and don’t eat into the hardware serial port, etc…
[code];====================================================================
; DIY - Radio Receiver Test Program
;
; Currently this program assumes all 7 inputs are hooked up to P0-P6
; TBD - Make more general purpose, to allow different input pins.
; For P1-P7 change mask from 0x7f to 0xfe and make pulse_values word(8)
; For P8,10-15 change mask to 0xFD, PDR5 to PDR8, and pulse_values to word(8)
; BUGBUG - Need to check how PCR5 and PMR5 are used…
;----------------- Variables used in MPulsin function --------------------------
awPulsesIn var word(16)
wPulseError var word
wPulseMask var word
;----------------- Other variables --------------------------------------------
awPulsesPrev var word(16)
fPulseChanged var bit ; we had a channel change
fNoTransmitter var bit ; did we detect no transmitter…
fLostTransmitter var bit ; We lost contact with transmitter
i var byte
keypress var byte
pulse_slop con 2
;--------------------------------------------------------------------
; Init code
;====================================================================
;--------------------------- Init needed for MPulseIn -----------------
; Make sure all 7 pins are marked for input…
input p0
input p1
input p2
input p3
input p4
input p5
input p6
wPulseMask = 0x7f
;----------------------- other init used to show if transmitter was lost, etc -----------------------------------
; Specific to the DIY receiver code
fNoTransmitter = 0 ; assume we have a transmitter.
fLostTransmitter = 0
start:
gosub MPulseIn
; if we get a timeout and it is channel 0 then we now the receiver is not on...
if (wPulseError) then
; we detected no tranmitter at startup...
if fNoTransmitter = 0 then
serout s_out, i9600, "No Transmitter at power up(",hex wPulseError, ")", 13 ]
fNoTransmitter = 1
endif
elseif awPulsesIn(0) < 950
; On Bind we set channel 1 to about 800 normal is usually > 1000 so if under 950
; we probably lost our connection with the transmitter
if fLostTransmitter = 0 then
serout s_out, i9600, "Lost contact with transmitter", 13]
fLostTransmitter = 1
endif
else
; Ok we hamve a message so reset our error codes
fNoTransmitter = 0 ; assume we have a transmitter.
fLostTransmitter = 0
fPulseChanged = 0
for i = 0 to 6
if (awPulsesIn(i) > (awPulsesPrev(i)+pulse_slop)) or (awPulsesIn(i) < (awPulsesPrev(i)-pulse_slop)) then
fPulseChanged = 1
awPulsesPrev(i) = awPulsesIn(i)
endif
next
if fPulseChanged or wPulseError then
if awPulsesIn(6) < 1135 then
keypress = 0xff
else
keypress = (awPulsesIn(6)+15 - 1150) / 50 ; add in some slope as we could be slight
endif
serout s_out, i9600, [hex wPulseError, ":", hex keypress, ":" ]
for i = 0 to 6
serout s_out, i9600, [dec awPulsesIn(i)," "]
next
serout s_out, i9600,[13]
if keypress = 0xA then
low 12
else
input p12
endif
if keypress = 0xB then
low 13
else
input p13
endif
if keypress = 0xC then
low 14
else
input p14
endif
endif
endif
goto start
;==============================================================================
; Read in Multiple pulse widths in one pass. This function will not return
; until all of the pulses requested have been returned or a timeout happens.
; If there is a timeout it will return the mask of those items that were not
; returned. Zero if all were returned.
; Parameters/Variables Used.
; wPulseMask - Input: the word mask of which bits to retrieve
; awPulsesIn - Output: Word Array to receive the pulses from the different IO pins.
; the size of this array must be at least the highes pin number
; used in the mask+1 as we are zero biased.
; wPulseError - Output: if zero all were returned else the bits set as one
; were the ones that were not returned due to timing out.
;
; BUGBUG: it is assumed that all of the IO bits that are set to be retrieved are
; already configured as input IO pins. Could add code in to set them properly…
;
;-------------------------------------------------------------------
MPulseIn:
; Make sure all 7 IOs are set to input.
; PMR5 = 0 ; all IO lines are general IO
; PCR5 = 0 ; All are input (may want to leave bit 7 alone…
; Ok now lets transisiton to assembly language.
;
; bMask = 0x7f ; set a mask of which bits we are needing…
;
mov.w @WPULSEMASK, r1 ; R1 contains the mask of bits left to be retrieved.
; wait until none of the IO lines are high...
; while PDR5 & bMask
; ;
; wend
mov.l #250000,er2 ;(4) - setup timeout counter
_PI7_WAIT_FOR_ALL_LOW:
mov.b @PDR5:8, r0l ; R0l is the state of IO pins 0-7
mov.b @PDR8:8, r0h ; r0h is the state of IO pins 8-15
and.w r1, r0 ; see if any of the IO bits is still on...
beq _PI7_WAIT_FOR_NEXT_IO_TO_GO_HIGH:8 ; all zero go to wait for one to go high...
dec.l #1,er2 ;(2)
bne _PI7_WAIT_FOR_ALL_LOW:8 ; an IO pin is high and we have not timed out, keep looping until none are high
; We timed out waiting for all inputs to be low, so error out...
bra _P17_RETURN_STATUS:16 ; will return status that all timed out...
; while bMask
_PI7_WAIT_FOR_NEXT_IO_TO_GO_HIGH:
mov.l #250000,er2 ;(4) - setup timeout counter
_PI7_WAIT_FOR_NEXT_IO_TO_GO_HIGH2:
; we still need some 1 or more of the pulses…
; while (PDR5 & bMask) = 0 ; waiting for a pulse to go high.
mov.b @PDR5:8, r0l ;(4)
mov.b @PDR8:8, r0h ;(4)
and.w r1, r0 ;(*2) see if any of the IO bits is still on…
bne _P17_IO_WENT_HIGH:8 ;(*4) One went high so go process
dec.l #1,er2 ;(2)
bne _PI7_WAIT_FOR_NEXT_IO_TO_GO_HIGH2:8 ; (4) Not a timeout go try again.
; we timed out…
bra _P17_RETURN_STATUS:16 ; will return status of what timed out…
; wend
; iPin = ???; TBD: convert which bit is high to IO line number 0-6
; see which bit is on in the mask
_P17_IO_WENT_HIGH:
xor.w r2,r2 ;(*2)
mov.w #1, r4 ;(*4)
mov.l #AWPULSESIN,er3 ;(*6)
_P17_WHICH_BIT_LOOP:
shlr.w r0 ;(@2)
bcs _P17_WHICH_BIT_LOOP_DONE:8 ;(@4)
shll.w r4 ;(@2) - Set up our mask
inc.l #2, er3 ;(@2) - point to the next place in the array.
add.w #18,r2 ;(@4) - we do 18 clocks for each pass through this loop
bra _P17_WHICH_BIT_LOOP:8 ;(@4)
_P17_WHICH_BIT_LOOP_DONE:
; bMaskBit = 1 << iPin ; get the mask for which pin…
; ok R4 now has the mask for the bit that we are processing, clear it from our global flag.
xor.w r4, r1 ;(*2)
; = (22) - count so far of clocks after went high Maybe 20 or 24
; iPinLoopCnt = 0 ; This may be replaced with time calculations…
; while (PDR5 & bMaskBit)
; iPinLoopCnt = iPinLoopCnt + 1 ; how long until it goes low again
; wend
_P17_WAIT_FOR_IO_GO_BACK_LOW:
mov.b @PDR5:8, r0l ;(#4)
mov.b @PDR8:8, r0h ;(#4)
and.w r4, r0 ;(#2)
beq _P17_IO_WENT_BACK_LOW:8 ;(#4)
add.w #22,r2 ;(#4) - number of cyles per loop
bcc _P17_WAIT_FOR_IO_GO_BACK_LOW:8 ;(#4)
; we had a timeout return the status.
xor.w r4, r1 ; Turn back on the one we timed out on.
bra _P17_RETURN_STATUS:8 ;
_P17_IO_WENT_BACK_LOW:
; need to calculate the pulse width in ms… need to divide calculated clocks by 16
add.w #22,r2 ; (4) ; need to add the rest of the overhead(*-1 loop above) in…
shlr.w r2 ; (2)
shlr.w r2 ; (2)
shlr.w r2 ; (2)
shlr.w r2 ; (2) / 16 (for clock speed)
; aPulses(iPin) = iPinLoopCnt ; convert loop count to pulse width…
mov.w r2,@er3 ; Save away the value
; bMask = bMask & ~bMaskBit ; turn off waiting for this one…
or r1,r1 ; (2) see if we are done or not
; wend
bne _PI7_WAIT_FOR_NEXT_IO_TO_GO_HIGH:16 ;(6)our mask has not gone to zero so wait for the next one.
_P17_RETURN_STATUS:
mov.w r1,@WPULSEERROR
; finally transisition back to basic and return.
return [/code]
In this code the main work horse is MPulsin. You simply do a gosub of it to read in the servo pulses. You also need the variables that are in the section marked as used by MPulsin. Also currently you need to do some initialization code, in particular you need to set the mask wPulseMask to which IO pins you wish to use, by setting the cooresponding bit in the mask. I only support pins 0-15 and have only tested 0-7 so far. The rest of the code in the test program simply prints out the results to the terminal and also has some specific code for our DIY spektrum to try to detect when the transmitter signal has been lost.
I hope that helps…
As for my next steps, I am torn between updating this code to use the same TimerW that we setup in the phoenix code to make sure that interrupts does not screw up our timings, or to integrate in the XBee intot he transmitter/receiver and get the first version of this up and running…
Kurt