stm32duino core with System Workbench for bluepill

Development environment specific, Arduino, Eclipse, VS2013,Em::Blocks etc
User avatar
Rick Kimball
Posts: 754
Joined: Tue Apr 28, 2015 1:26 am
Location: Eastern NC, US
Contact:

Re: Eclipse importable bluepill project

Postby Rick Kimball » Wed Dec 07, 2016 5:37 pm

Looking at detail of the _init() function we see it is provided by newlib if we were linking with the stdlib libraries.

Code: Select all

0800328c <_init>:
 800328c:       b5f8            push    {r3, r4, r5, r6, r7, lr}
 800328e:       bf00            nop
 8003290:       bcf8            pop     {r3, r4, r5, r6, r7}
 8003292:       bc08            pop     {r3}
 8003294:       469e            mov     lr, r3
 8003296:       4770            bx      lr

In the project linker settings I had selected "No startup or default libs (-nostdlib)", but I also provided the --specs=nano.specs so if it really needs some stdlib code it is going to grab it from the list of libraries in that spec. However the libc function __libc_init_arrray() does actually call _init(), so I had to provide something. The default_init() function appears to just be a nop function. This function is meant to be a hook for operating systems to perform any initialization. For us, I think we should use it to our advantage to initialize the board hardware.

Maybe the _init() function should be more like:

Code: Select all

void _init(void) {
   extern void init(void); // from boards.cpp .. would have to be defined as extern "C" { void init(void) } in boards.h
   // we could be initializing the RCC clock/PLL etc and the peripheral clocks
   // before the global c++ constructors are called.
   // calling board
   init(); // init function from boards.cpp
}

That way the underlying hardware is properly configure before any c++ ctors are run.

Or we could just rename void init() in boards to _init() in boards.cpp and make sure it has 'C' binding instead of C++.

-rick

[Edit]

BTW: __libc_init_array looks something like this:

Code: Select all

   extern void (*__preinit_array_start[])(void);
   extern void (*__preinit_array_end[])(void);
   extern void (*__init_array_start[])(void);
   extern void (*__init_array_end[])(void);

   {
      unsigned int i, cnt;
      //
      // call any global c++ ctors
      //
      cnt = __preinit_array_end - __preinit_array_start;
      for (i = 0; i < cnt; i++)
         __preinit_array_start[i]();
         
      _init();

      cnt = __init_array_end - __init_array_start;
      for (i = 0; i < cnt; i++)
         __init_array_start[i]();
   }

[/Edit]

[Edit2]
__libc_init_array() actually comes from libc

.text.__libc_init_array
0x00000000080031b8 0x50 /home/kimballr/.arduino15/packages/arduino/tools/arm-none-eabi-gcc/4.8.3-2014q1/bin/../lib/gcc/arm-none-eabi/4.8.3/../../../../arm-none-eabi/lib/armv7-m/libc.a(lib_a-init.o)
0x00000000080031b8 __libc_init_array
[/Edit2]
Last edited by Rick Kimball on Mon Apr 17, 2017 5:05 pm, edited 2 times in total.
-rick

robertkendrick
Posts: 2
Joined: Wed Nov 30, 2016 5:08 pm

Re: Eclipse importable bluepill project

Postby robertkendrick » Wed Dec 07, 2016 11:10 pm

Thanks for taking the time to write this.

Yes, I was running the System Workbench compiler. So, as usual, most of my problems were self inflicted.

Point also taken about the openocd cfg file. I had searched the project files (the xml) and puzzled as to why there were no mention of debugging tools and settings. Assume they are setup via eclipse plugins.

ag123
Posts: 318
Joined: Thu Jul 21, 2016 4:24 pm

Re: stm32duino core with System Workbench for bluepill

Postby ag123 » Mon Apr 17, 2017 11:12 am

hi all,

i'm using eclipse (actually without Sloeber) i'm setting the defines by manually defining them using platforms.txt and boards.txt as a reference. tedious but it works.

