Triggered I/O

techElder

Well-known member
I'm looking for fresh input. I must be fried, because I can't think of a simple way to do this.

I have a hardware device (function unimportant) that has a TRIG_IN input, a TRIG_OUT output and a SELF_TRIG link (where the IN is directly connected to the OUT.)

So, the following subs work great for connecting one device to another and getting them to function in sequential order.

I call the TrigOut routine after the first one is finished functioning, and then the next one is waiting for that pulse in TrigIn and performs its function.

What I can't seem to figure out is the SELF_TRIG operation with a hardware link where the first device continuously performs its function by triggering itself. I know it can't be done with two separate subroutines, but seems like there should be a simple way.

There is no separate indicator that self trigger should occur. Its just a link from out back to in.

Help? (Hoping Hippy has some magic dust to throw on this problem! :D)

Code:
[color=Green]'---------------------------
[PLAIN]'------[ SUBROUTINES ]------[/PLAIN]
'---------------------------[/color]

[color=Black]TrigOut:
   [/color][color=Green]' create a timed high level on the TRIG_OUT pin
   [/color][color=Blue]pulsout [/color][color=Black]TRIG_OUT,ONESECOND
   [/color][color=Blue]return[/color]

[color=Black]TrigIn:
   [/color][color=Green]' wait for a timed high level on the TRIG_IN pin
   [/color][color=Blue]do until [/color][color=Black]TRIG_IN [/color][color=DarkCyan]= [/color][color=Black]TRUE : [/color][color=Blue]loop
   return[/color]
 

hippy

Technical Support
Staff member
Hoping Hippy has some magic dust to throw on this problem! :D
You might have to explain what you have / want in more detail. You "have a hardware device"; but where does the PICAXE fit into this scheme of things ?

A block diagram might help explain what you doing or trying to achieve.
 

Buzby

Senior Member
If the 'Trig_IN' pin is an input to a PICAXE, and the 'Trig_OUT' is a normal PICAXE output from the same chip, then there will be no problem connecting the pins of one PICAXE to itself.

But if you then connect the 'Trig_OUT' pin of another PICAXE to this arrangement you will be short-circuiting that output each time one of the other devices sends a trigger.

Much better to use a diode driver onto a bus.

With this arrangement, and a requirement that trigger pulse is one second long, it is possible to determine that the in & out are linked by using very short 'test' pulses.

It's an interesting problem to solve.

Cheers,

Buzby
 

techElder

Well-known member
Block Diagram

Buzby, that is correct, but the object is to allow for "daisy chaining" of function blocks similar to RX/TX in serial comms. The spec would have to be that an output would not "return" to the origin without the link having been removed. Diodes would be the friend here, but I was trying to think in terms of software.

Here's a simple block diagram, but imagine that this could be several blocks strung out to the right with each performing a sequential function.

ADDED:

I'm using a 20X2. I'm always forgetting about the "SRLATCH" stuff with SRQ. It would mean some hardware changes (PCB etc.) Not optimal.

I guess I'm going to have to poll the timer in order to RESET the pin after TRIG_IN detects the TRIG_OUT level whether using a regular pin or SRQ.
 

Attachments

Last edited:

Buzby

Senior Member
Looking at your block diagram, it is unclear how further devices would connect.

Edit :

If in 'normal' operation you need each device to start when the previous one finishes, then the simplest way is for each node to have it's trig_out connected to the trig_in of the next node, and repeat this for each node.
Code:
------------in-[node1]-out------[1K]-------in-[node2]-out------[1K]------in-[node3]-out---------
                                             |-short-|
To determine if a node is shorted just needs a resistor in each link, and a bit of extra code.

Firstly, use the pullup instruction on the 'in' pins.
Secondly, use tristate on the 'out' pins such that active=0v, and idle=floating. You can do this by using 'LOW' and 'INPUT' to set the active and idle states.

Now, if you drive the 'out' LOW, the 'in' will show low if it's shorted, but show high if it's not.

You can't use simple PULSIN/PULSOUT because of the tristate requirements, so you will have to do the timing in code, but no PCB changes needed.

Cheers,

Buzby
 
Last edited:

techElder

Well-known member
The diagram is shown with only one set. The TRIG_IN would connect to TRIG_OUT on the left and provide TRIG_OUT to another function block on the right ... daisy chain style.
 

Buzby

Senior Member
Hi Tex,

Thats what I 've shown above. Each node triggers the next, left to right.

Are we singing from the same hymnsheet now ?

Cheers,

Buzby
 

techElder

Well-known member
I missed your edit when I replied. Yes, I see what you've diagrammed and how to determine proper hardware operation. That might be necessary.

So, the "problem" is not on how to trigger the sequentially installed function blocks one after another. That works fine.

The solution I'm trying to come up with is how to use the same circuitry, TRIG_OUT and TRIG_IN within one function block to continuously trigger the function of that block; triggering itself in the same way that it would trigger other blocks.

