3

I need to do the following: I have 2 input pins on a microcontroller, and it is possible, that a signal is received on one or the other, but it is also possible that the two will be physically connected on the outside, and the signal arrives on both at the same time.

The problem: if I use something like

if (PINB.1 && PINB.2)
{
  // ...
}

there is the one in a million chance, that the signal arrives between when the two values are loaded into the registers for the logical AND operation to be performed. When I leave the if, both the pins are high, but I still detected that only the second one was high.

I tried out different solutions, and the best so far seems to be to start a very short countdown when either of the inputs is high, and when the timer (a few milliseconds at most) runs down, I check again.

Does anyone know a simpler or better solution? I thought this problem was very common, but I could not find any "tried and true" methods so far.

Edit: I know from the hardware, that after an edge the pin will hold its value for at least a few dozen milliseconds. Noise is already been taken care of.

PINB.1 and PINB.2 were just examples. They might possibly be on different ports, so bitmasking the whole port might have the risk of not being flexible enough.

Gilles 'SO- stop being evil'
  • 104,111
  • 38
  • 209
  • 254
vsz
  • 4,811
  • 7
  • 41
  • 78
  • What condition are you watching for exactly? Do you just want to respond to every rising edge on either pin? – Owen Aug 26 '11 at 06:50
  • I have to watch for a lot of different conditions (edges, number of signals in a certain time slot, lengths of signals, etc.), but I know from the hardware that after a rising edge the pin will be high for a reasonable amount of time: at least a few dozen milliseconds. – vsz Aug 26 '11 at 07:00
  • What condition is the `if` in your question looking for? – Owen Aug 26 '11 at 08:23
  • Can you change hardware? Are input ports in same register? Best solution would be to put all your inputs in PINs in order to share same I/O register, that is, when you read register you'll be reading all inputs simultaneously. To test inputs, a simply OR/AND masking would solve all your issues. On second thought, I really doubt that your microcontroller is so slow in order to interfere with results. You say that input signals are already damped by the milliseconds, which kind of processor would take so much time to do a pair of compare instructions??? – ruhalde Sep 02 '11 at 18:16

5 Answers5

5

You have answered your own question: simply use a timer and check the pins again, it is the simplest form of a digital filter you can use. But you must start the timer when you detect a pin level change. If you have a very steep raising edge, ie the pin is connected to some digital IC, then it might even be sufficient to simply read the pins twice, depending on how fast your CPU clock is in comparison to the raising edge.

Another solution is to use an edge-sensitive interrupt, if the MCU has this feature. Then you are guaranteed to read the pin just after the change. With one interrupt for each pin, your program can store the most recent values of the pins for the == comparison. You'll have to ensure that the values are guarded with semaphores between the interrupts and "main", or you are back where you started.

Lundin
  • 195,001
  • 40
  • 254
  • 396
4

Are you wanting to look for the condition when they are both asserted? If so just sample them if not both asserted then dont bother. if this is an interrupt thing and you are probably using C code? Even if assembler just sample two or three times if after interrupt both are not asserted then it was a false deal and ignore it.

If you are looking at these as two separate events and concerned about the few times you read the port and they are both asserted. You should probably already separate the reading of a port and the handling of what you found. Read the port if bit 0 then do stuff if bit 1 (from the stored value not a re-read of the port) then do bit 1 stuff.

There is no such thing as best practices other than "do your system engineering" (because design goals are different across the different industries that use similar hardware). All of these issues and resolutions are covered by the system engineering. Your system engineering will tell you exactly what the margin is on the event you are concerned about and knowing the properties of the controller/processor you know how the interrupt system responds if used or what your execution and sampling rate is to know how the microcontrollers properties relate to the event in question. I am willing to bet that performing and saving two reads quickly then saying if either one of these reads has both bits asserted then declare the event had happened. You should already be oversampling the input based on the expected/designed signal, and as a result you can probably discard the samples that are on the edge of the state change of the inputs.

