Skip to main content
lanchon
Associate III
February 28, 2008
Question

C++?

  • February 28, 2008
  • 16 replies
  • 2631 views
Posted on February 28, 2008 at 16:20

C++?

    This topic has been closed for replies.

    16 replies

    lanchon
    lanchonAuthor
    Associate III
    May 17, 2011
    lanchon
    lanchonAuthor
    Associate III
    May 17, 2011
    Posted on May 17, 2011 at 12:24

    hi!

    is anyone using c++ successfully with the stm32? using what tools?

    I'm trying to use the latest codesourcery but can't make it work. two problems:

    #1. when I include a c++ source file in the build, the injected stack unwinding code indirectly generates these references:

    thumb2\libc.a(lib_a-abort.o): In function `abort': abort.c: undefined reference to `_exit'

    thumb2\libc.a(lib_a-signalr.o): In function `_getpid_r': signalr.c: undefined reference to `_getpid'

    thumb2\libc.a(lib_a-signalr.o): In function `_kill_r': signalr.c: undefined reference to `_kill'

    thumb2\libc.a(lib_a-sbrkr.o): In function `_sbrk_r': sbrkr.c: undefined reference to `_sbrk'

    I've read something about codesourcery's newlib being built with --disable-newlib-supplied-syscalls, but I don't know why it's built that way, or how to fix this (I'm not familiar with GCC and it's libs at all). for now I've sidestepped the issue by using -fno-exceptions, which avoids the stack unwinding code, but bumped into...

    #2. now the the build completes but the program doesn't work on the target. I assume the presence of c++ code forces the selection of a different initialization code, and somehow this new code fails (I'm guessing it might have something to do with the linker script).

    no workaround for #2! would someone be able to help me? what info would you need posted? what other tools do work for c++ on the stm32?

    thank you very much!

    lanchon
    lanchonAuthor
    Associate III
    May 17, 2011
    Posted on May 17, 2011 at 12:24

    ok, I sort of know what's up with #2, I'll write tomorrow if I find the time.

    lanchon
    lanchonAuthor
    Associate III
    May 17, 2011
    Posted on May 17, 2011 at 12:24

    to clarify on Ride7, though it builds the app, OpenOCD can't program the chip using the produced ELF. it fails with this error:

    Info: configuration.c:50 configuration_output_handler(): failed writing image flash: error reading from image

    (this is different from when I build directly with codesourcery, in which case OpenOCD programs ok but the target fails to run.)

    I've also tried Anglia's IDEaliST. it's friendly to c++ but the output file has the same problem with OpenOCD if a c++ source is included in the build. (#1 isn't an issue with this IDE.)

    seriously, no one's using c++?

    lanchon
    lanchonAuthor
    Associate III
    May 17, 2011
    Posted on May 17, 2011 at 12:24

    update: apparently Ride7 doesn't really want to do c++. after some massaging I got it to build a c++ app, and...

    -#1 wasn't an issue, apparently they have some fallback system calls for newlib

    -the build didn't work, so #2 keeps on being the show stopper (not really a surprise, since the linker file I'm using comes from Ride7)

    ...so still blocked...

    obtronix
    Associate II
    May 17, 2011
    Posted on May 17, 2011 at 12:24

    Quote:

    On 21-02-2008 at 21:53, Anonymous wrote:

    I guess noone's working with c++ after all. is anybody interested in me keeping on posting to this thread?

    I suspect many of us design using OOD but implement in C and Assembly, at least I do.

    lanchon
    lanchonAuthor
    Associate III
    May 17, 2011
    Posted on May 17, 2011 at 12:24

    I'm using these macros to define pointers to bit-band bits:

    #define BB_BIT(NAME, REGISTER, BIT_NUMBER, BASE, BB_BASE) static volatile int* const (NAME) = ((int *) ((BB_BASE) + (((int) &(REGISTER)) - (BASE)) * 32 + (BIT_NUMBER) * 4));

    #define PERIPHERAL_BIT(NAME, REGISTER, BIT_NUMBER) BB_BIT(NAME, REGISTER, BIT_NUMBER, PERIPH_BASE, PERIPH_BB_BASE)

    and using them like this:

    PERIPHERAL_BIT(LED, GPIOC->ODR, 12);

    void f(void) { *LED = 1; }

    this defines ''static volatile int* const'' pointers that should be as efficient as macros. now I don't know the first thing about arm assembler but when the code is compiled as c it's clear that it's optimized and that the bit-band bit address is loaded into r2 as if it were a constant from .L40:

    .L38:

    ldr r2, .L40

    mov r0, #393216

    ldr r3, [r2, #0]

    eor r3, r3, #1

    str r3, [r2, #0]

    bl busyWait

    b .L38

    .L41:

    .align 2

    .L40:

    .word 1109524912

    (incidentally, the use of offline constants like .L40 beats the prefetch mechanism; can't it be done any better?)

    however when the same code is compiled as c++, it's not optimized:

    ldr r3, .L49

    ldr r4, [r3, #0]

    .L47:

    ldr r3, [r4, #0]

    mov r0, #393216

    eor r3, r3, #1

    str r3, [r4, #0]

    bl _Z8busyWaiti

    b .L47

    .L50:

    .align 2

    .L49:

    .word .LANCHOR0

    here .L49 holds the address of the pointer pointing to the bit-band bit address (the pointer is called .LANCHOR0 (strangely similar to my nick) and not LED, since it's static).

    why the c++ compile is less optimized is anybody's guess. I think there's no good reason for it, could someone comment?

    anyway, this means that .LANCHOR0 must be initialized. in c this would be done through the .data section, but in c++ initializations invoke constructors which may have side effects, so copying memory is not sufficient and user code must be run (in the general case). g++ chose to handle this initialization with code, and puts a pointer to the code in section .init_array.

    the linker script should dump that section into the flash and init symbols describing it's extent, and the boot code should read that data and invoke the initializers before invoking main. I've never seen a linker script in my life before, but it's clear that mine is not dumping .init_array into the flash, and besides the boot code that comes with the stm32 fwlib wouldn't invoke the initializers either. so that's why the code fails.

    being naive, I thought I could simply modify both things so that the list of initializers would get called, but there must be more to it than that. in particular, since a constructor could refer to a global constructed value, how is initialization ordered across compile modules so that inits are done in the right order? (if such an order is guaranteed by c++, and I imagine it is.) (there must also be a similar mechanism for destructing globals, but that not important for non-hosted embedded apps.)

    could somebody point to c++ startup code and linker script samples? as you can guess I'm also unfamiliar with gcc...

    in short, I want to handle abstractions, not details! :)

    lanchon
    lanchonAuthor
    Associate III
    May 17, 2011
    Posted on May 17, 2011 at 12:24

    I guess noone's working with c++ after all. is anybody interested in me keeping on posting to this thread?

    lanchon
    lanchonAuthor
    Associate III
    May 17, 2011
    Posted on May 17, 2011 at 12:24

    I

    http://www.st.com/mcu/forums-cat-6445-23.html

    at last!

    I tried Anglia but had some problems, maybe something broke when more runtime was needed, or maybe it was me, I really couldn't tell you now.

    I need c++ cause I almost vomit when I have to program in c. it's an horrendous experience for me, I suffer, really. c is a portable assembler that doesn't support abstraction. it's true, you can apply OO principles to any language, including real assembler, but the end result is that you're doing the work of a compiler. and I want less work, not more. c won't understand your OO work and its type system won't help you or check on you. and the mapping (compilation) process you have to do is tedious and error prone. plus there's much more to c++ than objects, like generic programming and exceptions.

    I believe there's not a single reason to prefer c over c++. c++ doesn't have to be one bit slower or less space efficient than c, and in the real world programs can be made more efficient in c++. (in the extreme of complexity, you can say that programs can at lest be *made* in c++, in contrast with assembler or c.)

    I chose the microcontroller with the absolute requirement of c++ support. I need it cause I'm involved in a sort of complex project.

    > why you want c++ (and so dynamic memory) [...]?

    the use of c++ does not imply dynamic memory in any way. but in my project I need it. I'll have realtime periodic code using fully static memory and the user interface (complex) running on the background. the UI uses all the not very deterministic services like heap and exceptions, while the realtime part doesn't.

    (btw, if you try c++ on the STM32 and find that the binaries are too big, you could disable exceptions in the makefile so that the stack unwinding code is not linked.)

    giles
    Associate II
    May 17, 2011
    Posted on May 17, 2011 at 12:24

    As mentioned by someone else you can do and i do use object oriented design in C (without a heap) (and use c++ for windows apps where there a mmu).

    However if you download the anglia toolchain they have a c++ example hello world type program, havent tried it myself but theres a linker script and sourcecode :)

    http://www.st-angliamicro.com/software.asp

    (\Program Files\Anglia\IDEaliST\examples\stm32\hellocpp).

    *curious* Can i ask why you want c++ (and so dynamic memory) for embedded as preference?