PDA

View Full Version : Synchronous pulses



AndrewC
- 13th October 2009, 22:47
.. not sure if that is the correct title but want I want to do is output a pulse in parallel on three different pins. The pulses will be of different lengths (1msec down to a few usecs) and the leading edges need to be aligned.

I can think of one way of doing it - put all 3 o/p's high together then pause incrementally as I bring them back down one at a time - but I was wondering if there was a more elegant way of doing it ?

Thanks,

Andrew

Jerson
- 14th October 2009, 03:07
Are you thinking of a software PWM? Quite easy to do really.

http://darreltaylor.com/DT_INTS-14/SPWM.html

AndrewC
- 14th October 2009, 08:01
Are you thinking of a software PWM? Quite easy to do really.

http://darreltaylor.com/DT_INTS-14/SPWM.html

No, not a software PWM.
Actually for controlling some photographic strobes.
Three command lines, need to fire simultaneously but then shut off after different times and wait for the next trigger.

Andrew

mackrackit
- 14th October 2009, 09:13
Add a little to your idea... Assuming the pins in question are on the same port...


TRIS? = %00000000
X VAR BYTE
Y VAR BYTE
Z VAR BYTE

STROBE:
PORT? = %00000111
PAUSE X ' Or use PAUSEUS
PORT? = %00000011
PAUSE Y
PORT? = %00000001
PAUSE Z
PORT? = %00000000
RETURN

Acetronics2
- 14th October 2009, 09:34
Hi, Andew

It's in French ... Yes.

But just close to what you look for ...

http://mathieu.agopian.free.fr/prog_pic/servobis/

http://mathieu.agopian.free.fr/prog_pic/servoter/

Alain

AndrewC
- 14th October 2009, 09:35
Reply to Dave:

Yup, that's what described.

The issue is that the three outputs will not always be ordered longest to shortest from bit 0 to bit 2 (or bit 2 to 0 as you ordered them). Not difficult to get around - just need to sort the pulse lengths, calculate the incremental time between sequential trailing edges and use a bunch of IF statements to pull them back down in the right order.

But woudn't it be nice if there was single command that could output parallel pulses :)

Andrew

mackrackit
- 14th October 2009, 09:42
How are you going to input the parameters to the PIC?

AndrewC
- 14th October 2009, 09:53
How are you going to input the parameters to the PIC?

That bit is easy :)

In this kind of application I probably only need about a dozen discrete pulse lengths. I'll probably store them in an array and select the array member by scrolling through it with single button per output. Depending on the PIC I'll use I might have an "up" and "down" button. Each flash needs a fire and quench signal, so that is 6 pins, plus the buttons takes me up to 9 (or 12) plus a serial output for an LCD plus a synch signal from the camera.

Andrew

AndrewC
- 14th October 2009, 10:01
Hi, Andew

It's in French ... Yes.

But just close to what you look for ...

http://mathieu.agopian.free.fr/prog_pic/servobis/

http://mathieu.agopian.free.fr/prog_pic/servoter/

Alain

Hi alain,

Yes, seems to be pretty much what I'm describing. Thanks for the link.

Andrew

Mike, K8LH
- 16th October 2009, 21:50
Hi Andrew,

Would you like me to describe one method for producing up to 8 precisely timed synchronous pulses (on a single port), each pulse with a pulse width value of from 0 (off) to 1023 usecs with 1 usec pulse width resolution? If so, please let me know and I'd be happy to explain how the following code snippets work. I apologize for the C code.

Kind regards, Mike






unsigned int pulse[] = { 120, // pulse 0 (RB0), 120-usecs
44, // pulse 1 (RB1), 44-usecs
45, // pulse 2 (RB2), 45-usecs
1001, // pulse 3 (RB3), 1001-usecs
0, // pulse 4 (RB4), off/not used
0, // pulse 5 (RB5), off/not used
0, // pulse 6 (RB6), off/not used
0 }; // pulse 7 (RB7), off/not used