ot: >> it isn't system workbench either it is gnu arm eclipse http://gnuarmeclipse.github.io. looking at the first post, i think system workbench is literally a better setup to work in and after all that is created by ST itself if i'm right about it. gnu arm eclipse is in perspective a 'public 3rd party effort', the environment is possibly similar to system workbench, the developer(s) of gnu arm eclipse developed several stm32 code 'generators' for creating blinky projects for some non st boards, notably from olimex, has a qemu emulator that sport several boards some from olimex and targets stm32 f1 and f4 targets but the features are incomplete (e.g. i think interrupt priorities currently won't work) and hence only basic emulation functionality) and segger j-link and openocd connectivity <<

here is how i've tixed the issues

utoa() issue

as mentioned by rick
https://github.com/arduino/Arduino/pull/4830/files
this is simply because the later gcc versions delivered a utoa() function that has a somewhat different declaration

in my local copy of STM32F1/cores/maple/itoa.h

Code: Select all

#define GCC_VERSION (__GNUC__ * 10000 \
                     + __GNUC_MINOR__ * 100 \
                     + __GNUC_PATCHLEVEL__)

#if !(GCC_VERSION > 40902)
extern char* utoa( unsigned long value, char *string, int radix ) ;
#endif

and STM32F1/cores/maple/itoa.c

Code: Select all

#if !(GCC_VERSION > 40902)
extern char* utoa( unsigned long value, char *string, int radix )
{
  return ultoa( value, string, radix ) ;
}
#endif


i.e. if gcc version is > 40902, i simply use the definition from newlib, note that i did not substitute an extern declaration as suggested in the Arduino's git

missing _init() - note superceeded, this is 'not a problem'

it turns out _init() is possibly intended for shared library initialization (e.g. in linux) and newlib does not ship with that,
http://dbp-consulting.com/tutorials/deb ... artup.html
i noted that newlib provides void __libc_init_array() but does not provide _init()

i discussed it in some details here viewtopic.php?f=41&t=655&start=80#p25978

the only trouble is that this is part of the variant start up codes, hence, we'd need to patch every variant if we want to fix the missing _init()

in my local copy
STM32F1/variants/maple_mini/wirish/start_c.c

Code: Select all

extern void _init (void); //declaration

void _init () {}


i'm of an opinion that we'd leave _init() as void _init() {}; as we do have init() called in STM32F1/cores/maple/main.cpp

Code: Select all

// Force init to be called *first*, i.e. before static object allocation.
// Otherwise, statically allocated objects that need libmaple may fail.
 __attribute__(( constructor (101))) void premain() {
    init();
}

int main(void) {
    setup();

    while (1) {
        loop();
    }
    return 0;
}

and in STM32F1/variants/maple_mini/wirish/boards.cpp

Code: Select all

void init(void) {
    setup_flash();
    setup_clocks();
    setup_nvic();
    systick_init(SYSTICK_RELOAD_VAL);
    wirish::priv::board_setup_gpio();
    setup_adcs();
    setup_timers();
    wirish::priv::board_setup_usb();
    wirish::priv::series_init();
    boardInit();
}


i've been trying to figure out how premain gets called but with my limited tools (eclipse + gnu arm eclipse + qemu) i noted that the call stack is
start_c() > __libc_init_array() > premain() > init()

note that arduino ide 1.8.2 with the current sam plug in (which delivers arm gcc) don't seem to need these fixes, sketches compile without hitting those errors. hence we can leave it till it happens.

if everyone is keen on the fixes as suggested above i can check out roger's repository and submit a pull request. note that on the caveat emptor norm, i won't be able to test this on 'all boards' and my fixes may actually lead to a missing utoa() since i deliberately coded based on arduino's implementation hint that it should be there if gcc_version > 4.9.2

i'm a little worried that the fixes may accidentally break existing compiles (e.g. with current arduino ide)

note _init() issue is superseded: the _init() issue isn't correctly analysed, it is superseded with further findings that the fix is basically that --nostdlibs should not be stated in the compile options, and that --specs=nano.specs (use newlib-nano) may be specified if it helps
viewtopic.php?f=41&t=1054&p=26498#p26507
Last edited by ag123 on Mon Apr 17, 2017 4:01 pm, edited 5 times in total.

User avatar
Rick Kimball
Posts: 754
Joined: Tue Apr 28, 2015 1:26 am
Location: Eastern NC, US
Contact:

Re: stm32duino core with System Workbench for bluepill

Postby Rick Kimball » Mon Apr 17, 2017 12:03 pm

ag123 wrote:...
the only trouble is that this is part of the variant start up codes, hence, we'd need to patch every variant if we want to fix the missing _init()

You don't have to patch each variant. You just have _init() call init().

Also, I think the right place to define the init() function is in the variant startup code. The intent of this function is to prepare the hardware for use before any constructor functions are called. If you have a board that has specific hardware that needs to be configured before you call any constructors then you want it to be a variant feature not a feature of the core. The way the code is invoked now isn't exactly right.
// Force init to be called *first*, i.e. before static object allocation.
// Otherwise, statically allocated objects that need libmaple may fail.
__attribute__(( constructor (101))) void premain() {
init();
}


