1
\$\begingroup\$

Microcontroller: STM32F401RE Doing input capture on TIM1's channel 1,2,3,4. ARR register value is 65536. The clock is 8Mhz. The 4 input capture channels are connected to 4 microphones. As soon as a sound(bang) occurs all of these channels change their state from 0 to 1. The input capture is set on the rising edge. Whichever microphone is closer to the bang that microphone changes it's state first and with respect to their distance the rest follow. So, let's say my counter is at 100 and a bang occurs causing 4 input captures. As soon as the input capture happens the counter value at that instance is stored in the respective channels CCRx Register.(let's say CCR1 stores 100,CCR2 stores 103, CCR3 stores 104,CCR4 stores 107) Once I get these 4 values I have to find the time between the first input capture and the rest of the input capture.

Eg- CCR2-CCR1=103-100 ; CCR3-CCR1=104-100; CCR4-CCR1=107-100;

As shown above there isn't a problem when these input captures happen at the 100th count. But when it happens at 65520 I get values such as 65520,65525,65535,5. In this scenario, the lowest value I get is actually the event that takes place last and because of the huge difference I don't get a proper answer. I can't use the overflow flag because the event can occur at any time. Even after 5 times it has overflown. The counter is always on and keeps on counting and the event(bang) can occur at any time. The maximum difference possible between the input captures is only 30 counts.

Is there some smart solution to this problem or I should write a code to actually identify this series of numbers and subtract numbers with 655xx with 65536 and numbers from 0 to 20 with 0 and then add the absolute differences?

\$\endgroup\$
7
  • \$\begingroup\$ could you please edit your question and its title, and start off by stating: (1) the purpose of your design, then (2) the way you intend the design to achieve it, and then (3) the actual problem - rather than starting with the implementation, and expecting the reader to somehow divine the intended function from your description of the problem. This is just too much hard work. \$\endgroup\$
    – danmcb
    Commented Oct 19, 2023 at 11:21
  • \$\begingroup\$ @danmcb I have mentioned the actual problem i am stuck on. Mentioning purpose will become too lengthy as it is a part of a bigger project. I dont have any intended way to achieve thats why i am here asking a question. Basically i just want to counter the overflow problem while subtraction. \$\endgroup\$
    – user351626
    Commented Oct 19, 2023 at 11:43
  • \$\begingroup\$ ok, fair comment. But I still think you could state your problem (and give it a title) more succintly - something like "how to measure time intervals on a microcontroller and handle timer overflows", something like that. It takes other people time and mental energy to read your description, so you should be as clear and succinct as you can. You could then in your first para say something like "I am using a uC to try to measure the time intervals between loud sounds detected with a microphone and comparator". Start with some context. \$\endgroup\$
    – danmcb
    Commented Oct 19, 2023 at 12:24
  • \$\begingroup\$ "The maximum difference possible between the input captures is only 30 counts." --- this is a pretty important part of the problem, why do you only mention it until almost the end of your post? \$\endgroup\$
    – danmcb
    Commented Oct 19, 2023 at 13:19
  • 1
    \$\begingroup\$ @danmcb Now even when i am reading it seems a little out of context. Ill make these changes...thank you . \$\endgroup\$
    – user351626
    Commented Oct 19, 2023 at 13:23

1 Answer 1

1
\$\begingroup\$

Since you have a free running timer which restarts from zero after reaching 65535 (2^16-1), you are actually doing modular arithmetic. This means that when you subtract two values from each other you implicitly get two possible answers, and of the two you need to pick the one with a smaller absolute value.


Signed answer

Consider the following code:

#define PERIOD 65536
int32_t diff = (int32_t)a - b;
int32_t result = (diff + (PERIOD + PERIOD / 2)) % PERIOD - PERIOD / 2;

If a is from an event which happened after b, result will be positive, otherwise result will be negative. Note that this only works if the maximum possible delay between the two is less than half of the timer period. If you have delays greater than that, you will get results with the opposite sign and wrong magnitude. result will be a value in the right-open interval
[-PERIOD / 2, PERIOD / 2).
For example, if PERIOD is 65536 like above, -32768 ≤ result < 32768.


Unsigned answer

If you impose an additional constraint that a is guaranteed to always happen after b, you can use slightly different code:

#define PERIOD 65536
int32_t diff = (int32_t)a - b;
uint32_t result = (diff + PERIOD) % PERIOD;

Now the maximum possible delay between the two can be up to the full timer period. Reflecting that, result will be a value in the right-open interval [0, PERIOD).
For example, if PERIOD is 65536 like above, 0 ≤ result < 65536.


To illustrate how the first (signed) version of code works with a practical example, let's say capture a is 65515, capture b is 65530 and capture c happens 10 counts later still, so it will wrap around to a value of 00004 (given how the timer restarts from 0 upon reaching 65565).

Calculating b - a you would get
diff = 65530 - 65515 = 15
result = (15 + 98304) mod 65536 - 32768;
result = 98319 mod 65536 - 32768;
result = 32783 - 32768;
result = 15;

Calculating a - b you would get
diff = 65515 - 65530 = -15
result = (-15 + 98304) mod 65536 - 32768;
result = 98289 mod 65536 - 32768;
result = 32753 - 32768;
result = -15;

Calculating c - b you would get
diff = 4 - 65530 = -65526
result = (-65526 + 98304) mod 65536 - 32768;
result = 32778 mod 65536 - 32768;
result = 32778 - 32768;
result = 10;

Calculating b - c you would get
diff = 65530 - 4 = 65526
result = (65526 + 98304) mod 65536 - 32768;
result = 163830 mod 65536 - 32768;
result = 32758 - 32768;
result = -10;


A further note about your code:
TIM1 is a 16-bit timer. You can't set a 16 bit register (ARR) to
65536, as that is a 17 bit value. If you write 65536 anyway it will get masked to 0 and you end up with 0 in ARR. It might work anyway, with the maximum possible period, depending how the timer hardware is implemented. For a properly defined period of 65536 you need to set ARR to 2^16 - 1 = 65535.

\$\endgroup\$
8
  • \$\begingroup\$ if A reads 65530 and B reads 10, how do you know whether A occurred first and the diff is 15, or B happened first and the diff is 65520 ? \$\endgroup\$
    – danmcb
    Commented Oct 19, 2023 at 13:06
  • \$\begingroup\$ @danmcb the maximum count difference is 30 per opening post. \$\endgroup\$
    – Arsenal
    Commented Oct 19, 2023 at 13:12
  • \$\begingroup\$ @jms where is that stated? (OK, I see it now ... should have been at the very start.) \$\endgroup\$
    – danmcb
    Commented Oct 19, 2023 at 13:17
  • \$\begingroup\$ @danmcb As I wrote in my answer: "you get two possible answers, and you need to pick the smaller of the two". Smaller in absolute value, that is. So if the set of solutions is {15, -65520} you pick 15, and if it's {-15, 65520} you pick -15. \$\endgroup\$
    – jms
    Commented Oct 19, 2023 at 13:36
  • \$\begingroup\$ @danmcb This code only supports resolving delays up to half of a timer period, with the possible results ranging from -period/2 to period/2. If you were to add an additional constraint that a must always happen before b, then you can use slightly different code to unambiguously calculate elapsed delays between 0 and a full period. You can't write code that achieves both. \$\endgroup\$
    – jms
    Commented Oct 19, 2023 at 13:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.