Jumpering the TRIG_OUT to the TRIG_IN within a function block is part of the hardware, but I haven't found a simple way to accomplish that in software and maintain the "daisy chain" operation, too.

You can't just generate a TRIG_OUT pulse, because the pulse is obviously gone before the subroutine has exited.
 

Buzby

Senior Member
Hi Tex,

It's too late ( 02:16 here ) for me to explain my idea in detail, but so I can start tomorrow, what pins on the 20X2 are you using for trig_in / trig_out ?

Cheers,

Buzby
 

PieM

Senior Member
Hi,

TRIG_OUT :
1- pulse to next and previous function block
2- high internal flag

TRIG_IN :
read pulse or internal flag
 

techElder

Well-known member
Thanks, PieM. I'm thinking that the problem with the flag is that when the function block is not connecting (shorting) TRIG_OUT to TRIG_IN, the function block is still seeing the flag and triggers its actions when it should be waiting for an external trigger through TRIG_IN.

Hi,

TRIG_OUT :
1- pulse to next and previous function block
2- high internal flag

TRIG_IN :
read pulse or internal flag
 

techElder

Well-known member
Seems like I could set the TRIG_OUT to a high level for detection by the next (if connected) function block's TRIG_IN.

In the same sub, the next statement sets the timer and the sub exits.

An interrupt on toflag resets TRIG_OUT to a low level, thus giving the TRIG_IN routine time to react to TRIG_OUT when the two are connected on the same function block.

Does that sound viable?
 

techElder

Well-known member
The PCB has been designed and routed. The pins are chosen. Perhaps the following will settle it.

I've come up with this that does almost work, but using the interrupt means I don't know where the program will be when toflag is set.

Difficult to simulate this without doing the hardware, though.


EDIT: Arrrrgh! I forgot to test for TOFLAG on return from the interrupt and before the SETTIMER OFF statement. (do until TRIG_IN = TRUE OR toflag = TRUE : loop)


Code:
[color=Green]' timer minor ticks are 8us at 32MHz
' ONESECONDPRELOAD = 1000000 us ; 1000000us / 8us = 125000 ; 65536 - 125000 = !!!
' HALFSECONDPRELOAD = 500000 us ; 500000us / 8us = 62500 ; 65536 - 62500 = 3036 (counting up from this value)
' QTRSECONDPRELOAD = 250000 us ; 250000us / 8us = 31250 ; 65536 - 31250 = 34286 (counting up from this value)[/color]

[color=Blue]symbol HALFSECONDPRELOAD      [/color][color=DarkCyan]= [/color][color=Navy]3036         [/color][color=Green]; at 32MHz[/color]
[color=Blue]symbol QTRSECONDPRELOAD       [/color][color=DarkCyan]= [/color][color=Navy]34286         [/color][color=Green]; at 32MHz[/color]
[color=Blue]symbol [/color][color=Purple]TRIG_IN                [/color][color=DarkCyan]= [/color][color=Purple]pinC.6       [/color][color=Green]; External sync input [/color]
[color=Blue]symbol TRIG_OUT               [/color][color=DarkCyan]= [/color][color=Blue]A.0          [/color][color=Green]; External sync output

'Other constants[/color]
[color=Blue]symbol ZERO                   [/color][color=DarkCyan]= [/color][color=Navy]0[/color]
[color=Blue]symbol TRUE                   [/color][color=DarkCyan]= [/color][color=Navy]1[/color]
[color=Blue]symbol FALSE                  [/color][color=DarkCyan]= [/color][color=Navy]0[/color]
[color=Green]' for PAUSE milliseconds[/color]
[color=Blue]symbol THREESECOND         [/color][color=DarkCyan]= [/color][color=Navy]12000           [/color][color=Green]; 12000 = 3 second (3000 millisecond) @ 32MHz[/color]
[color=Blue]symbol TWOSECOND           [/color][color=DarkCyan]= [/color][color=Navy]8000            [/color][color=Green];  8000 = 2 second (2000 millisecond) @ 32MHz[/color]
[color=Blue]symbol ONESECOND           [/color][color=DarkCyan]= [/color][color=Navy]4000            [/color][color=Green];  4000 = 1 second (1000 millisecond) @ 32MHz[/color]
[color=Blue]symbol HALFSECOND          [/color][color=DarkCyan]= [/color][color=Navy]2000            [/color][color=Green];  2000 = 1/2 second (500 millisecond) @ 32MHz[/color]
[color=Blue]symbol QTRSECOND           [/color][color=DarkCyan]= [/color][color=Navy]1000            [/color][color=Green];  1000 = 1/4 second (250 millisecond) @ 32MHz[/color]
[color=Blue]symbol EIGHTHSECOND        [/color][color=DarkCyan]= [/color][color=Navy]500             [/color][color=Green];   500 = 1/8 second (125 millisecond) @ 32MHz[/color]
[color=Blue]symbol TENTHSECOND         [/color][color=DarkCyan]= [/color][color=Navy]400             [/color][color=Green];   400 = 1/10 second (100 millisecond) @ 32MHz[/color]
[color=Blue]symbol TWENTYTHSECOND      [/color][color=DarkCyan]= [/color][color=Navy]200             [/color][color=Green];   200 = 1/20 second (50 millisecond) @ 32MHz[/color]
[color=Blue]symbol FOURHUNDRETHSECOND  [/color][color=DarkCyan]= [/color][color=Navy]10              [/color][color=Green];    10 = 1/400 second (2.5 millisecond) @ 32MHz[/color]


