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/TM4C1294NCPDT: UART 9 bit address mode not generating interrupt

Part Number: TM4C1294NCPDT
Other Parts Discussed in Thread: EK-TM4C123GXL

Tool/software: Code Composer Studio

I am developing firmware for a board that contains 1 TM4C129 and 6 TM4C123 MCUs.  They are connected through UART1 on all devices and we would like to use 9 bit addressing mode.  I am trying to simulate our setup using a DK-TM4c129X and a EK-TM4C123GXL.

Using the uart_echo example for both boards, I added UART1 and connected U1RX and U1TX between the two boards.  I echo data from the 129 UART0 to the 123 UART0 and this works in non 9 bit addressing but when I enable 9 bit addressing the 123 does not generate an interrupt.

129  setup:

    //
    // Configure the UART1 for 115,200, 8-N-1 operation.
    //
    ROM_UARTConfigSetExpClk(UART1_BASE, ui32SysClock, 115200,
                            (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE |
                             UART_CONFIG_PAR_NONE));

    ROM_UART9BitAddrSet(UART1_BASE, 0x14, 0xFF);
    ROM_UART9BitEnable(UART1_BASE);
    ROM_UART9BitAddrSend(UART1_BASE, 0x33);

129 interrupt

    while(ROM_UARTCharsAvail(UART0_BASE))
    {
        //
        // Read the next character from the UART and write it back to both UART.
        //
        data = UARTCharGetNonBlocking(UART0_BASE);
        ROM_UARTCharPutNonBlocking(UART0_BASE, data);
        if (data >= 0x30 && data <= 0x39) {
            ROM_UART9BitAddrSend(UART1_BASE, (uint8_t)data);
        } else
            ROM_UARTCharPutNonBlocking(UART1_BASE, data);
    }

123 setup

    //
    // Configure the UART for 115,200, 8-N-1 operation.
    //
    ROM_UARTConfigSetExpClk(UART1_BASE, ROM_SysCtlClockGet(), 115200,
                            (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE |
                             UART_CONFIG_PAR_NONE));

    ROM_UART9BitAddrSet(UART1_BASE, 0x33, 0xFF);
    ROM_UART9BitEnable(UART1_BASE);