unsigned char toggle[1024] @0x400 // 1024 element (interval) toggle array




//
// 1024 interval output routine (BoostC compiles the following
// do-while code into a 5-cycle loop which is perfect for 1-usec
// intervals with a 20-MHz clock).
//
void Output()
{ fsr0 = 0x400; // interval = 0
do // do
{ latb ^= postinc0; // { latb ^= toggle[interval++]
} while(fsr0h.3 == 0); // } while(interval < 1024)
}

//
// build new toggle array from the pulse array before calling Output()
//
void PrepArray()
{ for(i = 0; i < 1024; i++) //
toggle[i] = 0; // clear the array
toggle[pulse[0]] |= 1; // insert RB0 output toggle bit
toggle[pulse[1]] |= 2; // insert RB1 output toggle bit
toggle[pulse[2]] |= 4; // insert RB2 output toggle bit
toggle[pulse[3]] |= 8; // insert RB3 output toggle bit
toggle[pulse[4]] |= 16; // insert RB4 output toggle bit
toggle[pulse[5]] |= 32; // insert RB5 output toggle bit
toggle[pulse[6]] |= 64; // insert RB6 output toggle bit
toggle[pulse[7]] |= 128; // insert RB7 output toggle bit
toggle[0] ^= 0xFF; // fix toggle[0] element
}

AndrewC
- 16th October 2009, 22:26
Hi Mike,

sounds interesting - explain away :)

Andrew

Mike, K8LH
- 17th October 2009, 00:53
Hi Andrew,

The disadvantage of this particular method is that you need a PIC with lots of RAM, something like an 18F2620, for the 1024 byte toggle array. If this is a one-off project then perhaps that may not be a big deal.

The PrepArray() routine builds the following (abbreviated) toggle[] array from the pulse[] array values and the Output() routine uses those values to update LATB as shown below;



interval ^ LATB
0000-usecs toggle[ 0] = 0b00001111 0b00001111 RB3..RB0 toggled on
0001-usecs toggle[ 1] = 0b00000000 0b00001111
....
0043-usecs toggle[ 43] = 0b00000000 0b00001111
0044-usecs toggle[ 44] = 0b00000010 0b00001101 RB1 toggled off
0045-usecs toggle[ 45] = 0b00000100 0b00001001 RB2 toggled off
0046-usecs toggle[ 46] = 0b00000000 0b00001001
....
0119-usecs toggle[ 119] = 0b00000000 0b00001001
0120-usecs toggle[ 120] = 0b00000001 0b00001000 RB0 toggled off
0121-usecs toggle[ 121] = 0b00000000 0b00001000
....
1000-usecs toggle[1000] = 0b00000000 0b00001000
1001-usecs toggle[1001] = 0b00001000 0b00000000 RB3 toggled off
....

http://www.picbasic.co.uk/forum/attachment.php?attachmentid=3737&d=1255736963

The advantage of using a "toggle" data array and XOR'ing the values with LATB over using an "output" data array and simply writing the values to LATB is that the "toggle" array only requires inserting eight "toggle" bits into the array. An "output" data array would require inserting many many "output" bits into the array.

The Do-While loop in the Output() routine compiles to the following 5-cycle instruction sequence (by the BoostC compiler) for perfect 1-usec intervals (with a 20-MHz clock);



loop:
movf _postinc0,W ;
xorwf _latb,F ;
btfss _fsr0h,3 ;
bra loop ;


In your program you would edit the pulse array values for the outputs and then call the PrepArray() routine to build the toggle array. Then I suspect you would wait for some "trigger" event before calling the Output() routine.

Any of this make sense Sir? I'm rather pressed for time and that tends to make my rushed explanations rather useless to most people. Sorry...

Regards, Mike

