3

I have a very strange problem. It sounds to me that this is a known problem, but I cannot find any actual solutions for, or any solid explanations of it.

Here is my setup:
Host: Win7 PC, plenty of RAM.
Target: STM32F303RE Cortex M4 @ 64 MHz, on Nucleo32 board with Integrated ST-LINK 2.1
Toolchain: uVision V5.16
Preprocessor Symbols: USE_STDPERIPH_DRIVER,STM32F303xE,__CPLUSPLUS__FPU_PRESENT,__FPU_USED

Misc Controls: --C99 --cpp

All builds well. All optimization turned off.

The problem is during runtime. The processor ends up in a hardfault handler after a few C++ object instantiantions. Where exactly? I've marked this by splitting my code snippet. Now, I'm sort of new to C++ details and inner workings, but it sounds like I have the same problem as this bloke: Segmentation fault caused/avoided by changing source file order in Makefile

But also, not clear solution is explained. Perhaps it is not the C++ instantiation at fault. Though there is no solution found. Here is the gist of my program which demonstrates the problem: This first section of code "appears" to run well, until the section block I've separated out for your attention.


    #include "main.h"
    #include "stm32f30x.h"
    #include "stdint.h"
    #include "stdio.h"
    #include "string.h"
    #include "math.h"
    #include "usart.h"
    #include "can.h"
    #include "utils.h"
    #include "led.h"
    #include "i2c.h"
    #include "sabertooth.h"

    #include "FuzzyRule.h"
    #include "FuzzyComposition.h"
    #include "Fuzzy.h"
    #include "FuzzyRuleConsequent.h"
    #include "FuzzyOutput.h"
    #include "FuzzyInput.h"
    #include "FuzzyIO.h"
    #include "FuzzySet.h"
    #include "FuzzyRuleAntecedent.h"

    Fuzzy* fuzzy = new Fuzzy();

    int main(void)
    {
      /*************************************
       * Input 1
       ************************************/
      // Two "crossing ramp" sets for rowWidth i.e. "tolerance" of the row
      FuzzyInput* rowWidth = new FuzzyInput(1);

      FuzzySet* lowTolerance  = new FuzzySet(0.0f, 0.0f, 0.0f, 120.0f);
      rowWidth->addFuzzySet(lowTolerance);
      FuzzySet* highTolerance = new FuzzySet(0.0f, 120.0f, 120.0f, 120.0f);
      rowWidth->addFuzzySet(highTolerance);

      fuzzy->addFuzzyInput(rowWidth);
      USART1_puts("row width added as fuzzy input..");

      /*************************************
       * Input 2
       ************************************/
      // Five Sets for "difference between R and L distances"
      FuzzyInput* distDiff = new FuzzyInput(2);

      FuzzySet* tooFarRight   = new FuzzySet(-60.0f, -60.0f, -54.0f, -30.0f);
      distDiff->addFuzzySet(tooFarRight);
      FuzzySet* right         = new FuzzySet(-54.0f, -30.0f, -30.0f, 0.0f);
      distDiff->addFuzzySet(right);
      FuzzySet* centered      = new FuzzySet(-30.0f, 0.0f, 0.0f, 30.0f);
      distDiff->addFuzzySet(centered);
      FuzzySet* left          = new FuzzySet(0.0f, 30.0f, 30.0f, 54.0f);
      distDiff->addFuzzySet(left);
      FuzzySet* tooFarLeft    = new FuzzySet(30.0f, 54.0f, 60.0f, 60.0f);
      distDiff->addFuzzySet(tooFarLeft);

      fuzzy->addFuzzyInput(distDiff);
      USART1_puts("centering dist added as fuzzy input...");

      /*************************************
       * Output 1
       ************************************/
      FuzzyOutput* motorSpeedDiff = new FuzzyOutput(1);

      // Seven sets for steering modes to take (close ones narrow far ones wider)
      FuzzySet* hardRight   = new FuzzySet(-30.0f, -30.0f, -30.0f, -15.0f);
      motorSpeedDiff->addFuzzySet(hardRight);
      USART1_puts("\thardRight");
      FuzzySet* lightRight  = new FuzzySet(-15.0f, -5.0f, -5.0f, 0.0f);
      motorSpeedDiff->addFuzzySet(lightRight);
      USART1_puts("\tlightRight");

This is the last serial message I see in the terminal "lightRight" Hard fault occurs in next call to new FuzzySet()below this line.


      FuzzySet* nomRight    = new FuzzySet(-30.0f, -15.0f, -15.0f, -5.0f);
      motorSpeedDiff->addFuzzySet(nomRight);
      USART1_puts("\tnomRight");
      FuzzySet* lightLeft   = new FuzzySet(0.0f, 5.0f, 5.0f, 15.0f);
      motorSpeedDiff->addFuzzySet(lightLeft);
      USART1_puts("\tlightLeft");
      FuzzySet* goStraight  = new FuzzySet(-5.0f, 0.0f, 0.0f, 5.0f);
      motorSpeedDiff->addFuzzySet(goStraight);
      USART1_puts("\tgoStraight");
      FuzzySet* nomLeft     = new FuzzySet(5.0f, 15.0f, 15.0f, 30.0f);
      motorSpeedDiff->addFuzzySet(nomLeft);
      USART1_puts("\tnomLeft");
      FuzzySet* hardLeft    = new FuzzySet(15.0f, 30.0f, 30.0f, 30.0f);
      motorSpeedDiff->addFuzzySet(hardLeft);
      USART1_puts("\thardLeft");

      fuzzy->addFuzzyOutput(motorSpeedDiff);
      USART1_puts("motor steering added as fuzzy output");

      lotsMoreSetupCode();

      while(1)
      {
        USART1_puts("Done!");
        stop(1); // Blink LED forever
      }
    }

