Reply
Posts: 11
Registered: ‎04-19-2017

bgm121 example project snprintf broken

Hi, I've tried running a bluetooth sdk example (temperature sensor) on a BGM121 evaluation board. Everything works fine except that temperature values that are shown on the LCD is garbage.

 

I did some debugging and problem seems to be with the "snprintf" function that is used to format the "float" values into string. Looking at some of the similar postings here, I've tried selecting the newlib C library and enabling the float printf support from the linker options . But none of the options worked.

 

I've also tried giving some constant float values to the snprintf function. For example when I give it "0.0" it's formatted correctly as "0.0". But no other number is formatted correctly. Small numbers (<10.0 exp.) are formatted as "0.0", bigger numbers (~20.0) produce garbage numbers like "23242985423423".  This leads me to believe that it understand the float format specifier. Could this be caused by stack overflow/corruption?

 

Relevant line from the example project:

 

  /* Temp in C and F should both appear on LCD display */
  snprintf(tempString, HTM_TEMP_VALUE_TEXT_SIZE, HTM_TEMP_VALUE_TEXT, tempC, tempC * 1.8 + 32.0);

I'm using GCC ARM compiler.

Posts: 557
Registered: ‎09-18-2015

Re: bgm121 example project snprintf broken

Hi @hyOzd,

 

I believe Bluetooth stack code still needs to be compiled with IAR as GCC support is forthcoming later this year.

 

This being the case, the example probably does not work because there are differences in how stdio functions are compiled/linked between IAR and GCC.

 

Try building the code with IAR (you may need the eval license if you do not already have an IAR license) and see what happens as that is what we used for development and testing.

 

You might want to check out our Getting Start Guide for more details.

 

John

Posts: 11
Registered: ‎04-19-2017

Re: bgm121 example project snprintf broken

@JohnBThanks for your response. I'm working on linux, unfortunately IAR is not an option for me. Everything else, except this printf, worked fine with GCC. I can connect to bluetooth and see the temperature values via the smartphone app. I hope you can support gcc sooner.

Posts: 557
Registered: ‎09-18-2015

Re: bgm121 example project snprintf broken

Hi @hyOzd,

 

Since you've gotten that far, don't let this stop you!

 

There are command line flags necessary for GCC to support floats in stdio accordingly to one of my co-workers. It would be worth doing some searching on Google to see what they might be and then adding them to the project properties.

 

Alternatively, consider converting the values to integers (e.g. milli deg C) and trying different variations of printf/sprintf to see what happens.

 

I suspect everything underlying the example is working and that you are mostly just falling prey to different implementations of stdio functions in IAR vs. GCC.

 

John

Posts: 74
Registered: ‎09-03-2015

Re: bgm121 example project snprintf broken

Hi @hyOzd

 

When printing floats with newlib nano which is used with armgcc you can provide the linker option "-u _printf_float"

 

I found some documentation on this option here:

https://github.com/32bitmicro/newlib-nano-1.0/blob/master/newlib/README.nano

 

Do you see a difference in your map file when you add that linker option?

Posts: 557
Registered: ‎09-18-2015

Re: bgm121 example project snprintf broken

Thanks @kjostera!

 

I didn't know the flag off the top of my head, but @ChrisM mentioned he'd run into something like this before and GCC needed a flag to incorporate printf float support.

 

John

Posts: 11
Registered: ‎04-19-2017

Re: bgm121 example project snprintf broken

@kjosteraI have tried that option. It didn't work. I will check the MAP file as you suggested.

 

@JohnBI've also tried "sprintf", no luck. I've tried increasing the heap and stack size (via compile time defines __HEAP_SIZE, __STACK_SIZE) but that didn't work either.

 

Posts: 11
Registered: ‎04-19-2017

Re: bgm121 example project snprintf broken

@kjostera  I've checked the MAP file and indeed there is some difference. It seem to me that library with float support is correctly linked. I've uploaded the map files here: https://gist.github.com/hyOzd/9b29597b09248c30e070881595f00353

 

When float support is disabled nothing is formatted though. Output is simply missing any numbers.

 

By the way I've also tried integer formatting and it works as expected.

Posts: 74
Registered: ‎09-03-2015

Re: bgm121 example project snprintf broken

Hi @hyOzd

 

I'll try to dig into the newlib code to see what is going on. Do you get the same errors if you use printf with floats as when you do snprintf with floats?

Posts: 11
Registered: ‎04-19-2017

Re: bgm121 example project snprintf broken

@kjosteraI think I have to enable SWO to be able to see printf output. I'm new to this platform. This will take some time : )

Posts: 11
Registered: ‎04-19-2017

Re: bgm121 example project snprintf broken

@kjosteraI take that back. It wasn't hard : D I've enabled SWO and observed that printf also has the same problem. Here is some example output:

Temperature:
-2.0 C / -0.0 F