AndrewC
- 17th October 2009, 08:20
More or less makes sense.
As I'm only juggling three outputs, I think I'll just sort the outputs into increasing time, calculate the incremental time between trailing edges, put them all on together and then pull them back down sequentially with PAUSEUS delays.

Thanks for taking the time to answer :)

Andrew

Mike, K8LH
- 17th October 2009, 12:32
You're welcome.

Good luck on your project.

Regards, Mike

Jerson
- 17th October 2009, 14:00
This last post made me to put on my thinking cap ;) I do this stuff within an ISR usually, but your case doesn't need it.

How about something like this. BEWARE : untested code


Out1 var PORTB.0
Out2 var PORTB.1
Out3 var PORTB.2
AllOn con %00000111 ' all three outputs on

Delay1 var word ' turn off delay for output1
Delay2 var word ' and 2
Delay3 var word ' surely this has to be for 3

RunDelay var word ' this is the running timer

' set all outputs on together
TRISB = 0
Delay1 = 1000 ' in units of PAUSE time
Delay2 = 2000
Delay3 = 3000
Loop:
PORTB = AllOn

for RunDelay = 0 to 65535 ' or whatever is the maximum you want
' this would be your cycle / repeat time
if RunDelay > Delay1 then
Out1 = 0
endif

if RunDelay > Delay2 then
Out2 = 0
endif

if RunDelay > Delay3 then
Out3 = 0
endif

pauseus 10 ' this is the resolution of your delays
next
goto Loop

Mike, K8LH
- 17th October 2009, 16:00
Hi Jerson,

I agree that ISR code isn't necessary or even desirable in this case because of the high resolution required and the ISR context save/restore 'overhead'.

Andrew mentioned in his first post that the pulse width range could be several microseconds up to about one millisecond.

I believe the pulse width resolution for your example would be the loop code 'overhead' plus the 16-bit compare code 'overhead' plus the delay. The 16-bit compare code 'overhead' may well be the biggest limiting factor affecting resolution and the delay may not be necessary. Have you checked to see how many cycles are used for 1 loop cycle in your example Sir?

Regards, Mike

Mike, K8LH
- 18th October 2009, 16:32
Hey Andrew,

Once I figure out how to force an address for the toggle array in Swordfish BASIC I suspect my method might look something like this BASIC example, which I hope makes more sense than my previous pseudo C example.

Kind regards, Mike



Dim Tgl(1024) As Byte ' ??? force to $400..$7FF ???
Dim Pulse(3) As Word
Dim LastElement As FSR0H.booleans(3)
'
Pulse(0) = 3 ' RB0 pulse, 0..1023 usecs
Pulse(1) = 11 ' RB1 pulse, 0..1023 usecs
Pulse(2) = 12 ' RB2 pulse, 0..1023 usecs
'
' clear the 1024 element toggle array
'
FSR0 = AddressOf(Tgl) ' indirect for Tgl(0)
Repeat ' clear toggle array
POSTINC0 = 0 ' clear 0x400..0x7FF
Until LastElement '
'
' insert 3 output toggle bits into our 1024 interval toggle array
'
Tgl(Pulse(0)) = Tgl(Pulse(0)) Or 1 ' insert RB0 toggle bit
Tgl(Pulse(1)) = Tgl(Pulse(1)) Or 2 ' insert RB1 toggle bit
Tgl(Pulse(2)) = Tgl(Pulse(2)) Or 4 ' insert RB2 toggle bit
Tgl(0) = Tgl(0) Xor $FF ' prep Tgl(0) element
'
' implement a button press or some other trigger before falling into
' the output routine (1024 1-usec intervals with 20-MHz clock)
'
FSR0 = AddressOf(Tgl) ' Tgl(0..1023), 0x400..0x7FF
Repeat ' toggle outputs from toggle array
LATB = LATB Xor POSTINC0 ' at 1-usec (5 cycle) intervals
Until LastElement ' until end-of-array (0x800)