Continue after microsecond timed interval

I've searched the forum for leads into this, but my main problem is how to define the search term in order to find what I want. So far. no luck.

I'm very new to Arduino but have been playing with PIC and other microcontrollers using assembly language and embedded 'C' for a long time. This is what I am trying to do with an UNO, staying within the Arduino IDE / environment and using existing functions and libraries if possible.

1) Poll an input for a state change. When the state changes, start a microsecond (not millisecond) timer running with a countdown time of 416uS.

2) While the timer is running, I need to execute some other code, which is why I can't just use 'delayMicroseconds()'. The total execution time of the code will always be substantially less than 416uS - it will always complete well before the timer times out. I will make sure that is the case. However, it will take a different amount of time, give or take up to maybe ten microseconds, each time, depending on the outcomes of various branches within the code.

3) When the code has executed, poll something (a timer flag?) until the timer completes its 416uS run. Then stop, reload and restart the 416uS timer. Then continue on to run more code.

I can see something which is almost exactly what I need in the form of the 'Metro' Functions in the contributed libraries, but these have a resolution of milliseconds rather than microseconds. Is there an Arduino workaround or method? If not, can I embed assembly language or C code using direct access to registers within the body of an Arduino sketch, for certain tasks not covered by existing libraries or functions?

micros() returns a "stopwatch-like" value. You can record the current time with it. At a later time, you can subtract said value from micros() to determine how long it has been since you set the value. This concept is demonstrated in the BlinkWithoutDelay example. The example uses millis(), but it's the same concept for micros()

Assuming you're running at 16 MHz, you can:

  • Set up Timer1 for CTC, OCR1A = TOP = 416 * 16 = 6656, no prescaling
  • When your event happens, start Timer1
  • When you're finished processing something, start polling TIFR1 for TOV1

Untested.

These things could affect the precision of your interval:

  • Sooner or later you'll be unfortunate enough for the Timer0 interrupt to be executing just as the input changes, or the interval elapses, unless you disable that interrupt. You'd run long by a little bit.
  • The accuracy of the beginning and end of the interval will depend on exactly which statement is being executed when wither happens. If the relevant state chagnes just after it's tested, you'll miss it by whatever the loop overhead is - and a byte with something, branch, and read. That'll likely be something like 0.5 microsecond.

You don't mention what you want to do when the timer elapses. If it's something simple, like change the state of an output pin, you might be able to persuade the timer to do it for you. That won't suffer from any likelihood of interrupt or polling latency, at least in checking the end condition.

You can even use the timer tmd3 suggested and let it trigger an interrupt once that TOP value is reached.

The timer0 issue can be resolved by changing the base code, inserting a

sei();

at the start of the interrupt handler (enabling nested interrupts for this case).

Arrch: micros() returns a "stopwatch-like" value. You can record the current time with it. At a later time, you can subtract said value from micros() to determine how long it has been since you set the value. This concept is demonstrated in the BlinkWithoutDelay example. The example uses millis(), but it's the same concept for micros()

Two things about that: One is that I guess the value must wrap around eventually so I would have to have extra code to cope with the rare case where micros() returns a smaller value than it did when last checked: But also, all that MATHing about, ie,

Get millis() "Is it still under 416uS different from the 'start' value?" (This is likely to take 10,20,30,40 or more microprocessor instructions to resolve) If so, look again

-will take quite a bit more processor time (to do the fetch, compare values every time) than simply checking a timer flag.

"Is flag = 1?" If not, look again.

Where the interval concerns milliseconds as in the example you have quoted, then a few tens of microseconds 'jitter' either way caused by the rather lengthy maths comparison would not matter either way - but when the period being timed is itself measured in microseconds then any action taken to query the state of the time has to be as short as possible - ideally no more than a handful of microseconds.

But it is one one method, and it may be the only method open to me without breaking out of the pure Arduino environment.

Two things about that: One is that I guess the value must wrap around eventually so I would have to have extra code to cope with the rare case where micros() returns a smaller value than it did when last checked: But also, all that MATHing about, ie,

No, you don't have to. If you declare the corresponding variables as unsigned long (or uint32_t), the overflow in the subtraction will do that automatically for you. But you're correct, even doing that calculation may need up to a microsecond, so you may be off the desired value.

tmd3: Assuming you're running at 16 MHz, you can:

  • Set up Timer1 for CTC, OCR1A = TOP = 416 * 16 = 6656, no prescaling
  • When your event happens, start Timer1
  • When you're finished processing something, start polling TIFR1 for TOV1