Temperature:
26815615861041660897194016318624084531639826241354963212392740604758476638949656335295240634236384165689486644417324415125047746191574229439661745364795392.0 C / -272008374398648678612992.0 F

Temperature:
-0.0 C / 26815622276915611214692786152111585528179178826842844971506520371043033645953305192872570477225224303088270800635122717164976038059579834338011966034935808.0 F

Temperature:
-2.0 C / -0.0 F

Temperature:
-0.0 C / -2855074848836934119218683270104310421723327173544912560392770365623200097284446155120419593853373011786685712959046332144844358297731248368276265344259611565666889042266701720769191987432105233534168253359020916085508314742107787600449014107164969298237406275761295122519500184652611584.0 F

Temperature:
-0.0 C / 26815622276915611214692786152111585528179178826842844971506520371043033645953305192872570477225224303088270800635122717164976038059579834338011966034935808.0 F

Temperature:
-0.0 C / 26815622276915611214692786152111585528179178826842844971506520371043033645953305192872570477225224303088270800635122717164976038059579834338011966034935808.0 F

Temperature:
26815615861041660897194016318624084531639826241354963212392740604758476638949656335295240634236384165689486644417324415125047746191574229439661745364795392.0 C / -272008374398648678612992.0 F

Temperature:
26815615861041660897194016318624084531639826241354963212392740604758476638949656335295240634236384165689486644417324415125047746191574229439661745364795392.0 C / -272008374398648678612992.0 F

Temperature:
26815615861041660897194016318624084531639826241354963212392740604758476638949656335295240634236384165689486644417324415125047746191574229439661745364795392.0 C / -272008374398648678612992.0 F

Temperature:
26815615861041660897194016318624084531639826241354963212392740604758476638949656335295240634236384165689486644417324415125047746191574229439661745364795392.0 C / -272008374398648678612992.0 F

Temperature:
-2.0 C / -0.0 F

Temperature:
26815615861041660897194016318624084531639826241354963212392740604758476638949656335295240634236384165689486644417324415125047746191574229439661745364795392.0 C / -272008374398648678612992.0 F

Temperature:
-0.0 C / -2855074848836934119218683270104310421723327173544912560392770365623200097284446155120419593853373011786685712959046332144844358297731248368276265344259611565666889042266701720769191987432105233534168253359020916085508314742107787600449014107164969298237406275761295122519500184652611584.0 F

Temperature:
26815615861041660897194016318624084531639826241354963212392740604758476638949656335295240634236384165689486644417324415125047746191574229439661745364795392.0 C / -272008374398648678612992.0 F
Posts: 74
Registered: ‎09-03-2015

Re: bgm121 example project snprintf broken

Hi @hyOzd

 

If you are using our WSTK or STK's then I find that the easiest way to add stdio output support is to use the Virtual COM port on the kit together with our retargeting drivers. Just add retargetio.c and retargetserial.c to your project and add a the RETARGET_VCOM macro to your project (-DRETARGET_VCOM). Then you can initialize it like this:

 

  RETARGET_SerialInit();
  RETARGET_SerialCrLf(1);

After that all the printf output will end up on VCOM. We also have retargeting drivers for SWO and the memory lcd if you want to use that.

Posts: 11
Registered: ‎04-19-2017

Re: bgm121 example project snprintf broken

@kjosteraI've used code from this sample project to enable SWO. I will try your suggestions as well.

 

I can see the printf output in IDE. But "printf" also doesn't work. Here is some example output.

Temperature:
-0.0 C / -26815622275517848015484184817889116294296378170954319172726838254221387725634594835801762106018479426810052073085056013214570526728581580914868722291703808.0 F

Temperature:
-0.0 C / -26815622275517848015484184817889116294296378170954319172726838254221387725634594835801762106018479426810052073085056013214570526728581580914868722291703808.0 F

Temperature:
-0.0 C / 2855074848712916978034585853523098657214174900164613150605790838303661320840434456495228433091753560967058188100771517920177247340363617278683009914390047540472713976587457946700425543923495509759627146321823477410305738264234037958725584988972655626251844462905375940653756189543235584.0 F

Temperature:
-2.0 C / 0.0 F

Temperature:
-0.0 C / -26815622275517848015484184817889116294296378170954319172726838254221387725634594835801762106018479426810052073085056013214570526728581580914868722291703808.0 F

Temperature:
-2.0 C / 0.0 F

Temperature:
-2.0 C / -0.0 F

Temperature:
-2.0 C / -0.0 F

PS: Actually I've sent a reply an hour ago but I don't see it now.

 

Posts: 248
Registered: ‎11-17-2013

Re: bgm121 example project snprintf broken

Don't bother. Float support of all printf() variants in newlib (C library shipped with GCC) is broken, because it would need a working heap (read: malloc).

 

You will need to work around that by either printing just integers in a clever way or search for another open source (s)printf() implementation that works with float and double.

