This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

problem running example code with C++ and I-jet probe

I have been prototyping some code using the IAR C++ compiler on a DK-TM4C129X dev kit.

When I recently obtained an I-jet debug probe from IAR I was surprised to find that my previously working code was suddenly experiencing a hard fault on startup. After playing around with a lot of things, I discovered that the fault only occurs if I use the C++ compile option along with the I-jet debugger. The C++ code works fine if I use the ICDI debugger, and the C code works fine using the I-jet.

I was able to reproduce the fault using the TI-supplied blinky example code. IAR tech support was able to discover what was going wrong, and I am sharing this info in case others may experience similar problems.

The fix involves modifying the startup_ewarm.c and blinky.icf files:


In startup_ewarm.c:

Replace the iar_program_start extern declaration with

#if defined(__cplusplus) || defined(__embedded_cplusplus)

extern "C" void __iar_program_start(void);

#endif

(Note: The above change has nothing to do with the fault, but is required to eliminate linker errors when using the C++ compiler)

Also replace the first part of the IVT definition with

#pragma section="CSTACK"

__root const uVectorEntry __vector_table[] @ ".intvec" =

{

     //{ .ui32Ptr = (uint32_t)pui32Stack + sizeof(pui32Stack) },

     { .ui32Ptr = (uint32_t)__section_end("CSTACK") },

In blinky.icf, replace the "place in SRAM { readwrite, block HEAP };" statement at the end with

  define block CSTACK with alignment = 8, size = 0x200 { };
  place in SRAM { readwrite, block CSTACK, block HEAP };

The explanation from IAR tech support as to why this is needed is as follows:

For the Blinky project under C++ mode without those changes which I suggested, the linker's generated .map file will show 2 .intvec:

 

.intvec   const   0x00000000 0x26c startup.o [1]

.intvec   ro code 0x0000026c   0x40 vector_table_M.o [5]

 

So it seems that the default "__vector_table" is also being linked in from the library vector_table_M.o file, instead of just the "__vector_table" from your own startup.c file. It is most likely because the EWARM's .\arm\src\lib\cstartup_M.s has:

 

       REQUIRE __vector_table

 

And hence the linker will try to link all the instances of __vector_table.

 

When the debugger starts, it usually initializes the PC and SP automatically. And I think that it picks the wrong ones (from vector_table_M.o, instead of startup.o) to initialize the PC and SP.

 

Since the original blinky.icf does not have the CSTACK section defined, the SP gets initialized to '0'. And any instruction in the

main() using the stack will cause the fault exception because the SP is pointing to an invalid address.

 

So having the original startup.c to refer to the "CSTACK" seems to be able to prevent the linker from linking in the extra __vector_table.

  • Dave Hohl said:
    I am sharing this info in case others may experience similar problems.

    May I commend your generous, "Presentation of your findings - AND your resourcefulness in involving the tool vendor - as well?"    That's terrific - and occurs too little - here.   Much thanks - know that your generous effort and detailed report is appreciated.

    As paid, multi-seat users of IAR - we read your earlier post w/interest.    And started organizing some tests - yet we (rarely) mix C++ and C.

    As such mixed development sometimes causes/contributes to such issues - might you describe the, "How & When" you switch from "C" to "C++."    (I think I know - but do not wish to "color" your response...)    Again thanks...

  • Thank you for the kind words, cb1-!

    As far as switching between C and C++, I normally do all of my development in C++. But as I have experienced problems incorporating some of TI's example code into my project, I have sometimes had to resort to compiling the example code using the C++ option to see if the problem is language-specific. Usually this just involves adding the extern "C" declaration to the startup code and changing the IAR project options to use C++ instead of C. In some cases, however (e.g., the usb serial device project) further changes are necessary to get the code to compile and link properly (I still have not gotten that one working).

    It would be nice if TI would test its example code using both the C and C++ compilers so that those of us who like to take advantage of object-oriented programming could be confident that the code will port well.

  • Thank you - and I report our findings - both w/this vendor and other ARMs - much in duplicate of your own.

    While there are advantages under C++ - sometimes we note that trouble remains unrecognized (hidden) until the project is way far along - and then the issue proves costly and demands great resources to find/resolve.

    Object oriented may giveth - but when married to these small machines (both this vendor & many others) he taketh away, too!    (thus not for us)

  • I'm not sure that the problem has to do with running C++ on "small" machines. 15 years ago I was using C++ on a 16-bit Renesas M16C chip without any problems. And I have used it successfully on a TI MSP430 also.

    I think the problem is not the size or power of the processor, but rather that architectures are so much more complicated these days, and there are many more interactions among the hardware, software and tools. Sometimes I long for the good old days of programming for an 8085 chip!
  • Dave Hohl said:
    there are many more interactions among the hardware, software and tools. Sometimes I long for the good old days of programming for an 8085 chip!

    Your word play here exceeds mine - it is those (unwanted/unexpected) "interactions" which I should have better (i.e. somewhat) identified.

    Yet - longing for past 8085 or 8051 - be careful with that you request.   (you don't really want to go back...)

    You're a great addition to this forum Dave - keep pounding - already you've helped many.

  • One more tidbit of info for those who may be using the Micrium RTOS. Micrium's example code already includes the fixes described above. However, a different type of hard fault will occur as soon as the scheduler is invoked. IAR's tech support once again came to the rescue.

    The problem can be resolved by adding a copy of the cstartup_M.s file from the EWARM's .\arm\src\lib\thumb directory into your project and editing it to comment out the following line:

           REQUIRE __vector_table


    This will eliminate the multiple definitions of .intvec, which are at the root of the problem.

  • Thank you Dave, much appreciate the work you put into this.

    Robert
  • There is an alternate solution as well.

    Replace this

    static void (* const interrupt_vector_table[155])(void) =
    
    

    with this

    void (* const __vector_table[155])(void) =
    

    in startup.c

    Personally, I find this cleaner since you are not modifying the vendor's files. You only modify the startup vector table which you would do in any case.

    Not sure why IAR didn't point you in that direction, it's sort of what the code is set up to support to begin with.

    Robert