The declaration uses an attribute feature with a number to try and force that code to be the first constructor run. However, that is just a hack. If you want to be sure all you have to do is put the code you want to run before the other constructors in a function called _init() and it will run first. No guessing.

-rick
-rick

ag123
Posts: 318
Joined: Thu Jul 21, 2016 4:24 pm

Re: stm32duino core with System Workbench for bluepill

Postby ag123 » Mon Apr 17, 2017 12:50 pm

thanks rick,
i did find init() in STM32F1/variants/maple_mini/wirish/boards.cpp
i.e. it is part of the variant

however, i can't figure out how premain() which calls init()
gets patched into __preinit_array

apparently in the newlib code the function __libc_init_array()
https://github.com/eblot/newlib/blob/ma ... isc/init.c
is defined as such:

Code: Select all

/* Handle ELF .{pre_init,init,fini}_array sections.  */
#include <sys/types.h>

#ifdef HAVE_INITFINI_ARRAY

/* These magic symbols are provided by the linker.  */
extern void (*__preinit_array_start []) (void) __attribute__((weak));
extern void (*__preinit_array_end []) (void) __attribute__((weak));
extern void (*__init_array_start []) (void) __attribute__((weak));
extern void (*__init_array_end []) (void) __attribute__((weak));

extern void _init (void);

/* Iterate over all the init routines.  */
void
__libc_init_array (void)
{
  size_t count;
  size_t i;

  count = __preinit_array_end - __preinit_array_start;
  for (i = 0; i < count; i++)
    __preinit_array_start[i] ();

  _init ();

  count = __init_array_end - __init_array_start;
  for (i = 0; i < count; i++)
    __init_array_start[i] ();
}
#endi


which means that premain() is patched into the array __preinit_array[] and is called by __libc_init_array(), hence the call stack or graph looks like
start_c() > __libc_init_array() > premain() > init()

User avatar
Rick Kimball
Posts: 754
Joined: Tue Apr 28, 2015 1:26 am
Location: Eastern NC, US
Contact:

Re: stm32duino core with System Workbench for bluepill

Postby Rick Kimball » Mon Apr 17, 2017 12:53 pm

ag123 wrote:missing _init()

it turns out _init() is possibly intended for shared library initialization (e.g. in linux) and newlib does not ship with that,
http://dbp-consulting.com/tutorials/deb ... artup.html
i noted that newlib provides void __libc_init_array() but does not provide _init()

i discussed it in some details here viewtopic.php?f=41&t=655&start=80#p25978

I'm pretty sure newlib started life as an embedded system thing.

https://en.wikipedia.org/wiki/Newlib
"Newlib is a C standard library implementation intended for use on embedded systems. It is a conglomeration of several library parts, all under free software licenses that make them easily usable on embedded products."

_init() is provided by newlib, it is in the crti.o object.
$ arm-none-eabi-objdump -CS ~/.arduino15/packages/arduino/tools/arm-none-eabi-gcc/4.8.3-2014q1/lib/gcc/arm-none-eabi/4.8.3/crti.o

~/.arduino15/packages/arduino/tools/arm-none-eabi-gcc/4.8.3-2014q1/lib/gcc/arm-none-eabi/4.8.3/crti.o: file format elf32-littlearm

Disassembly of section .init:

00000000 <_init>:
0: e1a0c00d mov ip, sp
4: e92ddff8 push {r3, r4, r5, r6, r7, r8, r9, sl, fp, ip, lr, pc}
8: e24cb004 sub fp, ip, #4

Disassembly of section .fini:

00000000 <_fini>:
0: e1a0c00d mov ip, sp
4: e92ddff8 push {r3, r4, r5, r6, r7, r8, r9, sl, fp, ip, lr, pc}
8: e24cb004 sub fp, ip, #4
-rick

User avatar
Rick Kimball
Posts: 754
Joined: Tue Apr 28, 2015 1:26 am
Location: Eastern NC, US
Contact:

Re: stm32duino core with System Workbench for bluepill

Postby Rick Kimball » Mon Apr 17, 2017 1:01 pm

ag123 wrote:however, i can't figure out how premain() which calls init()
gets patched into __preinit_array


premain() is just an arbitrary name, you can all it unclemonkeycode() and it will still get invoked.

The __attribute__( constructor ... ) is what puts it into the the ".init_array" section of the .elf file. All the .init_array sections are added to an array that is called by __libc_init_array(). By giving it a high number it is supposed to put that function in the array list before others with a lower number.

