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.

TMS320F28035: MCU runs differently in "normal" and "debug"

Part Number: TMS320F28035
Other Parts Discussed in Thread: CONTROLSUITE

Hi,

I have a very weird issue on my prototype. All other conditions being equal, the MCU doesn't "act" the same way when powered normally, or after a program reload (without power cycle). And, unfortunately for me, the abnormal behavior is when the MCU is not connected to the emulator, which means that I can't see what is happening to the program when it doesn't behave properly (when in debug mode, it does behave as expected).

When I reload the program and run it (with the debugger), then unplug the debugger, everything works fine. A couple of relays (ie GPIOs) switch as expected, and when I add a little bit of voltage on the input of the power converter, PWM pulses happen, as intended.

When I just power on the board, the relays switch as expected, but strangely, adding the voltage on the input of the converter doesn't trigger the PWM pulses. The program runs at least in part properly, as the couple of GPIOs I checked do exactly what they are expected to, I can see some clock on the XCLOCKOUT pin too ... and yet, no PWMs. 

Does someone have any idea what could be different in "debug" mode and in "normal" mode that could make the program not behave ? 

Thanks in advance,

Adrien

  • Adrien,

    Do you have any initialized constants in RAM? If so, they would get loaded only when the emulator is connected and the program loaded (but not upon a "cold" power-up). Could you please check your .map file if this is the case?

  • Wanted to share this clarification from a colleague:

     

    This refers to .const section which is not initialized by .cinit.  It is expected to be linked to non-volatile memory.  If using RAM and linking to RAM, then .const is initialized only when loaded by the emulator. Example below:

     

    const int x=5;    // x is put in .econst.  Cannot be changed in C code.

    int y=5;          // y is put in .ebss, 5 is put in .cinit

     

    .econst section must be linked to non-volatile, or won’t work standalone (without emulator).

  • Thank you very much for your answer. It doesn't seem to be the issue, unfortunately. I tried to remove the "const" on the few variables that had it, and the issue is the same.

    Moreover (and I could be wrong, I never spent much time looking at where things are stored in memory and assumed the default was sensible), if I read correctly the .map and .cmd files, the const variables were already in flash.

    From the .map file : 

    .econst    0    003f6000    00000118     
                      003f6000    00000100     DSP2803x_PieVect.obj (.econst:_PieVectTableInit)
                      003f6100    00000010     Control_C28x.obj (.econst:_IqDivOffset)
                      003f6110    00000008     Control_C28x.obj (.econst:_IqDivShift)

    And from the .cmd file (TI default "F28035_CLA_C.cmd) : 

    MEMORY
    {
    PAGE 0:    /* Program Memory */
               /* Memory (RAM/FLASH/OTP) blocks can be moved to PAGE1 for data allocation */
       RAMM0       : origin = 0x000050, length = 0x0003B0     /* on-chip RAM block M0 */
       RAML3       : origin = 0x009000, length = 0x001000     /* on-chip RAM block L3 */
       OTP         : origin = 0x3D7800, length = 0x000400     /* on-chip OTP */
       FLASHH      : origin = 0x3E8000, length = 0x002000     /* on-chip FLASH */
       FLASHG      : origin = 0x3EA000, length = 0x002000     /* on-chip FLASH */
       FLASHF      : origin = 0x3EC000, length = 0x002000     /* on-chip FLASH */
       FLASHE      : origin = 0x3EE000, length = 0x002000     /* on-chip FLASH */
       FLASHD      : origin = 0x3F0000, length = 0x002000     /* on-chip FLASH */
       FLASHC      : origin = 0x3F2000, length = 0x002000     /* on-chip FLASH */
       FLASHA      : origin = 0x3F6000, length = 0x001F80     /* on-chip FLASH */
       CSM_RSVD    : origin = 0x3F7F80, length = 0x000076     /* Part of FLASHA.  Program with all 0x0000 when CSM is in use. */
       BEGIN       : origin = 0x3F7FF6, length = 0x000002     /* Part of FLASHA.  Used for "boot to Flash" bootloader mode. */
       CSM_PWL_P0  : origin = 0x3F7FF8, length = 0x000008     /* Part of FLASHA.  CSM password locations in FLASHA */
    
       IQTABLES    : origin = 0x3FE000, length = 0x000B50     /* IQ Math Tables in Boot ROM */
       IQTABLES2   : origin = 0x3FEB50, length = 0x00008C     /* IQ Math Tables in Boot ROM */
       IQTABLES3   : origin = 0x3FEBDC, length = 0x0000AA	  /* IQ Math Tables in Boot ROM */
    
       ROM         : origin = 0x3FF27C, length = 0x000D44     /* Boot ROM */
       RESET       : origin = 0x3FFFC0, length = 0x000002     /* part of boot ROM  */
       VECTORS     : origin = 0x3FFFC2, length = 0x00003E     /* part of boot ROM  */
    
    PAGE 1 :   /* Data Memory */
               /* Memory (RAM/FLASH/OTP) blocks can be moved to PAGE0 for program allocation */
               /* Registers remain on PAGE1                                                  */
       BOOT_RSVD   : origin = 0x000000, length = 0x000050     /* Part of M0, BOOT rom will use this for stack */
       RAMM1       : origin = 0x000400, length = 0x000400     /* on-chip RAM block M1 */
       RAML0       : origin = 0x008000, length = 0x000800     /* on-chip RAM block L0 */
       CLARAM0     : origin = 0x008800, length = 0x000400
       CLARAM1     : origin = 0x008C00, length = 0x000400
    
       CLA1_MSGRAMLOW   : origin = 0x001480, length = 0x000080
       CLA1_MSGRAMHIGH  : origin = 0x001500, length = 0x000080
       
       FLASHB      : origin = 0x3F4000, length = 0x002000     /* on-chip FLASH */
    
    }
    
    /* Allocate sections to memory blocks.
       Note:
             codestart user defined section in DSP28_CodeStartBranch.asm used to redirect code
                       execution when booting to flash
             ramfuncs  user defined section to store functions that will be copied from Flash into RAM
    */
    
    SECTIONS
    {
    
       /* Allocate program areas: */
       .cinit              : > FLASHA      PAGE = 0
       .pinit              : > FLASHA,     PAGE = 0
       .text               : >> FLASHC | FLASHE      PAGE = 0
       codestart           : > BEGIN       PAGE = 0
       ramfuncs            : LOAD = FLASHD,
                             RUN = RAMM0,
                             LOAD_START(_RamfuncsLoadStart),
                             LOAD_END(_RamfuncsLoadEnd),
                             RUN_START(_RamfuncsRunStart),
                             PAGE = 0
    
       csmpasswds          : > CSM_PWL_P0  PAGE = 0
       csm_rsvd            : > CSM_RSVD    PAGE = 0
    
       /* Allocate uninitalized data sections: */
       .stack              : > RAMM1       PAGE = 1
       .cio                : >> RAML0 | RAMM1      PAGE = 1
       .sysmem             : > RAMM1       PAGE = 1
       .ebss               : > RAML0       PAGE = 1
       .esysmem            : > RAML0       PAGE = 1
    
                         
       /* Initalized sections go in Flash */
       /* For SDFlash to program these, they must be allocated to page 0 */
       .econst             : > FLASHA      PAGE = 0
       .switch             : > FLASHA      PAGE = 0
       
       /* Allocate IQ math areas: */
       IQmath              : > FLASHA      PAGE = 0            /* Math Code */
       IQmathTables        : > IQTABLES,   PAGE = 0, TYPE = NOLOAD
       
       .bss_cla		       : > CLARAM0,   PAGE = 1
       .scratchpad         : > CLARAM0,   PAGE = 1
       
       Cla1Prog            : LOAD = FLASHD,
                             RUN = RAML3,
                             LOAD_START(_Cla1funcsLoadStart),
                             LOAD_END(_Cla1funcsLoadEnd),
                             RUN_START(_Cla1funcsRunStart),
                             LOAD_SIZE(_Cla1funcsLoadSize),
                             PAGE = 0
       
       Cla1ToCpuMsgRAM     : > CLA1_MSGRAMLOW,   PAGE = 1
       CpuToCla1MsgRAM     : > CLA1_MSGRAMHIGH,  PAGE = 1
       Cla1DataRam0		   : > CLARAM0,		  PAGE = 1
       Cla1DataRam1		   : > CLARAM1,		  PAGE = 1
       
       GROUP	           : LOAD = FLASHB,
                             RUN = CLARAM1,
                             LOAD_START(_Cla1mathTablesLoadStart),
                             LOAD_END(_Cla1mathTablesLoadEnd),
                             RUN_START(_Cla1mathTablesRunStart),
                             LOAD_SIZE(_Cla1mathTablesLoadSize),
                             PAGE = 1
       
       {
        CLA1mathTables
        .const_cla
       }   
    	
       CLAscratch          : 
                             { *.obj(CLAscratch)
                             . += CLA_SCRATCHPAD_SIZE;
                             *.obj(CLAscratch_end) } > CLARAM0,
    					     PAGE = 1
    					 
      /* Uncomment the section below if calling the IQNexp() or IQexp()
          functions from the IQMath.lib library in order to utilize the
          relevant IQ Math table in Boot ROM (This saves space and Boot ROM
          is 1 wait-state). If this section is not uncommented, IQmathTables2
          will be loaded into other memory (SARAM, Flash, etc.) and will take
          up space, but 0 wait-state is possible.
       */
       /*
       IQmathTables2    : > IQTABLES2, PAGE = 0, TYPE = NOLOAD
       {
    
                  IQmath.lib<IQNexpTable.obj> (IQmathTablesRam)
    
       }
       */
        /* Uncomment the section below if calling the IQNasin() or IQasin()
           functions from the IQMath.lib library in order to utilize the
           relevant IQ Math table in Boot ROM (This saves space and Boot ROM
           is 1 wait-state). If this section is not uncommented, IQmathTables2
           will be loaded into other memory (SARAM, Flash, etc.) and will take
           up space, but 0 wait-state is possible.
        */
        /*
        IQmathTables3    : > IQTABLES3, PAGE = 0, TYPE = NOLOAD
        {
    
                   IQmath.lib<IQNasinTable.obj> (IQmathTablesRam)
    
        }
        */
    
       /* .reset is a standard section used by the compiler.  It contains the */
       /* the address of the start of _c_int00 for C Code.   /*
       /* When using the boot ROM this section and the CPU vector */
       /* table is not needed.  Thus the default type is set here to  */
       /* DSECT  */
       .reset              : > RESET,      PAGE = 0, TYPE = DSECT
       vectors             : > VECTORS     PAGE = 0, TYPE = DSECT
    
    }

    I have tried to toggle a GPIO in some conditions, since that seems to work. 

    The application is a PFC converter. The voltage control loop is in the C28x, whereas the current control loop is in the CLA. The calculation of the average current reference (_iq type) in the main C28x interrupt gives a result (GPIO toggles properly under the condition "IrefDC > 0), but the next step, the "AC" current reference (float type, for use in the CLA) seems to go crazy (GPIO toggles randomly for a while, then stop in the wrong position, under the condition "Iref > 0.0"). 

    I don't know if that helps. It looks like IQmath is also something that is managed in a different way in memory (?), so could that be part of the issue ?

    Thanks again for your help.

  • Hi,

    When you load the program into the MCU using a JTAG emulator, CCS fills any unititialized RAM with 0. Therefore you might get a different behaviour if you have any variables which are not explicitely initialized.

    Furthermore it seems from your memory map that you are programming the CLA using the C compiler. If you declare any constants in the C code targeting the CLA (eg. gains or saturation values) you have to initialize them yourself. It won't be taken care of by the .cinit function that Hareesh mentioned. The process is similar to what you would do with the ramfuncs section but with the .const_cla section.

    The following topic might help you: https://e2e.ti.com/support/development_tools/compiler/f/343/p/535988/1962459

    Cheers,

    PB

  • Hi,

    Thank you very much for your answer Pierre. I need to dig deep and wrap my head around the link you indicated, but this could definitely be the case.

    So far, I have absolutely nothing in .const_cla section. It is not even initialized. All the variable I use in the CLA code is initialized in a .c file.

    In Control_C28x.c :

    #pragma DATA_SECTION(f_dutyMax, "CpuToCla1MsgRAM");
    #pragma DATA_SECTION(f_dutyMin, "CpuToCla1MsgRAM");
    #pragma DATA_SECTION(f_I_Ki, "CpuToCla1MsgRAM");
    #pragma DATA_SECTION(f_I_Kp, "CpuToCla1MsgRAM");
    
    
    float32	f_dutyMax = DUTY_MAX;
    float32	f_dutyMin = -100.0;
    float32	f_I_Ki = 3.0;
    float32	f_I_Kp = 10.0;

    And in Control.h (used in Control_CLA.cla) : 

    extern float32	f_dutyMax;
    extern float32	f_dutyMin;
    extern float32	f_I_Ki;
    extern float32	f_I_Kp;

    Using the examples of CLA provided in ControlSuite (this is my very first project using CLA) and the informations on the wiki, I placed all variables used in the .cla file in the .c file for initialisation, with the relevant pragma (either #pragma DATA_SECTION(XXX, "CpuToCla1MsgRAM"); or #pragma DATA_SECTION(YYY, "Cla1ToCpuMsgRAM"); ). From the examples and the wiki, it looked like the way to go, but apparently, I was misguided. 

    I guess I'll get back to figuring this out. Since none of that is very intuitive, it would have been nice to have an example of how to do things right in ControlSuite though ...

  • Hi,

    There is something I don't understand ... The way I did things, all variables used by the CLA are declared in a regular C28 .c file, and stored in RAM in a CLA-accessible area. Since the (non constant) variables are declared in a C28 .c file, aren't they initialized as normal (non constant) variables ? If so, shouldn't it work also in non-debug mode ? (and in which case, is it going to fail if some variables become const but still without changing anything else ?)

    Thanks in advance,

    Adrien

  • Hi Adrien,

    Adrien thurin said:
    Since the (non constant) variables are declared in a C28 .c file, aren't they initialized as normal (non constant) variables ?

    Yes, that is correct. If they are prototyped in a shared header file, and defined in a .c file they can be initialized. If the variables are global to just the .cla file, i.e. not shared and having file scope only, then they wont be initialized as there is no .cinit equivalent to initialize those variables.

    If its easier you could simply make all globals shared between the c28x and CLA, and have the c28x initialize them before passing control of the RAM over to the CLA. globals defined within the .cla file are placed in the ".bss_cla" section while shared globals need to be manually placed with pragmas.

  • Hi Vishal,

    Thanks for your answer. It makes total sense !

    I still can't get it to work, though, and I kind of ran out of ideas. There has been some improvements : PWMs switch, but the switching makes no sense (whereas previously, they wouldn't start at all). This improvement happened after I moved the CLA initialisation after the CLA clock power up (that was a dumb mistake !). I have also moved absolutely all variables used by the CLA in the c28x .c file, with the appropriate pragmas (even previously local CLA variables are now global and defined in the c28x .c file). The .map file shows that all CLA variables are in either Cla1ToCpuMsgRAM (variables modified by CLA) or CpuToCla1MsgRAM (variables read but not modified by CLA). The initialisation process is pretty much the same as in the examples in controlsuite too. And yet, the switching is very different in debug mode and after a reset : variable duty-cyle for sine-ish current in debug mode, 0 or max duty cycle / all or nothing in non-debug mode. It looks as if the control loop has gone crazy, which could be the case if the gains, reference, or other variables, weren't read properly. 

    If you had any idea about what could be going on, or what I could do to try to figure things out, that would be incredibly helpful.

    Thank you very much again,

    Adrien

  • Hi,

    I figured out what the second half of the issue was. I had an array I used to store a number of measures, in order to perform a floating average. It was initialized as such :

    _iq MyArray[N] = {0};

    It seems that in debug mode, the whole array is initialized to 0. But outside of debug, it doesn't seem to be the case, causing the floating average to start off with non-zero (sometimes unexpectedly negative) values. Because of that, all the control loops went ballistic.

    In the end, a simple loop to initialize the whole array to 0 fixed the issue.

    Thanks to everyone for your help.

    Adrien