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.

EK-TM4C123GXL: Writing to Port B Causes Interrupt on Port D???

Part Number: EK-TM4C123GXL

Hi guys - I've spent significant time toying with the code below and cannot for the life of me figure out the odd behavior.  Originally this code was part of a larger project I've been working on but have since, in attempts to determine what is happening, stripped the code down to it's essentials (what you see below) and the issue persists.

As you'll see below, I've configured pins B0-thru-B7 as general purpose digital output and I've configured pins D0-thru-D3 as general purpose digital input.  The D0-thru-D3 pins are set to trigger an interrupt.  I have these hooked into some typical buttons on a bread board, so that when a button is pressed the interrupt triggers.

Now, what's happening is that the interrupt is mysteriously being triggered every time the write to GPIO_PORTB_DATA_R occurs with differing data.  If I comment out the writes to GPIO_PORTB_DATA_R the port D interrupt is only triggered when I press a button on my bread board (as it should).

Also, if I change the while loop in main to just write a single value to GPIO_PORTB_DATA_R it will trigger the interrupt once (when it writes this initial value) and then never agin for subsequent writes (always of the same value).  So it appears it only triggers the port D interrupt when updating the value in port B's data.

I have no idea why this is happening.  I've followed the GPIO configuration steps from the datasheet (section 10.3) as you'll see in the comments in my InitPortB and InitPortD functions.

Any thoughts anyone might have are very welcomed as I'm pretty much out of ideas as to why this is occurring.

#include <stdint.h>
#include "inc/tm4c123gh6pm.h"

void InitPortB()
{
    // Step 1: Enable a clock to port D
    SYSCTL_RCGCGPIO_R |= 0x02;

    // Step 2: Set the direction (output)
    GPIO_PORTB_DIR_R = 0xFF;

    // Step 3: Configure the pins to GPIOAFSEL - Skipping as the pins are GPIO by default

    // Step 4: Skipping, I don't care about drive strength

    // Step 5: Skipping, not using pull-up, down or open drain functionality

    // Step 6: Configure the as digital
    GPIO_PORTB_DEN_R |= 0xFF;

    // Step 7: Skipping, not using an interrupt with these pins

    // Step 8: Unlock the port/pins to allow writing to them
    GPIO_PORTB_LOCK_R = 0x4C4F434B;
    GPIO_PORTB_CR_R = 0xFF;
}

void InitPortD()
{
    // Step 1: Enable a clock to port D
    SYSCTL_RCGCGPIO_R |= 0x08;

    // Step 2: Set the direction (input)
    GPIO_PORTD_DIR_R &= ~0x0F;

    // Step 3: Configure the pins to GPIOAFSEL - Skipping as the pins are GPIO by default

    // Step 4: Skipping, I don't care about drive strength

    // Step 5: Skipping, not using pull-up, down or open drain functionality

    // Step 6: Configure the as digital
    GPIO_PORTD_DEN_R |= 0x0F;

    // Step 7a: Disable the interrupt while it's being configured
    GPIO_PORTD_IM_R &= ~0x0F;

    // Step 7b: Configure the IS field in the GPIOIS register and the IBE field in the GPIOIBE register
    GPIO_PORTD_IS_R &= ~0x0F;  // Configure the interrupt for edge detection
    GPIO_PORTD_IBE_R &= ~0x0F; // Interrupt generation is controlled by the GPIOIEV
    GPIO_PORTD_IEV_R |= 0x0F; // Detect interrupt on a rising edge

    // Step 7c: Clear the GPIORIS register
    GPIO_PORTD_RIS_R &= ~0x0F;

    // Step 7d: Unmask the port by setting the IME field in the GPIOIM register
    GPIO_PORTD_IM_R |= 0x0F;

    // Step 8: Skipping, not writing to the pins so don't care about locking


    // Enable the Port D interrupt
    NVIC_EN0_R |= (1<<3);
}

void PortDInterruptHandler()
{
    GPIO_PORTD_ICR_R |= 0xFF; // Clear the interrupt
}

