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/CC1352R: Suddenly debugging stops

Part Number: CC1352R


Tool/software: Code Composer Studio

When I debug my program it happens that debugging seems to stop. My guess is that I set a register in the processor that "should not be set". After that the suspend button in the code composer window is disabled. I can only Terminate the debugging. The processor seems also to do some kind of stop. At least nothing happend anymore.

From out good old Atmet processor and studio I know that I can always suspend/pause execution and the studio shows me where the processor is. Practically the CPU is executing something and the program counter points to something. It's another question whether the instructions behind the program counter make sense.

I use TI-RTOS and have even a breakpoint in the exception handler. But this is also not triggered.

Can it be that I disable somehow the debugging support itself? Or the processor does a reset because of an error but doesn't start to run after the reset?

So what could be a state that I cannot even suspend/pause execution via my XDS110 debugger?

Regards
Erwin

  • Hello,

    Erwin Ahlers said:
    When I debug my program it happens that debugging seems to stop. My guess is that I set a register in the processor that "should not be set". After that the suspend button in the code composer window is disabled. I can only Terminate the debugging. The processor seems also to do some kind of stop. At least nothing happend anymore.

    If I had to guess, it sounds like you don't have the correct debug context. Can you confirm that you have the correct context selected in the debug view?

    Thanks

    ki

  • I have now the following scenatio:

    Iset a breakpoint in my code. When debugging it stops at this breakpoint. I guess a debug context is shown, which doesn't look so bad:

    If I continue then running for some seconds, the suspend button is still enabled but pressing it leads to

    My device isn't doing anything and I can only stop debugging. This case is somewhat different to the case where even the suspend button is disabled but the result is the same. I can't stop the device to see where I am to guess why I came into this solution.

    The link to the other issue shows the property page of the project with some connections. In my case not all is filled.

    Can this be a problem? When I press Verify... a window appears telling everything is ok.

    I'm quite sure I have a problem in my code which puts the device in that state showing this behaviour. But I have no idea what this could be. As written, I thought with a debugger I can always pause execution. Of course only when it is connected. But here it seems the device is loosing connection to XDS110. Connection between PC and XDS110 (which is very fragile because of this "unlucky" virtual com port behaviour) is still ok; at least I'm pretty sure.

    Regards

    Erwin

  • I think it is so that the suspend button is never enabled when I don't have a breakpoint before the device stops working.

    I debugged it so far that execution stops when I do a cleanup of I2C. I used I2C but wand to deconfigure it after usage. So I do

        Hw.SignalPoint(4);
        HWREG(I2C0_BASE + I2C_O_SIMR) = 0;
        HWREG(I2C0_BASE + I2C_O_SOAR) = 0;
        //Eventuell vohandene Interrupt Pending Bits/Flags löschen
        HWREG(I2C0_BASE + I2C_O_SICR) = I2C_SICR_STOPIC + I2C_SICR_STARTIC + I2C_SICR_DATAIC;
        //Master disablen. Der sollte zwar schon disabled sein, kostet aber auch nicht viel.
        HWREG(I2C0_BASE + I2C_O_MCR) = 0;
        HWREG(I2C0_BASE + I2C_O_MCTRL) = 0;
        Hw.SignalPoint(5);
    
        //Die Portfunktion (Data und Clock) der Pins zurücksetzen
        HWREG(IOC_BASE + (4*24)) = IOC_IOCFG0_PULL_CTL_DIS;
        HWREG(IOC_BASE + (4*25)) = IOC_IOCFG0_PULL_CTL_DIS;
        //HWREG(GPIO_BASE + GPIO_O_DOE31_0) &= ~(1 << 25);
        Hw.SignalPoint(6);

    As you can see I implemented some signal points that blinks a LED. The program runs until point 5. When I comment the two line where I put the used pins to normal mode again the program runs also to signalPoint 6. I also set a breakpoint at this line and started to step even on assembler level. From that it seems as suddenly my Hw instance seems to be gone. When in the assembler code the SignalPoint function should be started with parameter 6, stepping stops and nothing works anymore. But when the object exists at SignalPoint 5 it should exist at point 6 too, right?

    The objects are created inside a function so they should reside on the stack. I have no memory management system running. Could this be an issue? Are locally created objects also call the new/alloc function that requires a heap? But I don't have a heap.

  • Erwin Ahlers said:

    If I continue then running for some seconds, the suspend button is still enabled but pressing it leads to

    This error indicates that the debugger was unable to but the CPU in debug mode:

    https://software-dl.ti.com/ccs/esd/documents/ccs_debugging_jtag_connectivity_issues.html#device-hung

    The cause can vary a bit. It could be some contention issue with your application, though I am not sure.

    I am going to bring this thread to the attention of the device experts. They may be able to provide more suggestions.

    Thanks

    ki

  • Reading the interesting provided link brings me to another possible issue. The CC1352 has this second RF core. In my case I ignore this core completely for the first two to three seconds. So can we have here any kind of multi core issue? Should I do some initialisation of or for this RF core? Just to have the HW ready that no contention between both cores can happen?

    Erwin

  • I also observe that the device behaves differntly when I start it with the debugger and when I start without debugger. We've seens this already before but then suddenly this differnt behaviour was gone. I tried to find some information what's the difference when I run my device with connected debugger and when it starts without debugger. Unfortunately I had no success. Can you provide me some information source to understand what's the difference?

  • Hi Erwin, 

    Is it possible to share the project? As you have opted to do the implementations yourself using register level access, it is hard to give you pointers on what might be the issue. Have you checked if there is any unexpected interrupt happing as a result of the IO reconfiguring?

  • Sorry, I can't share the whole project. But to give you an idea what I do: I need a proprietary boot loader that gets the data via I2C. To do that I made a special code section in the last flash page where I then place my bootloader that can override all other flash pages where the normal application is located in. The startup configuration is so that the processor jumps to my bootloader start code in the last flash page. So no HW initialization is done from the application and I have to do it on hand with less other functions to keep the bootloader small (I have just less than one flash page for all the code). I do the implementation in C++ and all the bootloader objects are created inside one function to have them on the stack. After the bootloader functionality is executed the destructors of those objects are called automatically and all memory is freed again.

    I have it already that I can receive and send I2C data but when the destructors are called I think I need a cleanup in HW to do all unset what I have done in my bootloader functionality. I have in mind without that (some times ago already) I figured out problems when the remaining application starts and assumes there is the HW default state. As the application uses TI RTOS I'm not sure if it expects the HW default state.

    When I do my cleanup in the destructor (or also in a special cleanup function executed  before the destructor is called, that makes no difference) I see that the execution stops. Just some minutes ago I observed the following. The exception handler that I have given to TI RTOS was called with the register bits CPU_SCS_CFSR_BFARVALID and CPU_SCS_CFSR_IMPRECISERR. Then I changed my display routine inside the exception handler. Now the exception handler itself is not called anymore. Strange. I guess it has some timing issues, may be with the RF core?

    You mentioned whether I have checked unwanted interrupts. How can I do this? So if an interrupt would occure where I have not located a interrupt serving routine, what would happen and how could I detect this?

  • Erwin, since it looks like you are not using the I2C driver, any reason for this? 

  • In our application we also use our own C++ I2C driver that is also used in other projects working with an ATMEL processor. But in the bootloader I could try another I2C driver. Can you give me a hint how to use it? As said, I'm constrained in flash usage and all this bootloader stuff is executed in the constructor of the first global C++ object that is initiated. So before even main is startet.

  • Hi Erwin,

    I doubt that this is related to the RF code, it does not trigger imprecise errors. It could throw you a "unexpected interrupt" if you left it on and forgot to register it again but that does not seem to be the case.

    Have you tried decoding the exception to track the origin? The following site is quite helpful to get on with that topic: https://interrupt.memfault.com/blog/cortex-m-fault-debug#how-to-debug-a-hardfault-on-an-arm-cortex-m-mcu

    This is a snippet that I commonly use in cases where I can't rely on the TI-RTOS ROV view for decoding (like in the bootloader case):

    /*
    
    \brief     Debug stack pointer.
    \param sp  Stack pointer.
    Provide a view into the CPU state from the provided stack pointer.
    /
    static void
    debugHardfault(uint32_t sp)
    {
    volatile uint32_t r0;  /< R0 register /
    volatile uint32_t r1;  /< R1 register /
    volatile uint32_t r2;  /< R2 register /
    volatile uint32_t r3;  /< R3 register /
    volatile uint32_t r12; /< R12 register /
    volatile uint32_t lr;  /< LR register /
    volatile uint32_t pc;  /< PC register /
    volatile uint32_t psr; /*< PSR register */
    (void)(r0  = sp[0]);
    (void)(r1  = sp[1]);
    (void)(r2  = sp[2]);
    (void)(r3  = sp[3]);
    (void)(r12 = sp[4]);
    (void)(lr  = sp[5]);
    (void)(pc  = sp[6]);
    (void)(psr = sp[7]);
    
    /* Enter an infinite loop. /
    for(;;) { / hang / }
    }
    /---------------------------------------------------------------------------/
    /
    
    \brief  CPU Fault ISR.
    This is the code that gets called when the processor receives a fault
    interrupt. Setup a call to debugStackPointer with the current stack pointer.
    The stack pointer in this case would be the CPU state which caused the CPU
    fault.
    /
    static void
    faultISR(void)
    {
    asm volatile
    (
    "tst lr, #4        \n"
    "ite eq            \n"
    "mrseq r0, msp     \n"
    "mrsne r0, psp     \n"
    "bx %0             \n"
    : / output /
    : / input */
    "r"(debugHardfault)
    );
    }

    Note that it is written for GCC so you might have to adjust the inline assembly depending on the toolchain you use. 

  • Hi,

    I stripped the whole project down to something that I can share. The problem still exists and all my bootloader stuff is in the stripped version as in the real. I put all into All.zip. The iCall directory contains normally just links and could therefore not been added to the zip file. Therefore I inserted the file dummy.txt which can practically ignored.

    In the scope of the C++ constructor I create now an simple I2C driver that even works. But the real I2C functionality is not used in the stripped project. When the I2C driver in the bootloader is not needed anymore, I want to cleanup all what I've done before. In this cleanup the CPU stops to communicate with the debugger proble. When I have the register view open in Code Composer it happens also that register cannot be read, what makes sense when the target doesn't responde. Unfortunately I have it also from time to time (not very often) that everything works when I step through the program. But mostly stepping stops in the I2Cdriver.Cleanup funktionality.

    Would be very beneficial (even for me absolutely necessary) that this problem can be solved.

    All.zip

  • Hi Erwin,

    Thanks for sharing. I will take a swing at looking at your code and see if I can spot what might be happening.

  • Hi Erwin,

    It is the PRCM operations causing you headache as far as I can tell, your "LOAD" calls after PRCM modifications should be followed up with waiting for the load to complete. Try add in:

    while(!(HWREG(PRCM_BASE + PRCM_O_CLKLOADCTL) & PRCM_CLKLOADCTL_LOAD_DONE));

    following any call to:

    HWREG(PRCM_BASE + PRCM_O_CLKLOADCTL) = PRCM_CLKLOADCTL_LOAD;

  • Hi M-W,

    first of all sorry, I saw your answer only now. The E-mail notification I got was misinterpreted from me so I was still in the "wait for answer" state.

    I heve some doubt that the mentioned issue is the problem. There is a loop with 255 turns with a asm(" nop") instruction. With this we normally wait long enough to take the changes into operation. But I agree and came about the same stuff that such a while loop is much better. So thank's for confirmation that my understanding was correct.

    But I have found the real issue. In my cleanup code there is the line HWREG(PRCM_BASE + PRCM_O_PDCTL0) = 0;

    So I disable the peripheral, serial and RFC power domain. After that I try to do an GPIO operation. But GPIO is part of the peripheral power domain so it cannot happen. When keeping the peripheral power domain active, debugging doesn't stop and my application continues as expected.

    Interesting is now that the consequence of this misconfiguration is that the debugger cannot work anymore. JTAG DAP is part of the CPU power domain which cannot be disabled (for good reasons). So is the CPU internally, or better the hardware, in a state where it waits for a state change in  GPIO module which never comes? And there is no protection mechanism for this state?

    Nevermind, I'm happy that the application works now as expected.

    BTW: should I rate now my answer as "This resolves my issue" as it practically does?

    Regards
    Erwin

  • Hi Erwin,

    Interesting, the only part I found in the code you send that disabled the power domains was "HwDeInit" and on my side, this seems like a function that is actually never run (In other words, I saw no issue with the power domain being disabled). On that note, if you actually on your side happened to disable the power domains before, then that would explain the failure. Accessing the unpowered registers is highly undefined in behavior and in some cases it results in the device dropping the JTAG connection (among other things).

    On a side note, the CPU power domain can be powered of as PDCTL1 register in PRCM. This is in-fact always practiced by our power driver. As most of the JTAG is in the AON space, you are fine from a debugging point of view as well. This assuming the device has not fully crashed (like in your case) as the JTAG DAP might not be accessible. These kind of "debugger crashes" typically happen only on errors such as accesses to unpowered peripherals.