2021-10-01 05:41 AM
Since 25 years I use functions or macros like
#define usTimeRead() ((int16_t) (SysTick->VAL >> 1))
#define usTimePlus(TP, US) ((int16_t) TP - ((int16_t) US * (int16_t) 85))
#define usTimePast(TP) (((int16_t) TP - usTimeRead()) > (int16_t) 0)
to create timeouts or to do periodical jobs on 16bit MCUs.
Porting them to STM32G4, the following code should result in a 100us square wave generated at pin B6.
int main(void) {
sysConfigMCU();
/* Loop */
int16_t tp = usTimeRead();
for(;;) {
GPIOB->BSRR = ((uint16_t)0x0040);
tp = usTimePlus(tp, 100);
for ( ; !usTimePast(tp); );
GPIOB->BRR = ((uint16_t)0x0040);
tp = usTimePlus(tp, 100);
for ( ; !usTimePast(tp); );
}
}
This doesn't work - I have to change the macro usTimePast(TP) assigning the difference to temporary variable to get the program running correctly.
#define usTimePast(TP) ((tmp = (int16_t) TP - usTimeRead()) > (int16_t) 0)
I've simulated this behaviour with TDM-GCC with the same result - for values like
usTimeRead() == -32703 and tp == 32735 the compare in usTimePast(TP) will produce differnt results depending on weather the difference of the left side of compare will be assinged to a temporary variable or not!
Using Microsoft Visual Studio will prodece in both cases (with and without aasigning the difference to a temporary variable) the behaviour i know from 16bit MCUs and their compilers.
2021-10-01 06:46 AM
What is the type of tmp?
> Using Microsoft Visual Studio will prodece in both cases
Really?
#include <stdint.h>
#include <stdio.h>
int main(void)
{
printf("%d\n", (int16_t)32767 - (int16_t)(-32767));
int16_t tmp;
printf("%d\n", tmp = (int16_t)32767 - (int16_t)(-32767) );
}
yields different results (65534 rsp. -2).
For me, using usigned data types is much easier because a clean modulus computation is involved.
hth
KnarfB
2021-10-01 07:03 AM
SysTick is a 24 bit unsigned down counter, and it's not even full-span in most use cases.
Typically people use maximal, free-running, 16 or 32-bit up counters. And don't precompute the target, but rather compute the delta time and see if that exceeds the elapsed time..
2021-10-01 08:04 AM
tmp's type is also int16_t.
Tests with Microsoft Visual Studio has been done by a friend - he reported, the output signal will not toggle in the data file like in my data file,
when cnt24b reaches -32703.
# usTick cnt24b nextTp output
: : : :
32699 -32700 -32701 0
32700 -32701 -32701 0
32701 -32702 -32701 0 <===
32702 -32703 32735 10000
32703 -32704 32635 0
32704 -32705 32535 10000
32705 -32706 32435 0
32706 -32707 32335 10000
32707 -32708 32235 0
32708 -32709 32135 10000
32709 -32710 32035 0
32710 -32711 31935 10000
I will check using unsigned arithmetic next week (the compare has to be a signed compare).
Inspired by yout test I will also check, if casting the difference of two int16_t again to int16_t will also solve the problem -
yout test implies, that the difference of two int16_t isn' t treaded as an int16_t (at least, when an underflow or overflow
has been ocured).
2021-10-01 08:16 AM
Compiler error? Or unexpected result? I don’t see any error messages listed.
2021-10-01 08:23 AM
Ok - casting the difference again to int16_t is enough to get the same behaviour like assigning the difference to an int16_t temporary variable!
Wth STM32 compiler as well as with the TDM-GCC compiler.
It seems, the difference of two int16_t does not have to be an int16_t?
2021-10-01 08:32 AM
Right, the difference is an int, this is integer promotion in C. By casting or assigning it to an int16_t, the result gets truncated to int16_t.
2021-10-01 09:01 AM
Consider the 32-bit DWT->CYCCNT for a coherent/complete number space when you shift and truncate to 16-bit
2021-10-01 01:04 PM
2021-10-01 03:20 PM
This math will only be correct on underflows, when SysTick period is set to a multiple of 2^17 clock cycles, which is almost never the case.
int16_t tp = usTimeRead();
tp = usTimePlus(tp, 100);
for ( ; !usTimePast(tp); );
The loop is effectively a simple while loop. And the whole logic can be implemented as a single (probably static inline) function to not have to repeat the same set of code lines over and over again.