old_timer
  • 69,149
  • 8
  • 89
  • 168
  • +1 for "do your systems engineering". The question is unanswerable without knowing exactly what your systems constraints are. That said, given the timing you describe, I'd guess this is a non-issue. "A few milliseconds" is an eternity compared to the window where 2 pins connected to the same source might give different readings. It likely that if you miss a "detection event" because you happen to hit that window on one pass through this code, it will be fine as long as you detect it on the next pass. – AShelly Aug 29 '11 at 17:59
2

I think you're chasing a ghost, or you don't have your problem well specified.

For example, say you put a 1 ms timer between the bit tests - all you've done is 'move the bar' for the race. Is it OK to have the code act as if only one bit is set if the second bit goes high at 1 picosecond after the 1 ms timer expires? If so, why would you want that behavior to be different from what's happening with your current code.

That's not to say it wouldn't be correct, just that you should understand why it is if that's your assertion. And that depends exactly what the problem is.

Michael Burr
  • 333,147
  • 50
  • 533
  • 760
  • This is why I said that I only have to deal with the simultaneous signals when the two input wires are physically soldered together. This means that the only problem is that the condition in my `if` is not atomic, so it can happen, that the signal arrives when the conditions is being evaluated. If I check the condition a little delayed after a pin was high, I can be sure that both are set properly. – vsz Aug 26 '11 at 07:00
  • One thing to be careful of is to not get fooled if you have the pins connected to separate inputs, but they both happen to be high at the same time (or close enough to the same time). This is not a problem that's easy to solve in the general case, but your situation might have some properties that make it easier or less of a problem in some way. – Michael Burr Aug 26 '11 at 07:08
  • That small timer is useful for the extremely rare case if the simultaneous signal gets detected a little sooner on one port because of minor differences in transistor switching times, but it would be more common to have an error because the condition is not atomic. – vsz Aug 29 '11 at 05:45
  • @vsz: I guess what I;m trying to say is you need to define quite specifically what's meant by 'simultaneous' and should have an idea for what might happen if the inputs are connected to different signals but both are asserted 'simultaneously'. That might be OK, but you should have that contingency accounted for. – Michael Burr Aug 29 '11 at 07:35
1

In order to avoid hard-to-repeat bugs, embedded firmware should adhere to the following schema:

  1. input reading and buffering
  2. computation of buffered outputs from buffered inputs
  3. buffered output writing

In other words, you're moving from a continuous time domain to a discrete one. It's like elaborating snapshots taken of the real continuous world. Fail to do that and you'll end up with input signals which change in the middle of the computation with unpredictable and unrepeatable results.

That being said, if you read [0 1] or [1 0], that is the input for the subsequent computation. You'll read a [1 1] at next run.

You could not be sure to sample a [1 1] even if you connect the same signal to two pins of the same port: there are hardware tolerances which makes it impossible.

lorcap
  • 173
  • 2
  • 8
  • These hardware tolerances (and the bigger problem of not handling the condition in an atomic way) was that made me use that small delay. I was aware of these problems, I was just simply searching for a better/more elegant solution. – vsz Aug 29 '11 at 05:47
1

In the real world, there's seldom such a thing as two inputs which change "simultaneously". If you know that two inputs will either become active within a few instruction times of each other, or else not become active anywhere near each other, you could do something like:

  if (INPUT1)
  {
    if (INPUT2 || INPUT2 || INPUT2 || INPUT2)
      handle_double_input();
    else
      handle_input_1_only();
  }
  else if (INPUT2)
  {
    if (INPUT1 || INPUT1 || INPUT1 || INPUT1)
      handle_double_input();
    else
      handle_input_2_only();
  }

INPUT1 and INPUT2 should both be macros defined which use volatile qualifiers to ensure that the inputs are actually polled rather than cached. The repeated terms in the "if" test when one input is detected should allow time for the other input to switch as well. The number of repetitions required may vary with the maximum input skew and the execution speed of the controller.

supercat
  • 77,689
  • 9
  • 166
  • 211