Untested.

These things could affect the precision of your interval:

  • Sooner or later you'll be unfortunate enough for the Timer0 interrupt to be executing just as the input changes, or the interval elapses, unless you disable that interrupt. You'd run long by a little bit.
  • The accuracy of the beginning and end of the interval will depend on exactly which statement is being executed when wither happens. If the relevant state chagnes just after it's tested, you'll miss it by whatever the loop overhead is - and a byte with something, branch, and read. That'll likely be something like 0.5 microsecond.

You don't mention what you want to do when the timer elapses. If it's something simple, like change the state of an output pin, you might be able to persuade the timer to do it for you. That won't suffer from any likelihood of interrupt or polling latency, at least in checking the end condition.

Ok, what I'm doing is trying to receive 'Manchester' encoded code (it may be better known by another name). Put briefly, a Manchester encoded serial bit has two halves which are always in opposite states - one convention (which is also my convention) is that if the first half of the bit is logic '1' then the value of the bit is logic '1', and if the first half of the bit is logic '0' then the value of the bit is logic '0'. In this example, one whole bit is 1664 uS long, so each half of the bit is 832uS long and a quarter of a bit would be 416uS.

Without going into too much detail I have a known start point which I know is the start of the first bit, so that's where all timing initially starts from.

Start:

At the beginning of the bit: Delay 416uS (I could do this delay with the simple microsecond delay, no problem). This brings me to one quarter of the way through the bit.

-sample the state of the input now, save the input value as LHBIT

Now, Manchester encoded bits always have a state change half way through the bit. I wait for that by polling the input until it changes. I'm now in the middle of the bit.

Delay 416uS. Again, the simple system delay is OK.This brings me to three quarters of the way through the bit.

-sample the state of the input now, save the input value as RHBIT

Now, here's the problem. I need to time the remaining quarter bit time (416uS) to the end of the bit, so, I start a timer (416uS) and while the timer is running, I need to evaluate the bit value. If LHBIT = 1 and RHBIT = 0, that's a valid logic 1 bit, or if LHBIT = 0 and RHBIT=1, that's a valid logic 0 bit. In either case, shift the bit receiving register one place and insert this new bit into it... all this while the timer is still timing out the last quarter of the bit. When I've evaluated and stored the received bit, then I can relax and poll the timer until it times out.

At that point, I have reached the end of this bit / beginning of the next one and can go back to Start: to continue reception of the next bit. Of course there's a downcounter to keep track of how many bits I've received as well.

I could go: Start of bit Wait 416uS Sample LHBIT Wait until state changes Wait 416uS Sample RHBIT Wait 416uS ... and then evaluate the bit I've just received.

The problem there is that as I'm doing the evaluating, the next bit is already flowing straight on from the end of the last. That's why I prefer to do the bit evaluation / shifting inside a 'hollow' last quarter bit timer. That way, when I get to the end of the bit, I'm ready to start receiving the next one straight away. Hope this makes sense.

The use of the timer as you describe it sounds to be exactly what I'm talking about in principle, but can I just go ahead and start writing to and reading from registers directly in an Arduino script as though I were writing normal embedded 'C'?

OK. A bit time is 1664-ish microseconds, so the transmit rate is ~600 per second. You want to sample things twice per bit - once in the first half of the bit, once in the last half, and to catch the mid-bit transition. I think that the interval measurement doesn't need to be particularly accurate, since each quarter-bit time is 416 usec, and that amounts to more than 6600 system clock cycles at 16 MHz. I think that timing jitter due to interrupt latency won't be a problem.

Intuitively, I believe that this is doable using the "blink-without-delay" timing technique: when an interesting event happens, save the value of micros(), wait for micros() to be appropriately bigger than the saved value, and then do the next thing. Sample the bit, wait for the mid-bit transition, and then sample again; half a bit-time later, do it all over again. If the timing of any of those operations were way off - like maybe 100 usec - it won't matter if the input signal is remotely compliant. You'll also effectively resync at each mid-bit transition, as the promulgators of Manchester had hoped.

Of course, all that's untested conjecture.

There are probably some elegant ways to do this with Timer1 and a few interrupts. They're likely too much trouble for this application.

My experience says that you can read and write processor registers as if they were variables, using the register names defined in the datasheet. If there are exceptions, I either haven't found them, or they escape me just now. Others may know of some. Obviously, if you do any direct writing to registers, your code likely won't be 100% portable to other subspecies of Arduino.

I would not use timers or interrupts or registers. Completely unnecessary.