So clearly, I am just making a bunch of these fuzzy sets, which are each a collection of 4 floats, but somewhere a le-wild pointer flies?

Here is the constructor found in FuzzySet.cpp: (Part of a fuzzy logic library I did not write) This SAME program runs well on an Arduino, but not this processor. Compiler difference?



FuzzySet::FuzzySet(){
}
FuzzySet::FuzzySet(float a, float b, float c, float d){
    this->a = a;
    this->b = b;
    this->c = c;
    this->d = d;
    this->pertinence = 0.0;
}

It sounds like something to do with static variables being accessed by other staticly declared functions in other contexts.

But I have nothing declared static.

Someone in the stack exchange link says it might be a linker fault. Do you agree? How to repair this?

Any ideas on what is actually happening?

I've set up the nice hard fault handler which prints register info, but apparently the error occurs even before main(). So going to the assembly code when things get jumbled doesn't seem useful.

How to go about repairing this? Thanks for your C++ expertise!

Community
  • 1
  • 1
  • Do you have enough heap space allocated? Is nomRight null? – Ross Apr 12 '16 at 19:20
  • I can actually swap the calling order for nomRight and lightRight, but the hard fault will occur in the same place, this time when creating the nomRight instance, (the second of the two created). This makes me think this is a "space" issue, and not a "bad object" kind of issue. Is there a way to check if nomRight == NULL? Could I do a check on the object and then print to terminal? I will give it a shot. – Tyler Troyer Apr 12 '16 at 19:27
  • _"apparently the error occurs even before main()"_ - but you've also said you see the fault after a great big chunk of `main()` has executed just fine. Which is it? Side note: `--C99`? Really? – Notlikethat Apr 12 '16 at 19:28
  • Notlikethat: See the comment by Beta in my linked post. Side note: What is wrong with C99? – Tyler Troyer Apr 12 '16 at 19:30
  • Can you set a hardfault handler in your vector table? And in this handler, read the `LR` register, fault address register, fault status register. The `LR` register will give you the address of the instruction that caused the fault, and status and fault register will give more information about the type of fault. – Dric512 Apr 12 '16 at 19:39
  • I found this question posted: http://engineering.stackexchange.com/questions/4013/defining-the-heap-and-stack-size-for-a-arm-cortex-m4-micro-controller The answer is that I had very little heap space allocated. Ross asked a good question. I had to increase heap size from 0x200, to 0x800 to get all these objects built. Thanks Ross. – Tyler Troyer Apr 12 '16 at 20:00

1 Answers1

0

Try to change heap and stack size of your code according microcontroller you use from startup_stm32fxxx.s file

here is the example

;******************** (C) COPYRIGHT 2016 STMicroelectronics ********************
;* File Name          : startup_stm32f407xx.s
;* Author             : MCD Application Team
;* Version            : V2.4.3
;* Date               : 22-January-2016
;* Description        : STM32F407xx devices vector table for MDK-ARM toolchain. 
;*                      This module performs:
;*                      - Set the initial SP
;*                      - Set the initial PC == Reset_Handler
;*                      - Set the vector table entries with the exceptions ISR address
;*                      - Branches to __main in the C library (which eventually
;*                        calls main()).
;*                      After Reset the CortexM4 processor is in Thread mode,
;*                      priority is Privileged, and the Stack is set to Main.
;* <<< Use Configuration Wizard in Context Menu >>>   
;*******************************************************************************
; 
;* Redistribution and use in source and binary forms, with or without modification,
;* are permitted provided that the following conditions are met:
;*   1. Redistributions of source code must retain the above copyright notice,
;*      this list of conditions and the following disclaimer.
;*   2. Redistributions in binary form must reproduce the above copyright notice,
;*      this list of conditions and the following disclaimer in the documentation
;*      and/or other materials provided with the distribution.
;*   3. Neither the name of STMicroelectronics nor the names of its contributors
;*      may be used to endorse or promote products derived from this software
;*      without specific prior written permission.
;*
;* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
;* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
;* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
;* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
;* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
;* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
;* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
;* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
;* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
;* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
; 
;*******************************************************************************

; Amount of memory (in bytes) allocated for Stack
; Tailor this value to your application needs
; <h> Stack Configuration
;   <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>

Stack_Size      EQU     0x200  ; <your stack size>

                AREA    STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem       SPACE   Stack_Size
__initial_sp


; <h> Heap Configuration
;   <o>  Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>

Heap_Size      EQU     0x400  ; <your heap size>

                AREA    HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem        SPACE   Heap_Size
__heap_limit

                PRESERVE8
                THUMB


; Vector Table Mapped to Address 0 at Reset
                AREA    RESET, DATA, READONLY
                EXPORT  __Vectors
                EXPORT  __Vectors_End
                EXPORT  __Vectors_Size

The value of stack is set by that line

Stack_Size      EQU     0x200  ; <your stack size>

and the heap

Heap_Size      EQU     0x400  ; <your heap size>

In Keil uVision you also have 2 tabs at the left-bottom corner where you can switch between "Text Editor" and "Config Wizard" to change your code heap and stack sizes.

Mykola
  • 3,343
  • 6
  • 23
  • 39