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.

CCS/MSP430FR5969: Continuous reset issue with hybrid 'C' and Assembly code project.

Part Number: MSP430FR5969
Other Parts Discussed in Thread: OPT3001

Tool/software: Code Composer Studio

I have a project with C and Assembly code that is constantly resetting. I have edited the code to help simplify the fault conditions and observations. The code fragment of interest has a call to an Assembly function that does nothing (just a RETA instruction) then an enable interrupt then a normal C function call. The C function call never finishes, the uC resets. The C code is built under a 'large model' by the way. Removing either the Assy function or the enable interrupt seems to stop the continual reset. This issue looks very similar to a previous post except I am using the correct RETA instruction (not RET)

        (void) main(void)

        {

    initRxMsgHandler();              // do nothing Assy function
    __enable_interrupt();            // enable interrupts globally
    init_FRAM( );                           // ordinary C function

    microcontroller resets here!!!!!!!!!!!!!!!!!!!!!!!

    init_OPT3001( );

}

initRxMsgHandler:
;    NOP
    RETA

  • When do you disable the Watchdog? Or did you edit that key bit of code out as well?

  • The hold watchdog during auto-initialization flag is ON. I enable the watchdog at the second line of my 'Main'. I also just disabled it now and no difference. The watchdog is set to a somewhat slow value of 2 to 4 seconds I believe. My more complete "Main' code (plus a few others) copied below. I will added a  _delay_cycles call to see if there is a 'time' element to this fault.

    void main (void)
    {
        MSP430_Init();
        initWDT( );
        init_GPIO( );
        init_RTC();
        init_Timers( );
    //    initTimer0A0( );
        init_I2C();
        init_SPI();
        init_Comm1( 0 );
        initFRAMmgr( );
        WDTreset( );
        initRxMsgHandler();

        __enable_interrupt();                        // enable interrupts globally

        init_FRAM( );
        init_OPT3001( );
        init_BME280( );
        initADXL362( );

        Comm1_putStr((char*)BannerStr);
        InitMessageHandler( );
        initDataManager( );
        initMainStateMachine( );

        while (TRUE)
        {
            WDTreset( );
            MainStateMachine( );
            DataAquisitionStateMachine( );
            CommandHandler( );
            HighLevelADXL362_INT1( );
        }
    }

    void initWDT( void )
    {
     //   WDTCTL = ( WDTPW | WDTSSEL__VLO | WDTCNTCL | WDTIS_4 ); 

       WDTCTL = ( WDTPW | WDTSSEL__VLO | WDTCNTCL | WDTIS_4 | WDTHOLD);
        SFRIFG1 &= ~WDTIFG;                        // Clear WDT interrupt flag
    //    SFRIE1  |=  WDTIE;                        // Enable WDT interrupt
    }


    initRxMsgHandler:
    ;    NOP
        RETA


  • Adding _delay_cycles at top of Main did not appear to affect fault. I commented out a line of code near the top of Main and the code was able to execute about 5 lines lower before resetting. Strange behavior. Wondering if the issue has to do with where the Linker is locating the code functions. Once Compiled, the micro can't tell whether the source was C or Assembly. Investigation continues.

  • I'm curious how the compiler or the linker knows that your assembly subroutine is assembly.  It seems to be called as a C function, but then the function name simply appears as a label, and not defined as the initWDT function is:

    initRxMsgHandler:
    ;    NOP
        RETA

    Is that how assembly code is included in C?  Would you still get the resets if you changed initRxMsgHandler to a proper C function that does nothing?

  • You can use assembly two ways. Either via asm("") statements within your C code or as separately compiled files.

    I have done the latter but with gcc. By naming the file something.S the gcc front end knows to run it by the preprocessor first. This way you can include the device header files with all of those handy symbols in them.

    You do have to be careful about naming your C visible functions (a leading "_" is required) and of course following the parameter passing standards.

  • First, that Assembly function was clipped out of a .asm file and copied at the bottom of my Main code snippet for reference (sorry about confusion). I am aware of naming conventions with hybrid C and Assembly projects.

    Second, I added a dummy C function (see below) that looked exactly like the Asm function (verified by looking at the disassembled code using CCS). The application worked fine (did NOT reset). So I sais to myself "'How can this be?"

    void DummyFunction(void)
    {
        __no_operation();
    }
    Third, I checked the map file and found that adding that trivial 'do nothing' assembly function caused the Linker to link in a very large object file (of size 0x04ac) at the top of my .text section that was not there otherwise. Linker must have seen some set of reference symbols and decided to do that (fine, won't complain about that). This pushed all the remaining executable code down by over a Kbyte. Again, I think it's the code location that's at issue. Maybe there is a memory alignment issue. Maybe code is being pushed into the FRAM2 area. Code should be able to run anywhere (with large model setting), but  I'll check it out. Thoughts?

  • In my experience, if you're sure the WDT is off, then resets usually mean you are trying to execute code at locations where no memory actually exists, or there is memory there but it's all FFs.  Happens to me all the time in assembler when I Call Subroutine when I really mean Call #Subroutine.

    I guess I would look at the .HEX files of the working and non-working versions, and see what's different about where things are placed in memory.  But maybe your CCS disassembly does that for you.

    One other question:  in your disassembly of the C version of the do-nothing function, does it end with a RETA?

    Well this is quite a mystery.  In the end it will have been something simple, but finding it is the problem.

  • Pretty sure it's not the WDT and I'm using RETA not RET. It may be an invalid memory issue (only the VMAIFG flag is not set when reset occurs). I'll keep looking. Thanks for the input. Will post the answer when I find it (if it's not too embarrassing).

  • Here's the deal.

    Fault: Linker was locating ISR functions in FRAM2 space above 64K. Can't do that because of the way the micro handles ISR addresses.

    Cause: When I made a call to the trivial small Assembly function, the Linker pulled in the entire Assembly file that contained the function (about 1 KB's worth). I think in a C file, the Linker only pulls in the referenced functions, non reference functions are not linked in. This pushed an ISR function (that was formerly placed below address 64 K) into the FRAM2 space above 64K. The micro didn't like that. When called, the calculated return address was invalid and the code crashed. I don't know why I could not detect this with the VMAILG. May look into this further. This was a build issue, not a hybrid C./Assembly issue.

    Solution: Added #pragma statements in all ISRs to force Linker to place ISRs into lower 64K address space (using linkercmd file).

    Takeaway: I knew about the ISR address limitation, I should have known better.

  • Thanks for the update.  Glad you've found the problem. 

  • That is interesting. GCC puts each function in a separate section (if -function-sections is used) and then the linker trims off unused sections if given --gc-sections.

    I checked and an interrupt routine was put in section ".text.rxISR" but if I used "-mlarge" to get the large model it was put in section ".lowtext". So I am safe from that problem. The CCS compiler really ought to know better than to put ISRs in high memory since the vector table can't point to them. At the very least it should generate an error message while linking.

  • Hi James,

    Thanks for updating your status. Please feel free to come back if further question or issue.

**Attention** This is a public forum