Pseudocode:

const int delayTime = 1000; // adjust to suit
stopTime = micros() + delayTime;
myOtherFunction(); // evaluate your other stuff
while (micros() < stopTime) {} // burn around in a tight empty loop
// proceed with getting next bit

tylernt:
I would not use timers or interrupts or registers. Completely unnecessary.

Pseudocode:

const int delayTime = 1000; // adjust to suit
stopTime = micros() + delayTime;
myOtherFunction(); // evaluate your other stuff
while (micros() < stopTime) {} // burn around in a tight empty loop
// proceed with getting next bit

@tylernt,

did you check what your code does when micros() + delayTIme; causes an overflow resulting in a very small stoptime?

I expect that the while loop will not “burn” the time you expect.

That said, the right way to do what you proposed is with subtractions:

const int delayTime = 1000;    // adjust to suit
uint32_t  startTime = micros();
myOtherFunction(); 
while (micros() - delayTime < startTime);  

// proceed with getting next bit

Check this with paper and pencil to see the difference in behaviour around the overflow point.

IF you want to solve this non blocking, check the blink without delay example

Wow, this is a busy forum. By the time I came back this topic had been washed all the way down to the fourth page. Thanks for your efforts to clarify my approach to the problem.

One thing I had not realised is the speed at which these devices apparently run, so I had assumed that polling (by doing complicated mathematical comparisons) would eat a lot of processor time per check and thereby make the response time (to a 'timeout reached' condition) rather coarse.

However, it is true that the minimum unit of time in this example (416uS) does allow some elbow room, and it is also true that by waiting for the mid-bit state change on every bit, I effectively re-synchronise once per bit, which doesn't give timing errors any chance to build up to a significant level.

I'll give the Starttime and Micros() approach a try - it sounds workable.

If you want to decode a Manchester encoded signal with the greatest accuracy possible on the Arduino hardware, use a 16 bit timer to get the timings and a CHANGE interrupt for the signal input. At every edge your interrupt handler gets called, read the timer value to know how much time has gone since the last call and set the timer to 0. With a simple state machine you can do the decoding very easily.

pylon: If you want to decode a Manchester encoded signal with the greatest accuracy possible on the Arduino hardware, use a 16 bit timer to get the timings and a CHANGE interrupt for the signal input. At every edge your interrupt handler gets called, read the timer value to know how much time has gone since the last call and set the timer to 0. With a simple state machine you can do the decoding very easily.

Thanks for the good advice, although I have a reason not to do it that way. That method is likely to work well as long as the incoming signal is perfect, but in my case this signal is coming from an FM radio receiver.

In weak signal conditions, where the signal is below a certain minimum strength, noise tends to start to appear and gets worse the weaker the signal is.

What this means is that there will be false extra edges which will hopelessly confuse any method which works by measuring the lengths of the pulses. By using the method I suggested (sampling the bit at the 1/4 and 3/4 marks) the bit can stand quite a lot of corruption and will still be decodable as long as the signal is in the correct state during the very small time it takes to sample it. Of course, a false edge could also be mistaken for the mid-bit state change as well, but as long as it occurs some time between the 1/4 bit sample and the 3/4 bit sample the routine (as outlined) will still manage to decode the damaged bit - if it can just struggle through to the middle of the next bit, all timing is then re-synchronised.

For the record, I did get this working using a very crude Arduino-only method without resorting to direct register access. Remember that 416uS = one quarter of a Manchester bit time in my actual example.

Pseudocode: Set Bitcounter = number of bits to receive Clear bit receiving buffer variable Detect leading edge of first bit of transmission

While Bitcounter is not equal to zero { Wait 416uS Sample data input state at the 1/4 bit point, save as LHBIT Wait for the mid-bit state change (If LHbit is high, wait for input = low, else wait for input = high) Wait 416uS Sample data input state at the 3/4 bit point, save as RHBIT Wait somewhat less than 416uS Evaluate bit validity / bit value from LHBIT and RHBIT and if valid shift it into the bit receiving buffer variable Bitcounter=Bitcounter minus one }

As you can see, the crude solution adopted was just to replace the final 416uS delay (to reach the end of the bit) with a shorter delay, equivalent to (416uS minus the average time taken for the bit evaluation code to complete). As this shortened delay plus the bit evaluation / shift in code take roughly 416uS overall, the end of the bit / beginning of the next bit occurs at around the time that the bit evaluation code completes. This rather approximate timing method is compensated for by the fact that the code resynchronises the timing at the mid-point of every bit.