Home > ARM, Кодинг, Контроллеры, Mac OS X, stm32 > How to use sprintf function in stm32f4xx firmware

How to use sprintf function in stm32f4xx firmware

Sometimes you need to implement pretty output to USART. This task can be solved in two ways:

  • Write your own converters from int or double to char*
  • Use sprintf and printf

Second way is better. I will use sprintf(str, ...) and write simple loop that will send str byte-by-byte to USART.

I use mac os x + eclipse + arm-none-eabi + openocd + stm32f4discovery.
Let’s start implementing this.

We are going to make this code run.

  1. int k = 34;
  2. double j = 45.76;
  3. uint8_t s[255];
  4. int size = sprintf(s, “Hi from MCU! %d %f”, k, j);

Also do not forget to include "stdio.h".

Compilation will fail with error:

...arm-none-eabi/lib/armv7e-m/libc.a(lib_a-sbrkr.o): In function `_sbrk_r':
sbrkr.c:(.text._sbrk_r+0xc): undefined reference to `_sbrk'

You have to implement _sbrk function. This function is used in memory allocation processes. And it’s not implemented in standard libs because it fully depends on hardware.

On the top of your file where you plan to use sprintf add this include:

  1. #include <errno.h>

And than add declaration of _sbrk function.

  1. caddr_t _sbrk(int incr)
  2. {
  3.   extern char _ebss; // Defined by the linker
  4.   static char *heap_end;
  5.   char *prev_heap_end;
  6.   if (heap_end == 0)
  7.   {
  8.     heap_end = &_ebss;
  9.   }
  10.   prev_heap_end = heap_end;
  11.   char * stack = (char*) __get_MSP();
  12.   if (heap_end + incr > stack)
  13.   {
  14.     errno = ENOMEM;
  15.     return (caddr_t) 1;
  16.   }
  17.   heap_end += incr;
  18.   return (caddr_t) prev_heap_end;
  19. }

This will solve 99% of problems. But i am a lucky guy, so this code did not work for me.
Debugger shows, that after execution of fprintf(..) function my stm32 falls to infinite loop in startup_stm32f30x.S file. Or, core falls to hard fault.

  1. /**
  2.  * @brief This is the code that gets called when the processor receives an
  3.  *        unexpected interrupt. This simply enters an infinite loop, preserving
  4.  *        the system state for examination by a debugger.
  5.  *
  6.  * @param None
  7.  * @retval : None
  8. */
  9.   .section .text.Default_Handler,“ax”,%progbits
  10. Default_Handler:
  11. Infinite_Loop:
  12.   b Infinite_Loop
  13.   .size Default_Handler, .Default_Handler

This means that sprintf throws some exceptions, for example do not allocate memory correctly. You should go to the Project -> Properties -> C/C++ Build -> Settings. Open "Tool Settings" tab, click on the "Target Processor" line in the left side of this window. Than set "Float ABI" be equal to "Toolchain default". Now sprintf will work fine.

References

  1. syscalls.c
  2. http://stackoverflow.com/questions/5948647/newlib-sscanf-throw-hardfault-exception-in-stm32
Advertisements
  1. bahadir
    07.01.2016 at 15:15

    not a good idea. costs +10k code space

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: