Proven Methods Create Logic-Analyzer Triggers That Work
Setting up logic-analyzer triggers is often difficult and time consuming. You might think that a knowledge of programming would make the job a snap. But that's not the case, since many of the key concepts you need to know are unique to logic analysis. Understanding these concepts and how to use them effectively is the best way to avoid problems while setting up triggers that do the job properly.
Compare the memory of a logic analyzer to a very long conveyor belt. The samples acquired from the device under test (DUT) are boxes on that belt. At one end, new boxes are continuously placed on the conveyor belt. At the other end, the boxes fall off. In other words, logic-analyzer memory is limited in depth (number of samples). So if the memory is full, the oldest sample currently in memory will be bumped out whenever a new one is acquired.
In essence, a logic-analyzer trigger does the equivalent of looking for a special box and stopping the conveyor belt when that box reaches a particular position on the belt. That special box is the trigger. Once the logic analyzer detects a sample that matches the trigger condition, it waits until the trigger is located appropriately in memory. It then stops acquiring further samples.
The location of the trigger in memory is known as the "trigger position." Normally, this position is set to the middle so that the maximum number of samples that occurred before and after the trigger are in memory. You can set the trigger position to any point in memory, however.
While logic-analyzer triggers are often simple, implementing them can require complex programming. For example, you may want to trigger on the rising edge of one signal, which is followed by the rising edge of another signal. The logic analyzer must find the first rising edge before it begins looking for the second one. Since there is a sequence of steps to find the trigger, this is known as a "trigger sequence." Each step of the sequence is called a "sequence level," or a "state."
Every sequence level consists of two parts: the conditions and the actions. The conditions are Boolean ex pressions such as, "If ADDR = 1000" or "If there is a rising edge on SIG1." The actions are what the logic analyzer should do if the condition is met. Examples of actions include triggering the logic analyzer, going to another sequence level, or starting a timer. This is similar to an If/Then statement in programming.
In the trigger sequence, each sequence level is assigned a number. The first level to be executed is always Sequence Level 1. But because of the "Go To" actions, the rest can be executed in any order.
When a sequence level is executed and none of the Boolean expressions are true, the logic analyzer acquires the next sample and executes the same sequence level again. As a simple example, consider the following trigger sequence:
- If DATA = 7000 then Trigger
If the following samples were acquired, the logic analyzer would trigger on Sample 6.
Sample | ADDR | DATA |
1. | 1000 | 2000 |
2. | 1010 | 3000 |
3. | 1020 | 4000 |
4. | 1030 | 5000 |
5. | 1040 | 6000 |
6. | 1050 | 7000 |
7. | 1060 | 2000 |
Sequence Level 1 simply means, "Keep acquiring more samples until DATA = 7000, then trigger."
Even if a Boolean expression in a sequence level is met, another sample is always acquired before executing the next sequence level. In other words, if a sample meets the condition in Sequence Level 1, another sample will be acquired before executing Sequence Level 2. It is not possible for a single sample to be used to meet the conditions of more than one sequence level. Each sequence level can be thought of as representing events that occur at different points in time. Two sequence levels can never be used to specify two events that happen simultaneously.
For instance, consider the following trigger sequence:
- If ADDR = 1000 then Go to 2
- If DATA = 2000 then Trigger
If the following samples were acquired, Sample 1 would meet the condition in Sequence Level 1. The logic analyzer would trigger on Sample 7.
Sample | ADDR | DATA |
1. | 1000 | 2000 |
2. | 1010 | 3000 |
3. | 1020 | 4000 |
4. | 1030 | 5000 |
5. | 1040 | 6000 |
6. | 1050 | 7000 |
7. | 1060 | 2000 |
Note that the logic analyzer will not trigger on Sample 1, because a new sample is acquired between the time the condition in Sequence Level 1 is met and the condition in Sequence Level 2 is tested. Think of this trigger sequence as "Find ADDR = 1000 followed by DATA = 2000 and then trigger." Multiple sequence levels in a trigger sequence imply a "Followed By."
Once a logic analyzer triggers, it doesn't trigger again. Even if more than one sample meets the trigger condition, the logic analyzer only triggers once. Using "ADDR = 1000" as our trigger, if the logic analyzer acquires the following samples, it will trigger on Sample 2 and only on Sample 2.
ADDR | |
0000 | |
1000 | (Trigger) |
2000 | |
1000 | (No trigger) |
1040 | |
1060 | 2000 |
So if you set up a trigger condition that is never met, the logic analyzer will never trigger.
Suppose the conditions are met in a sequence level. It is clear which sequence level will be executed next when a "Go To" action is used. But whether there is no "Go To" isn't necessarily apparent. On some logic analyzers, if there's no "Go To," this means that the next sequence level should be executed. On others, the same sequence level should be executed again. Due to this confusion, it's good practice to always use a "Go To" action rather than relying on the default. In fact, the HP 16715A state-and-timing module deals with this problem by automatically including a "Go To" or "Trigger" action in every sequence level.
Boolean Expressions While multiple sequence levels imply a "Followed By," Boolean expressions actually can be used within a sequence level. Look at the following:If ADDR = 1000 and DATA = 2000
For this expression to be met, ADDR must equal 1000 in the same sample that DATA equals 2000. In other words, ADDR equals 1000 at the same time that DATA equals 2000. So if you want to trigger on two events that occur at the same time, a Boolean expression should be used.
It's a common mistake to try to use two sequence levels when a Boolean expression should be used or vice versa. Boolean expressions are utilized for events that happen at the same time, while multiple sequence levels are used when one event follows another.
Branches are similar to the Switch statement in the C programming language and the Select Case statement in Basic. Both provide a method for testing multiple conditions. Each branch has its own actions, as shown below:
- Else If ADDR > 2000 then Go to 3
Else If DATA = 2000 then Trigger - If DATA <= 7000 then Trigger
- If there is a Rising Edge on SIG1, then Trigger
In Sequence Level 1, there are three branches. Three possible actions can be taken.
When the condition of one branch is met, the branches below it aren't tested. There's no way for more than one branch to be executed based upon a single sample, even if that sample causes the conditions for more than one branch to be met. In other words, each branch is an "Else If."
Edges And Ranges Edges represent a transition from low to high or high to low on a single signal. Typically, edges are specified as rising edge, falling edge, or either edge, where rising edge indicates a transition from a low to a high. On most logic analyzers, up to two edges can be included in the trigger sequence, although some allow only one.Ranges are a convenient method for specifying a range of values such as, "ADDR in range 1000 to 2000." Most logic analyzers also support a "not in range" function as well. Ranges are a convenient shortcut so that you don't have to specify "ADDR >= 1000 and ADDR <= 2000."
Counters Occurrence counters are employed in situations where users want to find the nth occurrence of an event. For example, if a user wants to trigger on the fifth time that ADDR = 1000, the trigger could be set up as follows:If ADDR = 1000 occurs 5 times then Trigger
Global counters, on the other hand, are like integer variables. As they're more flexible than occurrence counters, they can be used to count complex events such as an edge followed by another edge. These counters can be incremented, tested, and reset. By default, global counters begin with zero and don't need to be reset unless they've already been used in the trigger sequence.
In general, though, occurrence counters should be used in place of global counters for two reasons. They are easier to use, and there are a limited number of global counters.
Timers Timers check the amount of time that has elapsed between events. If you want to trigger on one edge followed by another edge that occurs within 500 ns, a timer should be used. When using timers, it's critical to remember that they need to be started before they're tested. In other words, they don't start automatically.The key to setting up a timer is to identify where it should be started and tested. Consider an example in which the timer should be started when the rising edge on SIG1 is detected. Testing should occur when the rising edge occurs on SIG2 (Fig. 1).
A trigger sequence that could set up this measurement is:
- If there is a Rising Edge on SIG1, then
Start Timer1
Go to 2 - If there is a Rising Edge on SIG2 AND
Timer1 < 500ns then Trigger
While the above trigger sequence seems correct, it actually has a critical flaw. What happens if there is a rising edge on SIG1 but SIG2 doesn't occur within 500 ns? The logic analyzer will never trigger. Timer1 will keep running and condition "Timer1 < 500 ns" will never be met. Another rising edge might be on SIG1 that's followed within 500 ns by a rising edge on SIG2 that occurs later on, so this situation is unacceptable.
The other problem with this sequence is that it doesn't check for a second rising edge occurring on SIG1 prior to the rising edge on SIG2. The first rising edge on SIG1 might be too far from the rising edge on SIG2, but the second one could be within 500 ns.
To fix these problems, whenever the timer exceeds 500 ns without triggering, the sequence should loop back to Level 1 to look for another rising edge on SIG1. The sequence also should reset the timer whenever a second rising edge on SIG1 is found before the rising edge on SIG2. Here's an example of the correct sequence:
- If there is a Rising Edge on SIG1, then
Start Timer1
Go to 2 - If there is a Rising Edge on SIG2 AND
Timer1 < 500ns then Trigger
Else If Timer1 >= 500ns then
Reset Timer1
Go to 1
Else If Rising Edge on SIG1 then
Reset Timer1
Go to 2
Occasionally, users may run out of timers. Use a counter in place of a timer if the logic analyzer is sampling at regular intervals. A timer can be simulated by counting the number of acquired samples. Say the logic analyzer acquires a new sample every 10 ns and seven samples are acquired. This represents 70 ns.
Storage Qualification Storage qualification determines whether an acquired sample should be stored (i.e., placed in memory) or thrown away. This keeps the logic-analyzer memory from being filled with unneeded samples.The easiest way to obtain storage qualification is to set up the default storage. This is specified separately from the trigger sequence, in some thing like a separate tab or another dialog box. Default storage means "unless a sequence level specifies otherwise, this is what should be stored." For instance, you may want to store samples only if the address is in the range 1000 to 2000. In that case, you would set the default storage to:
ADDR In Range 1000 to 2000 Initially, the default storage is set to store all samples acquired. You also can set it to store nothing, which means that no samples will be stored unless a sequence level overrides the default storage.Sequence-level storage qualification means that within a particular sequence level, only certain samples will be stored. Until a "Go To" or "Trigger" action is used to leave a particular sequence level, the storage qualification applies. This is useful when you want a different storage qualification for each sequence level. You may want to store nothing until ADDR = 1000 and then store only samples with ADDR in the range 1000 to 2000 for the rest of the measurement.
Setting up this kind of storage requires the use of an additional branch. If you want to store only samples with ADDR in the range 5000 to 6FFF while looking for DATA = 005E, the following sequence level could be used in some situations:
- If DATA = 005E then Trigger
Else If ADDR in range 5000 to 6FFF then
Store Sample
Go to 1
Note the use of the "Store Sample" action. This means, "Store the most recently acquired sample in memory now." It does not translate into, "From now on, start storing." Note that the "Store Sample" action is never executed unless ADDR is in the range 5000 to 6FFF, which means this branch essentially states, "While in this sequence level, store only samples with ADDR between 5000 and 6FFF."
The above example seems to imply that only samples with ADDR between 5000 and 6FFF will be stored. But this depends on how the default storage has been set up. Suppose the default storage is set to "Store Everything." Then, if a sample is outside of the range 5000 to 6FFF, the "Else If" branch isn't executed and the default storage is applied. In essence, the sequence level states what to do when a sample has a value in a particular range. But it doesn't explain what to do for samples outside the range. To specify the sequence-level storage unambiguously, use the following:
- If DATA = 005E then Trigger
Else If ADDR in range 5000 to 6FFF then
Store Sample
Go to 1
Else If ADDR not in range 5000 to 6FFF then
Don't Store Sample
Go to 1
Alternatively, if the default storage is set to "Store Everything," the following can be used:
- If DATA = 005E then Trigger
Else If ADDR not in range 5000 to 6FFF then
Don't Store Sample
Go to 1
Sequence-level storage always overrides the default storage, but only for the conditions specifically mentioned within it. You must be very careful that those conditions account for the interaction between default and sequence-level storage.