123 interrupt

    while(ROM_UARTCharsAvail(UART1_BASE))
    {
        //
        // Read the next character from the UART and write it back to the UART.
        //
        ROM_UARTCharPutNonBlocking(UART0_BASE,
                                   ROM_UARTCharGetNonBlocking(UART1_BASE));

        //
        // Blink the LED to show a character transfer is occuring.
        //
        GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, GPIO_PIN_2);

        //
        // Delay for 1 millisecond.  Each SysCtlDelay is about 3 clocks.
        //
        SysCtlDelay(SysCtlClockGet() / (1000 * 3));

        //
        // Turn off the LED
        //
        GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, 0);

    }

  • Hello Robert,

    I was in the process of replicating your setup when I reached a point where I am not 100% sure how you have things set up.

    You mention echoing data between UART0's. I did the same (well, technically I used UART3 on the DK, but that's a matter of semantics regarding the core issue) and then went to add in the 9-bit feature after confirming operation.

    However as I did this, I am unsure how best to mimic your setup.

    1) Do you still want data echoed on UART0 while using 9-bit mode?

    2) You mention not getting an interrupt and your 123 interrupt uses UART1_BASE when checking ROM_UARTCharsAvail. Does this mean you shifted the interrupt vector to UART1? Because if you are interrupting for UART0 data but then looking for UART1 data, you may have gotten stuck in that loop.

    3) Just as a sanity check but, did you enable the GPIO's and SysCtlPeripheralEnable for UART1 as well?

  • Ralph,

    I connected PB0 (RX) on the 129 to PB1 (TX) on the 123, PB1 (TX) on the 129 to PB0 (RX) on the 123.

    I modified the 129 UARTIntHandler to call ROM_UARTBitAddrSend UART1_BASE if the input character is between '0' and '9' otherwise it echos to UART1.

    I added a separate UARTIntHandler for UART1 on the 123 called UARTIntHandler2 that echos the character from UART1 to UART0.

    I have enabled GPIOs and UART1.

    What I expect to see is that if I enter a character on the 129 terminal I should see it echo on both the 129 and 123 terminals if the AddrSend matches the AddrSet.

    If I disable the 9bit mode, I see the character on both terminals so I know the interrupt, GPIO and UART1 are enabled.

    If I enable 9bit mode I only see the character on the 129 terminal.

    Robert

  • Hello Robert,

    Okay thank you for that added explanation, the details are much clearer to me now, I didn't have my projects configured quite the same way, but that will be easy to implement from where I am now.

  • Hello Robert,

    It looks like 9-bit UART on these devices is quite complex. I'm still trying to figure out exactly how to get it working on my end.

    Couple things I've gleamed:

    1) You'll need to watch the UART line manually with a logic analyzer as UART terminals on PCs do not support 9-bit mode. As such, I've adjusted to try and echo back to UART1 TX instead of UART0.

    2) There may be a need for UARTFIFODisable to TX, but I am still investigating this element.

  • Hi Ralph,

    UART0 on both development boards are connect to a terminal program on the PC via the debugger USB.

    UART1 on both development boards are connected to each other with jumpers and are in 9bit mode.

    I did notice that if I called UART9BitEnable before UART9BitAddrSet, the 9BITEN bit in the UART_9BITADDR register would be 0.  If I called UART9BitEnable after UART9BitAddrSet it would be 1.  UART9BitAddrSet seems to reset the 9BITEN bit.

    Robert

  • Hello Robert,

    Interesting observation, I had the order as AddrSet and then Enable so never had an issue with that.

    I managed to get interrupts firing for 9-bit receive. The UARTIntEnable also needs the flag for 9-bit interrupts: UART_INT_9BIT

    However, I am not able to receive data properly still. I get into the interrupt, but the data is nowhere to be found. Still trying to figure out what is going on with that.

  • Hello Robert,

    Right now from what I am seeing on my LSA is that the DK-TM4C129X is sending 9-bit data back as well for some reason and that is why the receive is not working. So my focus on the issue right now is trying to figure out what is triggering that 9th bit to be transmit.

  • Ralph,

    Thanks for the update.

    I don't have a lot of experience with 9 bit mode but I was under the impression that once you enable 9 bit mode then a bit is added to all data.  The ninth bit identifies the character as either address or data.

    I too get the interrupt when I send the address byte but not when I send non address data.

    Robert

  • Hello Robert,

    I'm not experienced with it either but reading around, it sounds like that may well be the case and that last bit is a '1' for the address and a '0' for the data.

    The UART LSA captures were showing that the data byte always appeared to be followed by a last bit of '1' though. Which means it was basically looking like it sent the address twice. I think this is because the pin is driving high after sending 8 bits of data, and is being misinterpreted when in 9-bit mode. I picked up on this because the analyzer I am using was making that interpretation if I sent a normal 8 bit data packet but kept it sniffing for 9-bit mode. It reported the 8-bit data as an address in that case. Which got me thinking perhaps the slave device is making the same logic error. 

    To try and work around that, I forced the UART into Parity Zero mode and then sent data. This would force the last bit to be low. And it was received properly in that case.

    The parity setting specifically is UART_CONFIG_PAR_ZERO.

    This makes me think that 9-bit UART may not be implemented properly (probably on TX side as the parity setting is not required from the slave side to receive). However with the parity forcing idea, in theory using such a method may let you get around the issue anyways.

    We'll continue to investigate if this is an errata item or if there is something I've missed with the configuration.

  • Robert Applebee said:
    I too get the interrupt when I send the address byte but not when I send non address data.

    May an 'alien' invade your joint - interesting & logically progressing thread?

    Sometimes 'experience' - especially broad experience - proves immensely helpful.    In years past - an earlier small Tech Firm of mine - employed the '8051 Family of MCUs' - sometimes operating in (that MCU's) 9 Bit UART Mode.

    And guess what - the behavior (noted by you both) and memorialized (w/in the quote, above) was, 'Exactly exhibited by our past '8051 MCUs!'

    Why is that?     Our past (now dog-eared) notes reveal that the '9 bit Interrupt' was intended to enable (ALL UARTS on the bus) to determine if the incoming message was, 'Aimed at them!'    If not - they returned to their (other) operations.    Just as you report - when (only) subsequent data was received - No such 'Address Alerting Interrupt' was generated...

    Thus - what's been reported - may in fact - prove 'normal!'    (and customary - at least from a historical perspective...)

  • I think there is a problem in the TivaWare function UART9BitAddrSend(). Try adding this version of that function to your project to override the library version.

    //*****************************************************************************
    //
    //! Sends an address character from the specified port when operating in 9-bit
    //! mode.
    //!
    //! \param ui32Base is the base address of the UART port.
    //! \param ui8Addr is the address to be transmitted.
    //!
    //! This function waits until all data has been sent from the specified port
    //! and then sends the given address as an address byte.  It then waits until
    //! the address byte has been transmitted before returning.
    //!
    //! The normal data functions (UARTCharPut(), UARTCharPutNonBlocking(),
    //! UARTCharGet(), and UARTCharGetNonBlocking()) are used to send and receive
    //! data characters in 9-bit mode.
    //!
    //! \note The availability of 9-bit mode varies with the Tiva part in use.
    //! Please consult the datasheet for the part you are using to determine
    //! whether this support is available.
    //!
    //! \return None.
    //
    //*****************************************************************************
    void
    UART9BitAddrSend(uint32_t ui32Base, uint8_t ui8Addr)
    {
        uint32_t ui32LCRH;
    
        //
        // Check the arguments.
        //
        ASSERT(_UARTBaseValid(ui32Base));
    
        //
        // Wait until the FIFO is empty and the UART is not busy.
        //
        while((HWREG(ui32Base + UART_O_FR) & (UART_FR_TXFE | UART_FR_BUSY)) !=
              UART_FR_TXFE)
        {
        }
    
        //
        // Force the address/data bit to 1 to indicate this is an address byte.
        //
        ui32LCRH = HWREG(ui32Base + UART_O_LCRH);
        HWREG(ui32Base + UART_O_LCRH) = ((ui32LCRH & ~UART_LCRH_EPS) |
                                         UART_LCRH_SPS | UART_LCRH_PEN);
    
        //
        // Send the address.
        //
        HWREG(ui32Base + UART_O_DR) = ui8Addr;
    
        //
        // Wait until the address has been sent.
        //
        while((HWREG(ui32Base + UART_O_FR) & (UART_FR_TXFE | UART_FR_BUSY)) !=
              UART_FR_TXFE)
        {
        }
    
        //
        // Force address bit low for data bytes to follow
        //
        HWREG(ui32Base + UART_O_LCRH) = (ui32LCRH | UART_LCRH_EPS |
                                         UART_LCRH_SPS | UART_LCRH_PEN);
    
    }
    

  • I may have made this too difficult. A simpler solution seems to be to configure the UART to UART_CONFIG_PAR_ZERO instead of UART_CONFIG_PAR_NONE. The function UART9BitAddrSend() changes the configuration to UART_CONFIG_PAR_ONE to send the address byte then changes it back to its previous configuration after the address byte has finished transmitting. An example would look like this:

    int
    main(void)
    {
        uint32_t ui32SysClock;
    
        ui32SysClock = SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ | SYSCTL_OSC_MAIN | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_480), 120000000);
    
    
        SysCtlPeripheralEnable(SYSCTL_PERIPH_UART3);
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOJ);
    
        // Set GPIO PJ0 and PJ1 as UART pins.
        GPIOPinConfigure(GPIO_PJ0_U3RX);
        GPIOPinConfigure(GPIO_PJ1_U3TX);
        GPIOPinTypeUART(GPIO_PORTJ_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    
        //
        // Configure the UART1 for 115,200 baud 9bit address mode.
        //
        UARTConfigSetExpClk(UART3_BASE, ui32SysClock, 115200,
                                (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE |
                                        UART_CONFIG_PAR_ZERO));
        UARTEnable(UART3_BASE);
    
        UART9BitAddrSet(UART3_BASE, 0x14, 0xFF);
        UART9BitEnable(UART3_BASE);
        UART9BitAddrSend(UART3_BASE, 0x33);
        UARTCharPut(UART3_BASE, 0x33);
        UARTCharPut(UART3_BASE, 0x33);
    }
    
    

  • Bob/Ralph,

    Changing the parity from UART_CONFIG_PAR_NONE to UART_CONFIG_PAR_ZERO now generates interrupts for the Rx data as well as when the 9 bit address send matches the set address on the receiving MCU.

    Thanks

  • Hello Robert,

    Glad to help out. After further reading of the datasheet, this is also the intended solution based on specified device operation as well.

    Sometimes even we don't listen to our own manuals fully either as it spelled out the solution pretty clearly: The Transmit FIFO does not hold the address/data bit, hence software should take care of enabling the address bit appropriately. Naturally that would also apply to the data bit as well... :)

  • Robert Applebee said:
    UART_CONFIG_PAR_ZERO now generates interrupts for the Rx data as well as when the 9 bit address send matches the set address on the receiving MCU.

    Pardon - but if that's the (same) interrupt - does that not intrude upon, 'Every unaddressed UART/MCU' - which have 'NO INTEREST whatsoever' in being so regularly, 'Interrupted - by 'data messages' intended ONLY for another?'     That 'fine point'  (interrupt vs interrupts) - at least to myself/others - has not been made clear...

  • I only had two MCU development boards connected together but I think my test results indicate that receiving MCU does not generate RX interrupt unless addressed.

    MCU1 is the TX UART.

    MCU2 is the RX UART.

    Test Setup:

    1. MCU1 and MCU2 9Bit Enabled

    2. MCU2 Address set to 0x33

    3. MCU1 Sends address 0x33, MCU2 generates 9Bit Address match interrupt.

    4. MCU1 Sends data byte, MCU2 generates RX interrupt.

    5. MCU1 Sends address 0x32.  No interrupt on MCU2.

    6. MCU1 Sends data byte.  No interrupt on MCU2.

  • Thank you - your detailed & direct 'issue addressing' response is much appreciated.

    Pardon but there remains one small, 'element of confusion'   (And indeed - Firm/I are 'Detail Phreaks!')

    Kindly consider:   (All centered upon 'MCU2' - your RX UART)

    • MCU1 Sends address 0x33,   MCU2 generates 9Bit Address match interrupt.

    And (that) behavior is 'Just as Expected!'

    • MCU1 Sends data byte, MCU2 generates RX interrupt.

    Our 'sense' here is that - 'RX Interrupt' is a different interrupt - and is NOT the '9Bit Address-Match' interrupt.

    May we ask you to confirm this understanding - and/or correct where we've 'gone astray?'    Thank you.

    From our past history w/the '8051' (which has an enormous installed base) an interrupt was only noted when a, '9Bit Adr-Match' was detected - and not when follow-on 'data' arrived.    Vendor's MCU (or ARM's IP) 'appears' to have: 

    • 'extended' (either) the single interrupt's generation
    • or has created a new (receiving) interrupt...
  • The RX and 9Bit address match are two of fourteen possible UART events that share the same interrupt level and thus the same ISR.  In the uart_echo example only the UART_INT_RX and UART_INT_RT are enabled to generate an interrupt (receive and receive timeout).  For the modified 9Bit mode UART_INT_9BIT was also enabled (address match).  The ISR should have code to service each of the enabled events but it is the same physical interrupt.

    Hope this sheds some light. 

    Robert

  • Thank you - once again your response is superb and very much appreciated.

    Now my Tech Firm employs ARM Cortex MCUs (and more advanced, ARM others) from four different vendors - and the interrupt scheme described - appears (somewhat) unique - for your MCU.    This is (not) the first time that the 'interrupt implementation' (here) has been, 'Called into question.'   (i.e. see (many) posts from my highly skilled 'Canadian friend' (and acknowledged Tech Expert/Prof.) 'Robert!')

    Again - we thank you - wish you the best - and 'Applaud' your kindness & efficiency in responding...