See the how the linker sections assembles the init array sections.

https://github.com/rogerclarkmelbourne/ ... on.inc#L87

Also it isn't actually in the ".preinit_array" section, it is just an arbitrary name roger decided to use for constructor code.
Last edited by Rick Kimball on Mon Apr 17, 2017 1:05 pm, edited 1 time in total.
-rick

ag123
Posts: 318
Joined: Thu Jul 21, 2016 4:24 pm

Re: stm32duino core with System Workbench for bluepill

Postby ag123 » Mon Apr 17, 2017 1:03 pm

thanks rick, it seemed then that in my case, i missed out to include a lib in my build path, let me check that on my end

wow, i've been tracing and tracing and i simply couldn't figure out where in the ld scripts, assembler files or c functions that premain() somehow gets into init_array :D
Last edited by ag123 on Mon Apr 17, 2017 1:09 pm, edited 1 time in total.

User avatar
Rick Kimball
Posts: 754
Joined: Tue Apr 28, 2015 1:26 am
Location: Eastern NC, US
Contact:

Re: stm32duino core with System Workbench for bluepill

Postby Rick Kimball » Mon Apr 17, 2017 1:08 pm

ag123 wrote:thanks rick, it seemed then that in my case, i missed out to include a lib in my build path, let me check that on my end :D

It should pick it up automatically if you have your flags set correctly. You shouldn't have to explicity include the crti.o code.

In my case, I explicitly turned off both the c startup code and the libc code. That is why I had to supply it. If you just add -specs=nano.specs, you will get a suitably small libc, which should provide the _init() and the __libc_init_array().
-rick

ag123
Posts: 318
Joined: Thu Jul 21, 2016 4:24 pm

Re: stm32duino core with System Workbench for bluepill

Postby ag123 » Mon Apr 17, 2017 1:13 pm

i run into a problem of 'fat binaries' and in an attempt to solve that i set the ld flags
--nostdlib no standard lib
-Xlinker --gc-sections remove unused sections
--specs=nano.specs use newlib-nano

i'm actually building using gcc-arm-none-eabi-6-2017-q1-update, so far it works
however, i get the error _init() is not defined if the above ld options are set
my guess is that --nostdlib overrides --specs=nano.specs and hence _init() is no longer included
however, without --nostdlib the binary size is considerably fatter even if --specs=nano.specs is stated
viewtopic.php?f=41&t=655&start=80#p25978

ok i discovered something about my gcc installation gcc-arm-none-eabi-6-2017-q1-update (this is actually 6.3.1 going by the path names i see)
in the installation folder gcc-arm-none-eabi-6-2017-q1-update/lib/gcc/arm-none-eabi/6.3.1

there are 2 crt*.o files: crti.o and crtn.o

Code: Select all

nm crti.o
00000000 T _fini
00000000 T _init

while

Code: Select all

nm crtn.o

returns nothing / empty

i did a quick test copy crti.o into crtn.o and build with --nostdlib, apparently that won't resolve the missing _init() error
not very relevant

i redo my compile test, apparently --nostdlib cannot be stated in the compile options as that would cause the missing _init() error.
compile with stdlibs now gives me

Code: Select all

   text    data     bss     dec     hex filename
  17724    3208    1088   22020    5604 STM32F103duino-blinky.elf

compile with stdlibs and --specs=nano.specs use newlib-nano now gives

Code: Select all

   text    data     bss     dec     hex filename
  14972    1184     992   17148    42fc STM32F103duino-blinky.elf

separate test, if i used my own void _init() and state --nostdlibs

Code: Select all

   text    data     bss     dec     hex filename
  14872    1088     968   16928    4220 STM32F103duino-blinky.elf

my earlier errors causing fat binaries are the missing c++ compile options
-fno-exceptions do not use exceptions
-fno-rttl do not use rttl
-fno-use-cxa-atexit do not use _cxa_atexit()
-fno-threadsafe-statics do not use threadsafe statics
it is also necessary to state the linker option -Xlinker --gc-sections
if these c++ compile options and linker options are missing, it bulk up the binary considerably
viewtopic.php?f=41&t=655&start=80#p25978

conclusion, just omit the --nostdlibs during compile and that should resolve the missing _init() problem
Last edited by ag123 on Mon Apr 17, 2017 1:54 pm, edited 11 times in total.


Return to “IDE's”

Who is online

Users browsing this forum: No registered users and 1 guest