Page 1 of 2

[STM32F407 Discovery] demo adaption to C++ fails

Posted: Wed Dec 21, 2011 9:14 am
by levrik
Hello,

i've some problems getting C++ /Chibios-RT (trunk from 20.12.2011 Rev.3643) running on STM32F4-DISCOVERY. After merging the STM32F103-G++ (C++-Stuff) Demo with the STM32F407-DISCOVERY Code (functionality), I end every time either in chSysHalt() with a dbg-message "stack-overflow" or in _unhandled_exception().
I've tried compilation with and without
- Optimation (O0 <-> O2)
- FPU-Support ( -mhard-float -mfpu=fpv4-sp-d16 )
- Aligned functions option ( -falign-functions=16 )
- alternate linker-scripts STM32F407xG.ld / STM32F407xG_CCM.ld

but without success. Also increasing the stack-values to higher amounts (1024) didn't help.

The STM32F407-DISCOVERY c-demo works like a charm.

Attached you'll find the files changed to the standard STM32F4-DISCOVERY-demo.

main.cpp

Code: Select all

/*
    ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
                 2011 Giovanni Di Sirio.

    This file is part of ChibiOS/RT.

    ChibiOS/RT is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.

    ChibiOS/RT is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "ch.hpp"
//#include "ch.h"
#include "hal.h"
#include "test.h"
#include "chprintf.h"
#include "evtimer.h"

using namespace chibios_rt;


class LED_Blink : public EnhancedThread<128> {
private:
   int counter;
protected:
  virtual msg_t Main(void) {
     while (true) {
        palSetPad(GPIOD, GPIOD_LED3);       /* Orange.  */
        Sleep(MS2ST(100));
        palClearPad(GPIOD, GPIOD_LED3);     /* Orange.  */
        Sleep(MS2ST(900));
        chprintf((BaseChannel *)&SD2, "%04u: Still living...\r\n", counter++);
     }
    return 0;
  }

public:
  LED_Blink() : EnhancedThread<128>("blinker") {
     counter = 0;
  }

  LED_Blink(int cnt) : EnhancedThread<128>("blinker") {
     counter = cnt;
  }
  virtual ~LED_Blink(){return; };
};

class TesterThread : public EnhancedThread<256> {

protected:
  virtual msg_t Main(void) {

   chprintf((BaseChannel *)&SD2, "Still living 2\r\n");
    return 1;// TestThread(&SD2);
  }

public:
  TesterThread(void) : EnhancedThread<256>("tester"){

  }
  virtual ~TesterThread() {return;};
};

/*
 * Executed as an event handler at 500mS intervals.
 */
static void TimerHandler(eventid_t id) {

  (void)id;
  if (palReadPad(GPIOA, GPIOA_BUTTON)) {
    TesterThread tester;
    tester.Wait();
  };
}

/*
 * Application entry point.
 */
int main(void) {
   static const evhandler_t evhndl[] = { TimerHandler };
   static EvTimer evt;
   struct EventListener el0;

  /*
   * System initializations.
   * - HAL initialization, this also initializes the configured device drivers
   *   and performs the board-specific initializations.
   * - Kernel initialization, the main() function becomes a thread and the
   *   RTOS is active.
   */
  halInit();
  System::Init();
  /*
   * Activates the serial driver 2 using the driver default configuration.
   * PA2(TX) and PA3(RX) are routed to USART2.
   */
  sdStart(&SD2, NULL);
  palSetPadMode(GPIOA, 2, PAL_MODE_ALTERNATE(7));
  palSetPadMode(GPIOA, 3, PAL_MODE_ALTERNATE(7));

  /*
   * Creates the example thread.
   */
  LED_Blink blinker1(1);


  evtInit(&evt, 500);                   // Initializes an event timer.
  evtStart(&evt);                       // Starts the event timer.
  chEvtRegister(&evt.et_es, &el0, 0);   // Registers a listener on the source.

  /*
   * Normal main() thread activity, in this demo it does nothing except
   * sleeping in a loop and check the button state, when the button is
   * pressed the test procedure is launched with output on the serial
   * driver 2.
   */
  while (true)
    Event::Dispatch(evhndl, Event::WaitOne(ALL_EVENTS));

}


syscalls_local.cpp

Code: Select all

#include <stdlib.h>

extern "C" void *malloc(size_t) {
   return (void *)0;
}

extern "C" void free(void *) {
}
void *operator new(size_t size) throw() { return malloc(size); }
void operator delete(void *p) throw() { free(p); }
extern "C" int __aeabi_atexit( __attribute__((unused)) void *object,
                        __attribute__((unused)) void (*destructor)(void *),
                        __attribute__((unused)) void *dso_handle)
{
    return 0;
}


Makefile:

Code: Select all

##############################################################################
# Build global options
# NOTE: Can be overridden externally.
#

# Compiler options here.
ifeq ($(USE_OPT),)
  USE_OPT = -O0 -g3 -ggdb -fomit-frame-pointer -falign-functions=16 -mhard-float -mfpu=fpv4-sp-d16
endif

# C specific options here (added to USE_OPT).
ifeq ($(USE_COPT),)
  USE_COPT =
endif

# C++ specific options here (added to USE_OPT).
ifeq ($(USE_CPPOPT),)
  USE_CPPOPT = -fno-rtti -fno-exceptions
endif

# Enable this if you want the linker to remove unused code and data
ifeq ($(USE_LINK_GC),)
  USE_LINK_GC = yes
endif

# If enabled, this option allows to compile the application in THUMB mode.
ifeq ($(USE_THUMB),)
  USE_THUMB = yes
endif

# Enable this if you want to see the full log while compiling.
ifeq ($(USE_VERBOSE_COMPILE),)
  USE_VERBOSE_COMPILE = no
endif

#
# Build global options
##############################################################################

##############################################################################
# Architecture or project specific options
#

# Enable this if you really want to use the STM FWLib.
ifeq ($(USE_FWLIB),)
  USE_FWLIB = no
endif

#
# Architecture or project specific options
##############################################################################

##############################################################################
# Project, sources and paths
#

# Define project name here
PROJECT = chibi-mf

# Imported source files and paths
CHIBIOS = ../externals/ChibiOS-RT
include $(CHIBIOS)/boards/ST_STM32F4_DISCOVERY/board.mk
include $(CHIBIOS)/os/hal/platforms/STM32F4xx/platform.mk
include $(CHIBIOS)/os/hal/hal.mk
include $(CHIBIOS)/os/ports/GCC/ARMCMx/STM32F4xx/port.mk
include $(CHIBIOS)/os/kernel/kernel.mk
include $(CHIBIOS)/test/test.mk

# Define linker script file here
LDSCRIPT= $(PORTLD)/STM32F407xG.ld

# C sources that can be compiled in ARM or THUMB mode depending on the global
# setting.
CSRC = $(PORTSRC) \
       $(KERNSRC) \
       $(TESTSRC) \
       $(HALSRC) \
       $(PLATFORMSRC) \
       $(BOARDSRC) \
       $(CHIBIOS)/os/various/evtimer.c \
       $(CHIBIOS)/os/various/syscalls.c \
       $(CHIBIOS)/os/various/chprintf.c \
       #main.c

# C++ sources that can be compiled in ARM or THUMB mode depending on the global
# setting.
CPPSRC = $(CHIBIOS)/os/various/ch.cpp main.cpp syscalls_local.cpp

# C sources to be compiled in ARM mode regardless of the global setting.
# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
#       option that results in lower performance and larger code size.
ACSRC =

# C++ sources to be compiled in ARM mode regardless of the global setting.
# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
#       option that results in lower performance and larger code size.
ACPPSRC =

# C sources to be compiled in THUMB mode regardless of the global setting.
# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
#       option that results in lower performance and larger code size.
TCSRC =

# C sources to be compiled in THUMB mode regardless of the global setting.
# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
#       option that results in lower performance and larger code size.
TCPPSRC =

# List ASM source files here
ASMSRC = $(PORTASM)

INCDIR = $(PORTINC) $(KERNINC) $(TESTINC) \
         $(HALINC) $(PLATFORMINC) $(BOARDINC) \
         $(CHIBIOS)/os/various

#
# Project, sources and paths
##############################################################################

##############################################################################
# Compiler settings
#

MCU  = cortex-m4

#TRGT = arm-elf-
TRGT = arm-none-eabi-
CC   = $(TRGT)gcc
CPPC = $(TRGT)g++
# Enable loading with g++ only if you need C++ runtime support.
# NOTE: You can use C++ even without C++ support if you are careful. C++
#       runtime support makes code size explode.
LD   = $(TRGT)gcc
#LD   = $(TRGT)g++
CP   = $(TRGT)objcopy
AS   = $(TRGT)gcc -x assembler-with-cpp
OD   = $(TRGT)objdump
HEX  = $(CP) -O ihex
BIN  = $(CP) -O binary

# ARM-specific options here
AOPT =

# THUMB-specific options here
TOPT = -mthumb -DTHUMB

# Define C warning options here
CWARN = -Wall -Wextra -Wstrict-prototypes

# Define C++ warning options here
CPPWARN = -Wall -Wextra

#
# Compiler settings
##############################################################################

##############################################################################
# Start of default section
#

# List all default C defines here, like -D_DEBUG=1
DDEFS =

