Is it possible to read in PWM input?

Hi, I’m new to this and was wondering if it is possible for the BBII with Atom Pro to read in a PWM signal? If yes, how would I go about doing it? Anyone help?

Hi again, I have found that pulsin command will read in PWM signal and I am able to do it. However, I also read from other posts that it will not be good to use pulsin to read multiple PWM input channels. I found the code on pastebin.com/9ZYb6gST and browsed through it. I wish to adapt the assembly code to read in three PWM input channels concurrently. However, I do not really understand the asm code and was wondering if anyone can tell me what I need to modify to do just that?

Testing out at the moment, don’t require much functionality. Just require the BBII to continuously read from 3 input pins (say P0 to P2) and print out the PWM signals. Any advice will be much appreciated. Thank you in advance.

Hi rev,

I wrote that assembly code awhile ago. This worked fine for some RC receivers but not all. The code assumed that only PWM signal would be active at a time. If they overlapped the code would rob the channel(s) that overlapped… So when you say concurrently, you would need to know if your signals overlap or not. At one point I was going to try versions that relaxed this and started by writing some basic code that gives the outline of what the new assembly language code should do, but never completed and tested it. The basic code looked like:

[code]
;=============================================================================
; this is just the outline of a function. Should convert to assembly language.
;==============================================================================
locknut var word ; how many times we went through the loop
bMask var byte ; Our mask of the bits we are still interested in
bIOVal var byte ; The IO port value (masked)
bIOValPrev var byte ; The previous IO port value (masked)
bIODif var byte ; what changed - What IO bits were turned off

abIOStates var byte(15) ; what state we were at
awIOTimes var word(15) ; Value of the loop counter.
cSaveStates var byte ; index into our saved array.
;=============================================================================
; this is just the outline of a function. Should convert to assembly language.
;==============================================================================
MPulseinV3:
; 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…

bMask = 0x7f		; what we are still looking for...

; first wait until all of the IOs are low 
while (PDR5 & bMask )
    ; 
wend 

; setup timerW
TCRW = 0x30	; setup for clock/8
TMRW = 0x80	; make sure it is running
TCNT = 0	;

; initialize for our main loop
cSaveStates = 0		; no saved states
bIOValPrev = 0x0	; no bits were on.

; main loop - to be used as actual values all code paths through this loop would need
; to have a consistent timings...
while bMask and (cSaveStates < 15)
	bIOVal = (PDR5 & bMask )				; get the masked value
	if bIOVal <> bIOValPrev then
		abIOStates(cSaveStates) = bIOVal	; save away the new value
		awIOTimes(cSaveStates) = TCNT		; save away the time from timerW
		cSaveStates = cSaveStates + 1		; increment how many states we have saved
		
		; Turn Off any bits in our mask that were on that are now off...
		bMask = bMask & ((!bIOValPrev) | bIOVal)
		bIOValPrev = bIOVal					; remember the previous value
	endif
	locknut = locknut + 1				; increment our loop counter
wend		

; Now to post process the data
for locknut = 1 to cSaveStates-1
	; Assumes that not two will end at the same time... Could handle this as well
	bIOVal = abIOStates(locknut-1) & !(abIOStates(locknut))  ; I think should give us a mask of the bits that turned off
	
	if bIOVal then
		
		; reuse bMask
		bMask = locknut-1
		while (bMask > 0) and (abIOStates(bMask) & bIOVal)	; loop back to find out when this bit was turned on.
			bMask = bMask - 1
		wend
		if !(abIOStates(bMask) & bIOVal) then
			bMask = bMask + 1
		endif
			
		; figure out which bit...
		bIOValPrev = 1
		while ((bIOVal & 0x1) = 0)
			bIOValPrev = bIOValPrev + 1
			bIOVal = bIOVal >> 1
		wend
		awPulsesIn(bIOValPrev) = (awIOTimes(locknut) - awIOTimes(bMask)) / 2 ; End - start /2 as clock is /8 
	endif
next	

; now print out masks and timers to see what is happening...
for locknut = 0 to cSaveStates-1
	serout s_out, i9600, [hex abIOStates(locknut), ":", dec awIOTimes(locknut), " "]
	if (locknut & 0x7) = 0x7 then
		serout s_out, i9600, [13]
	endif
next
serout s_out, i9600, [13]

return [/code]
The code assumed 7 inputs P0-P6. Can change by changing the mask (bMask=0x7f ). But not knowing your requirements it is hard to say.

You should probably start off trying using the pulsin command and see if it works well enough for you. Then if necessary the mpulsin code could be tried.

Kurt

Hi kurte, your reply has been very helpful. As suggested, I will try out the 3x pulsin commands first to see if it works out. If not, I will try out the code that you have attached. I will update this thread if I have any more questions. Thank you for your helpful reply!

Question related to pulsin:

It is mentioned in the manual that the default timeout is 65535 micro seconds for the pulsin command. How do I change it to say, 20000 micro seconds? There seems to be some contradiction between the manual and the forum. In the manual, it is said that the multiplier will change the default 65535 by multiplication. If that’s the case, how do i multiply 65535 by 0.305? Simply typing

pulsin , , , 0.305,

does not work as it requires an integer multiplier value. To further confuse things, I found out from a forum post that to change the default timeout value to 20000 microseconds, one can just input a value of 40000 as the multiplier. What’s going on here? :open_mouth:

The format of the pulsin command I believe is now.

PULSIN
Measures the duration of an input pulse on a specified pin.
Syntax
pulsin pin, direction, {TimeoutLabel, Timeout,} duration
pin is a variable or constant that specifies the pin to be used
for the input pulse. This pin will be placed into input mode
during the execution of this command and left in that state
after the command finishes.
direction is a variable or constant (0 or 1) that specifies the
pulse direction. If state = 0, the pulse must begin with a 1-to-0
transition. If state = 1 the pulse must begin with a 0-to-1
transition.
TimeoutLabel is an optional label that specifies the target if a
timeout occurs. If the command times out before a pulse is
detected, program execution will continue at this label. The
default timeout value is 65535 μs. If no TimeoutLabel is
specified, PULSIN will wait 65535 μs for a pulse to occur,
then program execution will continue with the next instruction.
Timeout is a variable or constant that specifies the number of
microseconds to wait before a timeout (failure) condition is
reached. The variable consists of 32 bits (and ranges in value
from 0-655350). Timeout is measured in 0.5 microsecond
intervals.
duration is a variable that stores the pulse duration in μs.
Make sure the variable is large enough to store the longest
expected pulse time (either 65535 μs or that set by
TimeoutMultiplier). If the variable is too small only the least
significant bits will be stored. If no pulse is detected within the
timeout value duration will be set to 0.

For those who are adventurous you can also use the Capture hardware of the AtomPro. There are 4 capture capable pins. FTIOA to FTIOD which are pins P9 to P12 on the 24/28 pin modules. On the 40 pin Pro module p8 to p15 are FTIO pins. All FTIO pins can be capture or compare match pins. Capture mode will grab the current TimerW/TimerZ value when the pin matches the specified capture state.

The procedure would be something like this:

  1. Set capture hardware to capture on rising edge.
  2. enable capture interrupt
  3. If a rising edge interrupt:
    a. read timer into temp(word sized var)
    b. change to falling edge interrupt
    c. exit interrupt
  4. if a falling edge interrupt
    a. read GRX register and subtract temp to get pulse length
    b. change back to a rising edge interrupt
    c. exit interrupt

Of course there is a little more to it. You need to specify how fast the timer is runnign and that will be your base time. You can read in pulses upto approx 32ms in length.