int main(void)
{
    InitPortB();
    InitPortD();

    uint32_t counter = 0;
    while(1)
    {
        if(counter % 2 == 0)
        {
            GPIO_PORTB_DATA_R = 99;
        }
        else
        {
            GPIO_PORTB_DATA_R = 0;
        }
        ++counter;
    }
}

  • Quick look at the code doesn't suggest anything..

    Possible you've got hardware issues?  Floating inputs of portD close enough to portB outputs to couple an edge?  Maybe try setting all unused portD pins to outputs and giving them a value so that they're driven.

    Ben

  • Might this be - yet another - manifestation of the "insane" decision to tie 2 pins upon Port B directly to Port D?

    (claimed done for (long) past compatibility - yet regularly wreaks (CURRENT) TORMENT!     Check the board schematic (LPad) - those DEVIL Pins are marked.    (visible via magnification...)   R9 & 10 perform this (universally unwanted) accommodation!

    Firm/I "always" yank those 0Ω "Plague-istors" and "tomb-stone" them - which well marks those boards as "FIXED."

    For the record: PD0 ties to PB6 & PD1 ties to PB7.      For YEARS I've urged this vendor to, "supply those plague-istors in a small bag" - so that those "One Per-Centers" (if that) - who seek (past) MSP compatibility - are spared the Pain & Suffering forced upon SO MANY of the PREDOMINANT MASSES!     (who have zero interest in "ancient-times" compatibility - to a lesser MCU...)

  • Oh yeah, that would do it. Remove R9 and R10 from the board. I've never used the 123 Launchpad - always the 1294.

    Ben
  • Benjamin Bawkon said:

    Quick look at the code doesn't suggest anything..

    Possible you've got hardware issues?  Floating inputs of portD close enough to portB outputs to couple an edge?  Maybe try setting all unused portD pins to outputs and giving them a value so that they're driven.

    Hi Ben, thanks for the suggestion.  I just tried this as you suggested and unfortunately the same behavior persists.  Interesting enough though, trying some other tweaks I've found that the value I need to write to GPIO_PORTB_DATA_R must be larger than 63 (decimal) in order for it to trigger the Port D interrupt.  63 decimal is equal to 00111.1111 binary.  I then also tried 128 decimal (1000.0000 binary) and this also triggers the interrupt.  

    So, there must be something about setting B6 and B7.  I've re-read (multiple times) through section 10.2.1.2 of the datasheet ("Data Register Operation") and I don't see any issues.  Based on the information in this section, it seems quite clear to me that I can set all pins high for port B by setting 0x4000.53FC to 0xFF.  Of course, GPIO_PORTB_DATA_R is #defined as this memory address (0x4000.53FC) cast to a dereferenced volatile uint32_t pointer....  So, I see nothing wrong here :(

    I'm going to try and switch from Port B to a different Port and see if the issue persists.

  • Yes, as cb1 pointed out, PB6 & PB7 are tied to PORT D via R9 and R10
  • ^ Sorry, was writing my previous response while you two both posted.... So, my mind is officially blown. You are suggesting *physically* removing resistor R9 and R10 from the board? I'm a software developer, not really a hardware dude, (and am old enough to know my limitations). I own a soldering iron who's burnt up tip is slightly smaller than a #2 pencil (not the sharpened point of the pencil). Honestly, I shouldn't even be allowed own a soldering iron. :)
  • No joke, just crack them off the board if you're that worried about soldering. Just grab them with a pair of needle nose and squeeze. The ceramic will pretty much explode. Nothing to worry about.

    Those ARE your problem. Get rid of them.
  • I must thank poster Ben for his kindness in memorializing my "first identification" of the NOTORIOUS R9 & R10 Imposition.
    Remove - and ideally tomb-stone each resistor. (i.e. tack-solder them to just one pad - vertically (i.e. like a grave-stone) this serves as clear visual confirmation that you've, "Readied this board for actual SERVICE" (not hoped for "compatibility" - which directly leads to your (and hundreds of others) Pain & Suffering!

    Any six year old - armed w/cell-phone - should be able to solder. (unless such "slave labor" is banned - your state...)

    Aside to "poster Ben" - from bitter experience - while NOT suitable for Terrence - the "tombstone suggestion" superbly marks such boards as "Ready for use!"     We've employed 100's of such boards - and always & only "tombstone those (delightful) Plague-Istors!"      (even w/"Pick n Place & 20 foot reflow oven - pointless to duplicate what's been (otherwise) nicely done.     we (slightly) mod the pcb - so as to avoid "restrictive, board usage guidelines...")

  • I'm sure it works fine, but leaving tombstoned parts is a big no-no in any kind of high vibration environment. The part can end up being FOD if it breaks free, or worse, pull the bad off the board and take a trace with it. Would highly suggest removing completely and then paint-dot on the board to visually indicate completion.

    Ben
  • Yes - of course you are right! Yet - for in-house experimentation - the tombstone is "unmistakable" (really "pops") and that was our objective.

    If I may (temporarily) remove my "patting hand" from my back - we STILL have "Work to Do!" The fact that the insipid cross connect existed - may not entirely explain how the interrupt was MISSED - upon its targeted port. (unless one of the "tied pins" was set to output - but I chase (first) the "low hanging fruit" - and read the code downstream - should that be necessary...
  • Was it missed? The interrupt is configured as a interrupt on change / edge detect. Writing the same value to PORTB[7:6] wouldn't trigger an interrupt. I think it fired every time it should based upon the tied port pins.
  • My point (and I admit to having only "briefly scanned" the code) is that, "No Port D Interrupts should have been configured and/or enabled" - such "unexpected" (possibly illegal) interrupts upon Port D - bear examination - do they not?     Had the poster "wanted" interrupt upon Port D - his "surprise" (and forum PROTEST) upon its arrival - would NOT have resulted!     That's what's been MISSED!

    Repeating poster's subject line: "Writing Port B - yields Interrupt on Port D!"      Unless that Port D was specifically programmed and enabled to recognize such interrupt - I find that behavior (Port D interrupting) "STILL" unexplained...

  • Port D was configured for edge interrupts. Original poster does want Port D interrupts and configured them as such.
  • Ok - sorry for putting you thru the code read - his title did not make that fact (especially) clear - seemed (to me) to imply that (only) Port B should respond (interrupt) upon arriving "writes."

    Thanks your efforts - perhaps we can "share" in the "fix" achieved via the banishment of those Plague-Istors.
  • You shouldn't be using these boards in production anyway.

    Robert
  • Apologies guys, I had to step away for a bit.  Appreciate the additional info.  Also, apologies for any vagueness in the title as yes, it doesn't specify that I meant for interrupts to occur on port D, just needed them to be independent of port B's data.

    So I did as you suggested - removed the resistors just a minute ago - and SUCCESS - No more triggering of interrupt D when setting PB6 or PB7.  I can't thank you guys enough.  I spent a LOT of time the last few days trying to figure out what was happening here and likely would not have gotten to the bottom of it without the info you provided.  I likely would've switched to another port and this would've continue to be a mystery to me possibly causing additional hopeless debugging in the future.  Huge thanks!

  • Glad it's all sorted out for you.