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: hardware watchpoint - Debugger Response Condition

Tool/software: Code Composer Studio

Hello,

I have a situation where GP4[0] is being set high, but not understood why.  So I need to setup a complex hardware watchpoint, with condition of that bit being written, but with other discrimination logic (since it is not any write, but under certain conditions where it is set high unexpectedly).  So I've used this Response Condition in the hardware watchpoint:

( ( ( *(unsigned int *)0x1e26064 & 0x1 ) == 0x1 ) && ( g_mb_debug == 1  ) )

where the 0x1e26064 is the location of BANK45, and the first bit is GP4[0].  g_mb_debug is a local variable to my application which is set high during the period when GP4[0] is being set high unexpectedly.  But when running with this logic, the processor application kind of goes nuts ... leds that shouldn't be active start blinking at a high rate of speed, etc.

Can anyone review my logic above, to see if there is something I've overlooked/doing wrong, that might be causing this issue.  Or maybe it is an issue with the OS/gpio bank support.  I've attached a picture below, showing the exact hardware watchdog setup.

Regards,

Robert

  • Robert56682 said:
    But when running with this logic, the processor application kind of goes nuts ... leds that shouldn't be active start blinking at a high rate of speed, etc.

    Just to be clear on the inner workings of this setup, the processor is going to always halt at this breakpoint and perform the accesses for your "Condition".  If the condition is false it will start the device running again.  From your perspective it will not have halted since this whole transaction will happen on the order of milliseconds. However, repeatedly halting the applications for milliseconds is going to have a major impact on any kind of real-time behavior in your application.  I expect that is related to your LED's going nuts.  

    Robert56682 said:
    g_mb_debug is a local variable to my application

    Doesn't a g_ prefix generally denote a global variable?  In any case, I would suggest at least temporarily making the variable into a global variable.  Otherwise, I think that's going to interfere with your ability to halt at the proper place.  For example, if some other thread has an errant pointer that is writing to your register, then that local variable wouldn't be in context and so the debugger wouldn't halt.

    Another thought...  In this case of a failure does the complete register have a repeatable value?  If for example there is a specific errant data value being written to this address then you could use the "With Data" field to specify the errant data value.  That would allow the comparison to occur in the silicon and not incur the constant stop/start artifacts.

  • Brad Griffis said:

    Just to be clear on the inner workings of this setup, the processor is going to always halt at this breakpoint and perform the accesses for your "Condition".  If the condition is false it will start the device running again.  From your perspective it will not have halted since this whole transaction will happen on the order of milliseconds. However, repeatedly halting the applications for milliseconds is going to have a major impact on any kind of real-time behavior in your application.  I expect that is related to your LED's going nuts.  

    Ah, didn't realize that.  The LEDs themselves are not active in my application.  So whatever is occurring, via the stop/start, is somehow sending values their way.  But I agree the stop/start is not going to work well, so I'll not focus on that too much.

    Brad Griffis said:

    Doesn't a g_ prefix generally denote a global variable?  In any case, I would suggest at least temporarily making the variable into a global variable.  Otherwise, I think that's going to interfere with your ability to halt at the proper place.  For example, if some other thread has an errant pointer that is writing to your register, then that local variable wouldn't be in context and so the debugger wouldn't halt.

    Yeah, g_ does indicate global, and it is (g_mb_debug is a global unsigned int).

    Brad Griffis said:

    Another thought...  In this case of a failure does the complete register have a repeatable value?  If for example there is a specific errant data value being written to this address then you could use the "With Data" field to specify the errant data value.  That would allow the comparison to occur in the silicon and not incur the constant stop/start artifacts.

    Here's the scenario ... maybe you can see if it lends itself to the "With Data":  GP4[0] is being used as the TX Enable for modbus.  It goes high at the beginning of the packet, and low after, under my control.  And that occurs for some time successfully ... minute or two, but then the last working time it goes low, it immediately goes back high ... within useconds.  I didn't command it to go high, but it does, and throws off/stops the modbus transmissions.  So, per your question, it's a known data value 0x043A0001 (the 1 in LSB is GP4[0] high), but that occurs also when TX enable is intentionally set high (as part of the packet transmission).  How to get around that?  (the data value is problem only under certain conditions).
    Thanks,
    Robert
  • Here's a thought... I see from the address you're monitoring that you're using the OUT_DATA register. I recommend making a quick change to your code that sets and clears this bit to stop using OUT_DATA. Rather than perform a read-modify-write to OUT_DATA, you should be doing a simple write to SET_DATA or CLEAR_DATA. The issue could be unprotected accesses to OUT_DATA. If there's other code in the system also accessing this register and if an interrupt happens to fire in the middle of your read-modify-write, then you can end up writing a bad value. Using the SET_DATA and CLEAR_DATA registers avoids that race condition. It's also more efficient because it avoids a slow read on the CFG bus.
  • Sounded like solid logic (avoid race condition from access in other parts of my application), and I was hopeful! ... but same result. After min or three, the last intentional CLR of GP4[0] is follow-ed up by it going unintentionally high again 1 us later.
  • Regardless of it not resolving the issue, I strongly recommend you keep that update as a permanent improvement. It's definitely the way to go. With that in place, can you check the watchpoint on the OUT_DATA register to see if there's any other code in the system accessing that register? If so, you need to make sure that EVERYONE is using the "set" and "clear" registers.
  • 10-4, good point. I'm going through a scrub of all possible OUT_DATA uses. Would you have a better way of doing just a plain toggle on an GPIO pin then the following. I didn't see a good way to do without the initial OUT_DATA read.

    void debug_toggle_tp14( void )
    {
    uint32_t
    t_u32;

    t_u32 = ( (gpio_regs_t *)GPIO_BANK23 )->OUT_DATA;

    if ( ( t_u32 & GP2P12 ) == GP2P12 )
    {
    ( (gpio_regs_t *)GPIO_BANK23 )->CLR_DATA = GP2P12
    }
    else
    {
    ( (gpio_regs_t *)GPIO_BANK23 )->SET_DATA = GP2P12
    }
    }
  • That's a big improvement. Too bad there's not a TOGGLE_DATA register! To be 100% safe, you may need to disable interrupts before the read, and then restore (not enable) interrupts after the write. The current code would have in issue in the following scenario:

    1. Someone calls debug_toggle_tp14().
    2. The OUT_DATA register has been read, but you haven't yet written the SET/CLR_DATA register.
    3. An interrupt occurs, perhaps causing a context switch, etc.
    4. Someone else calls debug_toggle_tp14().
    5. Context returns back to the original call, but it basically has no impact because someone else already toggled it. So in this case you missed a toggle.
  • Great points. I'll take a look at implementing that. In that particular case, the toggle routine wouldn't be called in multiple locations, but I'd like to have that robustness overall, and other places where GPIO toggles like that are being done.

    Some preliminary good news. I scrubbed all the OUT_DATA usages (and there were some others active) and made the SET/CLR_DATA substitutions, and modbus has been running for 20 minutes. Now, the true test will be hours/days, but it's never run that long, so calling it a victory at this point.

    Thanks!
    Robert

    P.S. I'll come back and mark this as answered in day or two, assuming it continues successfully.
  • Still running after a day. We'll mark this one V for victory.

    Thanks again,
    Robert