cancel
Showing results for 
Search instead for 
Did you mean: 

STM32CubeIDE V1.7.0, modulo arithmetic => Compiler Error?

ULehm.1
Associate III

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.

11 REPLIES 11
KnarfB
Principal III

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

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..

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

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).

TDK
Guru

Compiler error? Or unexpected result? I don’t see any error messages listed.

If you feel a post has answered your question, please click "Accept as Solution".

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?

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.

Consider the 32-bit DWT->CYCCNT for a coherent/complete number space when you shift and truncate to 16-bit

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Piranha
Chief II

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.