# List all default ASM defines here, like -D_DEBUG=1
DADEFS =

# List all default directories to look for include files here
DINCDIR =

# List the default directory to look for the libraries here
DLIBDIR =

# List all default libraries here
DLIBS =

#
# End of default section
##############################################################################

##############################################################################
# Start of user section
#

# List all user C define here, like -D_DEBUG=1
UDEFS =

# Define ASM defines here
UADEFS =

# List all user directories here
UINCDIR =

# List the user directory to look for the libraries here
ULIBDIR =

# List all user libraries here
ULIBS =

#
# End of user defines
##############################################################################

ifeq ($(USE_FWLIB),yes)
  include $(CHIBIOS)/ext/stm32lib/stm32lib.mk
  CSRC += $(STM32SRC)
  INCDIR += $(STM32INC)
  USE_OPT += -DUSE_STDPERIPH_DRIVER
endif

include $(CHIBIOS)/os/ports/GCC/ARMCMx/rules.mk


Thanks for hints and help.

Manuel

Re: [STM32F407 Discovery] demo adaption to C++ fails

Posted: Wed Dec 21, 2011 9:23 am
by Giovanni
Hi,

When the C++ wrapper is used the stacks of the various threads are allocated within the stack of the main() thread, increasing the threads stack sizes actually make them overflow the main() function stack.

Try to increase the size of __process_stack_size__ in the linker script, it must be large enough to contain the stacks of all threads created using the C++ wrappers.

Note that the C++ wrapper is in the list of components to be updated.

Giovanni

Re: [STM32F407 Discovery] demo adaption to C++ fails

Posted: Wed Dec 21, 2011 10:33 am
by levrik
Hi Giovanni ,

thanks for answering. I'll give it a try as soon as I've the hardware in hands again.

Manuel

Re: [STM32F407 Discovery] demo adaption to C++ fails

Posted: Wed Dec 21, 2011 1:58 pm
by levrik
Giovanni wrote:[...]
Note that the C++ wrapper is in the list of components to be updated.
[...]

I understood the trunk/todo.txt this way, that C++-wrapper is a topic for 2.x.x rather than 2.3.x and not in progress. Do you plan to update this topic in near future?

Manuel

Re: [STM32F407 Discovery] demo adaption to C++ fails

Posted: Wed Dec 21, 2011 3:04 pm
by Giovanni
There is a topic regarding C++ in the development forum, we are collecting ideas about it.

Giovanni

Re: [STM32F407 Discovery] demo adaption to C++ fails

Posted: Wed Dec 21, 2011 7:21 pm
by levrik
For archive reason:
The increase of __process_stack_size__ seems to solve the problem. Thanks a lot.

Concerning C++:
Did find the corresponding thread, thanks also for this.

Re: [STM32F407 Discovery] demo adaption to C++ fails

Posted: Thu Dec 22, 2011 6:59 pm
by levrik
levrik wrote:For archive reason:
The increase of __process_stack_size__ seems to solve the problem. Thanks a lot.
[...]

It seems that i was too overhasty by giving this statement. It is also necessary to change optimation-flags from -O0 to -O1 to make this working! Even increasing the stack to 0x0F00 does not work with -O0!

It seems that is also necessary to change newest trunk STM32F4-HAL hal_ldd.c line 99 to while ((PWR->CSR & PWR_CSR_VOSRDY) == 0)

Kind regards
Manuel

Re: [STM32F407 Discovery] demo adaption to C++ fails

Posted: Thu Dec 22, 2011 7:54 pm
by Giovanni
Thanks for reporting, fixed it, I am still working on that part.

Giovanni

Re: [STM32F407 Discovery] demo adaption to C++ fails

Posted: Thu Nov 01, 2012 11:24 am
by feanor
Giovanni wrote:Hi,

When the C++ wrapper is used the stacks of the various threads are allocated within the stack of the main() thread, increasing the threads stack sizes actually make them overflow the main() function stack.

Try to increase the size of __process_stack_size__ in the linker script, it must be large enough to contain the stacks of all threads created using the C++ wrappers.

Note that the C++ wrapper is in the list of components to be updated.

Giovanni

May i ask why/how the threads created by the C++-Wrapper are located within the main() thread? Is it possible to change so the threads are located not within the main-thread's stack?

Are there still efforts to update the C++-Wrapper?

Re: [STM32F407 Discovery] demo adaption to C++ fails

Posted: Thu Nov 01, 2012 12:26 pm
by Giovanni
Hi,

The threads stacks in the demo are automatic variables of the main() function so they are allocated in the process stack. I have no a timeline for an updated wrapper but not that you can use the normal OS C functions from C++ code without any problem, the wrapper is not strictly needed.

Giovanni