[color=Blue]SETFREQ M32                                  [/color][color=Green]; 32 MHz delay CONSTANTS depend on this frequency[/color]

[color=Blue]do
      gosub [/color][color=Black]TrigOut

      [/color][color=Blue]gosub [/color][color=Black]TrigIn

      [/color][color=Blue]pause ONESECOND

loop

end[/color]

[color=Black]TrigOut:
   [/color][color=Green]' create a timed high level on the TRIG_OUT pin
   [/color][color=Blue]setintflags [/color][color=Navy]%10000000[/color][color=Black], [/color][color=Navy]%10000000
   [/color][color=Purple]timer [/color][color=DarkCyan]= [/color][color=Navy]0xFFFF [/color][color=Green]' maximum before overflow after minor tick countdown
   [/color][color=Blue]settimer QTRSECONDPRELOAD [/color][color=Green]' quarter second
   [/color][color=Blue]high TRIG_OUT
   return[/color]

[color=Black]TrigIn:
   [/color][color=Green]' wait for a timed high level on the TRIG_IN pin
   [/color][color=Blue]do until [/color][color=Purple]TRIG_IN [/color][color=DarkCyan]= [/color][color=Blue]TRUE [/color][color=DarkCyan]OR [/color][color=Purple]toflag [/color][color=DarkCyan]= [/color][color=Blue]TRUE [/color][color=Black]: [/color][color=Blue]loop
   settimer off
   return


interrupt:
   setintflags OFF
   low TRIG_OUT
   return[/color]
 
Last edited:

Buzby

Senior Member
Hi Tex,

It looks like you are on the right track, but I'm still concerned about releasing magic smoke when you have a few devices connected and a shorting link in place.

Consider this ....

Code:
------------in-[node1]-out-------------in-[node2]-out------------in-[node3]-out---------
                                         |-short-|
If node1-out is LOW, when node2-out goes HIGH there is a direct connection from the HIGH on node2 to the LOW on node1.
This is not a good situation to be in because (a) there will be a high current draw through both chips, and (b) the voltage on the 'in' pin will be indeterminate, which means you can't really tell if it's a 1 or a 0.

A resistor between each node will alleviate these problems.

Cheers,

Buzby
 

techElder

Well-known member
Thanks for that. I'm purty sure I have a 220 ohm resistor in the line between TRIG_OUT and the output pin. I usually do that on serial pins, too.

I'm going to investigate how short I can make the output pulse once I get some hardware put together.

I'm still being nagged by thoughts that this is an over complicated solution.
 

techElder

Well-known member
More thoughts occur slowly.... (This time of year our thoughts are mighty busy elsewhere, aren't they? :D)

It finally occurred to me that the function block could be / have a mechanical block. That might bring up a safety and/or timing issue upon power up situations.

The idea was that on power up the programming would run to the point of waiting for a TRIG_IN signal before starting any functions. That, of course means that upon power up NOTHING HAPPENS.

So, the easy solution is to create a one time TRIG_OUT at the beginning of the program, so everything performs its function at least once upon power being applied. If the function block simply lights an LED, no problem. You get an initial bunch of light. Then there's those pesky mechanical safety and/or timing issues.

So, the easy solution is to add some sort of external "switch" just to be installed for those pesky mechanical safety and/or timing issues. Theoretically (or ideally), this "switch" is just a time delay that keeps those pesky mechanical safety and/or timing issues from seeing the initial TRIG_OUT at the beginning of the program.

So, the easy solution is to ....

Well, there's no easy solution other than to add more input hardware to the project.

Or, is there? :D
 

techElder

Well-known member
I'm still welcoming ideas and comments, but I'm continuing on with a solution.

Each function block has two variable controls for certain settings. These are read by ADC pins to adjust those settings. So, to solve those pesky mechanical safety and/or timing issues, I'll read those control's values at startup.

If the controls are BOTH set at minimum values (near ZERO) then I'll save a flag bit in EEPROM.

Reading the flag bit from EEPROM at startup will cause that function block to enter a long delay to wait for all the other function blocks to settle.

Otherwise, each function block will initialize with a TRIG_OUT pulse to get the proper POWER-UP started. (The PICAXE pin driving TRIG_OUT does have a series current limiting resistance in case this short pulse gets two (or more) outputs connected at different logic levels.)


The real purpose behind this kind of option is to maintain a single program/board/hardware configuration no matter how the function blocks are connected.
 
Top