Posts: 11
Registered: ‎04-19-2017

Re: bgm121 example project snprintf broken

Huh.. I understand.

 

But this example project defines a "heap" in the startup file (with below line), if not for "malloc" what is it for? I'm not interested in a formatter that requires dynamic memory allocation, I'm just curious.

 

static uint8_t heap[__HEAP_SIZE]   __attribute__ ((aligned(8), used, section(".heap")));
Posts: 3,093
Registered: ‎02-07-2002

Re: bgm121 example project snprintf broken

But what value is __HEAP_SIZE?

Posts: 11
Registered: ‎04-19-2017

Re: bgm121 example project snprintf broken

@vanmierloIf I remember correctly it was 0x300 (3072) by default. I've tried increasing it a bit (to 0xD00) but nothing changed.

 

I've also tried to utilize "malloc" function to see if it works. But code got optimized away without warnings.

Posts: 557
Registered: ‎09-18-2015

Re: bgm121 example project snprintf broken

Hi folks,

 

@ChrisM might be able to comment here about malloc().  It popped up in a conversation at one point, and I'm either thinking he said it was broken (?) or maybe am just conflating his comments with someone else's Smiley LOL

 

John

Posts: 492
Registered: ‎02-04-2013

Re: bgm121 example project snprintf broken

For GCC at least, you need to implement the sbrk() function to allocate memory on the heap using malloc().  This implementation is not always included depending on which sample code you use.

 

Best regards,

Chris

Posts: 11
Registered: ‎04-19-2017

Re: bgm121 example project snprintf broken

@ChrisMThank you for your response. I've tried this implementation of _sbrk just to see what would happen.

 

caddr_t _sbrk(int incr) {
  extern char _end;		/* Defined by the linker */
  extern char __stack;
  static char *heap_end;
  char *prev_heap_end;

  if (heap_end == 0) {
    heap_end = &_end;
  }
  prev_heap_end = heap_end;
  if (heap_end + incr > &__stack) {
    write (1, "Heap and stack collision\n", 25);
    abort ();
  }

  heap_end += incr;
  return (caddr_t) prev_heap_end;
}

It seems that printf is requesting memory around 4k. Obviously it didn't work.

 

But I'm still confused what happens when I don't provide the _sbrk function? Is there a dummy function somewhere that is used instead?

Posts: 492
Registered: ‎02-04-2013

Re: bgm121 example project snprintf broken

I believe we have a very minimal sbrk() implementation in one of the lower level SDK files (or maybe there's one in stdlib if you don't define one).  You should do a find in files search to find it.  Generally it doesn't handle the case where HEAP > STACK so you will run into problems if this happens.

 

I think by default it does start allocating memory at the HEAP section space.  Check the address of the pointer returned by the first malloc() call in your program.

 

Best regards,

Chris

Posts: 3,093
Registered: ‎02-07-2002

Re: bgm121 example project snprintf broken

I wonder where _end and __stack are located. The code you show seems to suggest that neither take __HEAP_SIZE nor __STACK_SIZE into account. As far as I can see __stack is at the start of the stack which grows downward. And _end starts at the bottom of the heap which grows upward. So it only checks if the heap outgrows stack+heap space and doesn't prevent overwriting the stack.

 

The implementation in SiLabs retargetio.c compares against MSP which is a bit better, but still doesn't prevent the master stack to later grow into the heap. I would also check against either __HeapLimit or __StackLimit if I were you. Safest would be if we could trigger some event on the stack pointer reaching the top of the heap, so we could at least capture such a failure.

 

One can also wonder why printf needs so much heap space. I can imagine it needs some, but 4kB seems overly conservative.

Posts: 11
Registered: ‎04-19-2017

Re: bgm121 example project snprintf broken

@vanmierlo  Thank you for clarifying. I actually misunderstood the linker file. I've changed my code to use __HeapLimit.

The thing is; I define the heap size as 0x1500 (5376) and check that sbrk doesn't fail by setting a break point. But printf still doesn't work (prints garbage).

 

I've also noticed that call pattern to the _sbrk function is this:

 

incr = 156

incr = 16

incr = 4096

 

This only happens when measurements start. I guess at first call to the "snprintf" function. I guess because for some reason debugger doesn't list the full stack frame when stopped in the "_sbrk" function.

 

Is it possible that it's not the snprintf requesting exactly 4KiB memory but malloc tries to reserve extra space?

 

Posts: 3,093
Registered: ‎02-07-2002

Re: bgm121 example project snprintf broken

I don´t know. But instead of looking at the stack frame you can also try to step out of the function in the hope to see where it came from.

Posts: 3,093
Registered: ‎02-07-2002

Re: bgm121 example project snprintf broken

To be honest I hardly ever use printf with floats on an embedded platform. Instead I´ve written a function to print floats in SI style which always prints a sign, 4 digits, one dot and a metric prefix.