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/MSP432P401R: GPIO Interrupts get disabled, intermittently, when not in debug, fixed by hitting reset button

Part Number: MSP432P401R

Tool/software: Code Composer Studio

Hi,

I'm working with the MSP432 launchpad. Long story short, I built a system that interface with an external SoC, through SPI (using DMA) and stream the data over Bluetooth (SPP profile, Bluetopia). The external SoC let me know that there is some data ready by lowering the state of a pin, which I monitor using GPIOs (GPIO_PORT_P4) and manage using its associated event handler. (DMA IRQ is also involved right after, but that's not pertinent for the current situation)

I developed this system over the past two months and everything worked well until I decided to try it as a stand-alone system. When I execute the system without the debugger, the Bluetooth interface, and debugging UART still work properly, but it appears that the GPIOs interrupts handler is not called anymore.

Reading across the forum for similar bugs, someone suggested to hit the reset button see what happens and indeed, after power up, if I hit the reset button for a few seconds, it appears to fix the issue 3 times out of 4.

Now I wonder, is it the correct way to proceed? and what exactly is going on? Eventually, this system is planned to be deployed in the real-world and I need to think ahead as to how it's going to behave when it's going to be out there.

best,

Fred

  • This should not be expected behavior.

    It sounds like you started to have this issue when you switched to a "stand alone system", can you desicribe the difference in these hardware setups? Is it possible there is a difference in your hardware from the prototype to this new system?

    The title says when not in debug, does the issue not appear when you are in debug mode? Can you set a break point to confirm you do not get into the interrupt?

    Since the interrupt seems to work sometimes but not others, perhaps the edge is not being seen by the MSP. A couple thoughts, if your SoC depends on a pull-up/pull-down you might check that is installed (open drain output type). A floating pin might not trigger consistently. Or the MSP432 reset timing does not reach the main code where it is ready for the interrupt by the time the SoC toggles the GPIO, so it does not catch this consistently if reset timing of both devices is not deterministically correct.
  • Hi John,

    Thank you for taking the time to reply, I will try to be more precise.

    In regard to hardware configuration, I'm always using the MSP432 launchpad, with the CC2564 boosterpack. The other SoC I'm interfacing with is powered by the MSP432 as well (for the record, I attached the top element of the ADS1299EEG-FE). I still haven't designed the PCB that will support the system later on.

    The difference between the two setups:

    (1) Debug mode, I use Code Composer Studio (CCS) to build the firmware and flash it by initiating a debug session. I had the system running in that mode for over a month without ever seeing that issue.

    (2) Stand-alone mode, I stop the debug session (and even close CCS for that matter), remove the power from the board. Then, I power-up the board using the USB port, without having CCS running. Alternatively, I alsohave a battery-operated mode that uses the Fuel Tank II booster pack, in which case I do not use the USB port to power the board, but the battery.

    I was able to confirm that the interrupt is not triggered, by adding a Display (printf), which output strings on the serial port. I monitor it using a serial port terminal. I do this without being in a debugging session on CCS. I do not have any break point in the code, the Bluetooth SPP link is still working properly, and the system is processing my commands. 

    Again, if I reset the device, it works 4 times out of 5.

    I read that a low-power mode could be related to this issue, is there anyway by which I could test this hypothesis? How is the power mode interacting with the OS integrated with Bluetopia.

  • Thank you for clarifying.  Debug session prevents the MSP from actually entering certain Low Power Modes (I believe it is LPM3 and up, but I would have to check on that).  Some peripherals cannot wake up the MSP from specific power modes (see table 7-8 of the TRM).  This means that a peripheral might work in debug (since the system isn't actually in that LPM) but then will not work outside of the debug since the system is waiting on a peripheral that cannot wake the MSP.  (This seems a little unlikey since you get operation 4/5 times, but I wouldn't rule it out 100% before testing the hypothesis.

    You can try removing the LPM from your code entirely just as a means to determine if this is causing the issue and then you can go back and enter appropriate LPMs in more clever ways so that you never run into an issue where you are waiting for a peripheral which is incapapble of waking up the device if this is indeed the issue.  (Depending on how your code is structured, be sure you do not mistakenly remove interrupt enables when removing the LPM since sometimes these operations are done together.)

    Can you tell me if you are using RTOS or driverlib or register level programming, just for my reference?

  • (1) I tested the LPM hypothesis. Before, I had no visible LPM instruction. I say no visible, because I'm using Bluetopia and it is possible that the power management is hidden somewhere in there.

    I tried to add an instruction for LPM0 (and also tested with LPM3), right before the program goes in BTPS_ExecuteScheduler(), which doesn't return, and in both cases I observe the same behaviour as before. So no effect.

    To answer your question, I'm using the OS integrated in Bluetopia Demos: BTPS, and driverlib to control the states of the registers.

    (2) While I was at it, I tested a new hypothesis: is there anyway by which the TM4C129 MCU be interacting with my system? I doubt it's as stupid as hanging on the main() breakpoint set by default in debug mode, since the Bluetooth and several modules are working, but could it be preventing or changing the way the program gets executed?

    I removed all jumpers linking the TM4 to the MSP, with the exception of the RESET pin, to be able to reset the MSP. I still get the same behaviour.

    (3) I'm now wondering if the power-up of the system could be an issue. I added an extra load on the system, by connecting the ADS1299, maybe the caps are dragging too much current on power up and this prevents the voltage from rising fast enough? Does that make any sense? I still don't see how that would allow for the Bluetooth to work properly, while killing the interrupts.

    Remains the question of why it works on debug, but when I run in debug, the flashing of the device triggers a reset. And the board has been power-up for a while at that point...

    Please let me know if you can think of anything else, I'll try to think of a way to test the power hypothesis.

     

  • I tried to add a very long delay (4 seconds) at the beginning of the main, to give the time for the power to settle. It had no effect.

    I also noticed that the MAP_PCM_gotoLPM3(); is generally placed in alwhile(1), so I moved my instruction to a task called periodically, no effect either.

    I'm a bit short of ideas right now...
  • Frederic,

    Can you provide me with code or code snippets so I can review how you are implementing the interrupt?  Also, I may have to pull in some other experts on the bluetooth stacks like Bluetopia since I am not as familiar with this if I cannot figure it out from reviewing the code alone.

  • Hi John,

    I'll drop a snippet of code tomorrow, I'm away from work, but I'm reading about the supply voltage supervisor (TRM section, 6.2 PSS Operation).

    I find this:

    <<When SVSMH is configured as a monitor and the VCC voltage falls below the SVSMH
    threshold the module sets the SVSMHIFG interrupt flag and generates an interrupt (only if SVSMHIE = 1).
    If the voltage remains below the SVSMH level and software attempts to clear SVSMHIFG, it is
    immediately set again by hardware. The interrupt flag of SVSMH remains set until cleared by a hard reset
    or by software.>>

    So I wonder if, under my hypothesis that power supply is the cause, the GPIO interrupt could be masked by the SVSMH interrupt flag, which, if it is raised, never gets resetted.

    I'll look into this tomorrow and keep you posted if I find anything.

    Fred
  • Hi John,

    I tried to add an Interrupt handler for the PSS, as explained in previous post, which clears the interrupt flag and disable it. It didn't fix the issue. (side-note,  the NIVC had attached a defaultISR handler, which lead to an infinite while loop. Therefore, it is unlikely that my addition had any effect)

    Here's a code extract from my program that configures the interrupt on GPIO 4.4. I did confirm (logic analyzer) that the signal sent by the ADS1299 was present, even under faulty condition. 

        //DRDY pin (P4.4), this pin trigger interrupts
        GPIO_setAsInputPin(GPIO_PORT_P4, GPIO_PIN4);
    
        // clear any flags set for that pin
        GPIO_clearInterruptFlag(GPIO_PORT_P4, GPIO_PIN4);
        // falling edge sensitivity
        GPIO_interruptEdgeSelect(GPIO_PORT_P4, GPIO_PIN4, GPIO_HIGH_TO_LOW_TRANSITION);
        // enable interrupt for that pin
        GPIO_enableInterrupt(GPIO_PORT_P4, GPIO_PIN4);
        // reduce priority (this prevents the debugging UART from starving and crashing the chip)
        Interrupt_setPriority(INT_PORT4, (1 << 5));
        // enable interrupt for that port
        Interrupt_enableInterrupt(INT_PORT4);
    
        // enable retention for SRAM BANK 1
        SysCtl_enableSRAMBankRetention(SYSCTL_SRAM_BANK1);
    
        // enable global interrupt management
        Interrupt_enableMaster();

    Let me know if you come to think of anything or if you want me to post other segment of code.
  • Fred,

    Just wanted to give you a quick update so you don't think I've forgotten about you.  I'm not seeing anything obviously wrong with this yet, so my plan is to go find someone in the Bluetooth/Bluetopia side of things on Monday to ask them their opinion on this.  Thanks for the patience. 

    Perhaps you can explain to me a bit more about why you need to reduce the priority of INT_PORT4?

  • Hi John,

    Thank you very much. 

    Bluetopia features a UART debugging console, that uses the USB/serial port. When I added interrupts management for the SPI over DMA, I ran into an issue by which the UART gets starved and its buffer overflow. To fix that I increased the length of the UART buffer - from memory it was at ~128 bytes and now it is at 1024 - and after noticing in the debug UART code that the priority for this system was set to high, I reduced the priority of my interrupts, to make sure that UART is free to process its own stuff. Both of these were required to stabilize the program. Eventually, I want to de-activate the console entirely, but I'm still using it to debug and I haven't looked into how to turn it off. I wouldn't be surprised to learn that the problem is related to the console, although the fact that my system works after a reset

    Something else I tried:

    - I mapped the SPI-DMA initialization routine onto a command I send over Bluetooth, so that I can re-init the system manually after boot-up, but that didn't fix it. It really seems like the GPIO interrupt management gets clogged as a whole.

    What I'll try on my end:

    - I'll build the GPIO example that comes with MSPWare and test under the same conditions to see what happens.

    * if the problem doesn't show up, I'll build up my program again from that example, until I find what triggers the bug.

    * If the problem is still there, then we'll have ruled out everything but the GPIO Interrupts on the launchpad, and this will narrow down the search.

    - Just to rule out that element, I'll also test with another launchpad, configured in the same way. 

    I'll keep you posted,

    -Fred

  • Fred,

    Are you able to supply me the program as an attachment (this is a public forum so I understand not everyone is willing to post their source code). 

    Since you suspect the UART, perhaps now is a good time to look into how to disable it? And see if after commenting out the console your program works or not.

    I would say have you checked the GPIO registers that the correct bits are set for the interrupt (thinking the BLE stack might reset these somewhere) but I doubt that is the issue since you said the interrupt fires when in debug mode, correct?

  • Hi John,

    Thank you again for you support. I will deactivate the debugging UART, however I need to work on a another task this week. I have no escape, I need to fix this bug, so give me a few days to wrap up this other thing and then I'll run through the elements we identified.

    I'll post my results here.

    I can't post the program publicly, unfortunately.

  • Hello,
    Apologizes in advance if this has already been discussed/tried. I was wondering if you could determine the state of the IO or perhaps force it high with the internal pull-up to ensure that the GPIO is in a known state.

    Chris
  • Hi Chris,

    I honestly didn't thought this was going to do anything, but given how easy this hypothesis was to test, I gave it a try.

    Since I installed a pull-up on the line, I haven't observed the bug again (tested >5 times), but I fail to understand why? I totally understand what the pull-up does, but why does that fix my issue?

    It is very likely that at the moment of configuring the GPIO, the line was floating. This because the driving element (ADS1299) was powered off, but how can this prevent the initialisation of the GPIO interrupt manager?

    Fred

  • Some more feedback, adding the pull-up greatly improved the stability of the system. I still need to issue a reset pulse after power up for the GPIO Interrupt to work fine, but then it works just fine. I know the TM4C installed on the launch pad issue such a pulse when starting a debugging session, but it won't be on board for stand-alone operation. I will try to circumvent the manual reset pulse using a circuit built around this IC http://www.ti.com/lit/ds/symlink/lm809.pdf, or something similar.

  • Frederic,
    I need to research the ADS1299 device to better understand the drive capabilities, but as you have pointed the pull-up only really helps with the high impedance state.

    Is it possible that the ADS1299 is powering up before the MSP432 and that the GPIO on the MSP432 is at a higher potential than DVCC? I am concerned that you are 'back-powering' the MSP432 through the GPIO and in an indeterminate state. Once the VCC is within a diode drop of the GPIO voltage and the reset is applied, then the device should power up normally.

    Do you have any way of confirming this?

    Thanks,
    Chris
  • Hi Chris,

    I figured it out.

    I feel a bit ashamed for not seeing it earlier, but I didn't understood correctly the way the GPIO Interrupts work. 

    Here's the incorrect code I was running:

    GPIO configuration
    
        //DRDY pin (P4.4), this pin trigger interrupts
        GPIO_setAsInputPin(GPIO_PORT_P4, GPIO_PIN4);
    
        // clear any flags set for that pin
        GPIO_clearInterruptFlag(GPIO_PORT_P4, GPIO_PIN4);
        // falling edge sensitivity
        GPIO_interruptEdgeSelect(GPIO_PORT_P4, GPIO_PIN4, GPIO_HIGH_TO_LOW_TRANSITION);
        // enable interrupt for that pin
        GPIO_enableInterrupt(GPIO_PORT_P4, GPIO_PIN4);
        // reduce priority (this prevents the HCI UART from starving and crashing the BT)
        Interrupt_setPriority(INT_PORT4, (1 << 5));
        // enable interrupt for that port
        Interrupt_enableInterrupt(INT_PORT4);
    
    
    Interrupt Routine
    
    void PORT4_IRQHandler(void)
    {
        uint32_t status;
    
        // get and clear
        status = MAP_GPIO_getEnabledInterruptStatus(GPIO_PORT_P4);
        MAP_GPIO_clearInterruptFlag(GPIO_PORT_P4, status);
    
        // check that it's a PIN4 event
        if(status & GPIO_PIN4)
        {
            //read NB_BYTES_READ bytes
            readBytes(NB_BYTES_READ);
        }
    
    }
    

    Now, you will probably notice the mistake. I thought reading the Interrupt Status was going to return which interrupt was activated. As it turns out, it returns the state of the pin. And given that I'm sensitive to high-low transition, the value returned is '0'.

    The correct interrupt routine is thus:

    /**
     * void PORT4_IRQHandler(void)
     * @brief DRDY interrupt, configured to be falling edge. When triggered, new data is
     *        available. If reading is active, read it.
     */
    void PORT4_IRQHandler(void)
    {
        uint32_t status;
    
        // get and clear
        status = MAP_GPIO_getEnabledInterruptStatus(GPIO_PORT_P4);
        MAP_GPIO_clearInterruptFlag(GPIO_PORT_P4, status);
    
        // check that PIN4 is low
        if(~status & GPIO_PIN4)
        {
            //read NB_BYTES_READ bytes
            readBytes(NB_BYTES_READ);
        }
    
    }

    I'm still puzzled as to why my program ever worked before, because it did work inconsistently, however now its rock solid and works all the time... In other terms, problem solved!

    Thanks everyone who tried to help, that's greatly appreciated. The problem turned out to be simpler than initially anticipated, but we only learn this once it's fixed...

  • Thank you. I really appreciate you circling back around and providing such a detailed explanation.

    Regards,
    Chris

**Attention** This is a public forum