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.

UART Receive interrupt on OMAP4460

Hello all -

I am working on a OMAP4460 system based on the Blaze tablet, and I am attempting to utilize one of the UARTs to do some basic data transfer.  We are able to transmit data out of the UART without any issues.

The problem that I am having is that the data received on the UART's RX line does not show up on a Linux file read() until the next time the UART does a transmit.  In other words, I can received som data on this UART, but it won't return from the file read until after I transmit another character.  I'm assuming this has something to do with the configuration not copying the data out of the FIFO, but I'm very much a n00b in this area and am not sure where to start looking.

Another very strange occurrence is that, if we jumper together the RX and TX pins on this UART, all the data is sent and received perfectly and timely.  Something about having an active transmit is allowing data in the receive FIFO to be read.

We are actually reading/writing from the file in an Android application through the Linux kernel, but I posted this here because I believe the issue to be related to the board-level configuration of the UART.

Below is some of the code I think is relevant, but if you need to see something else from the kernel, u-boot, x-loader, I'd be happy to post that as well.

Application code to open TTY:

int fd = open("/dev/ttyO0", O_RDWR | O_SYNC);

I did try to open the file handle with other flags like O_DIRECT, but it was unable to open the file at all in those cases.

Definition in arch/arm/mach-omap2/board-44xx-serial.c:

static struct omap_device_pad tablet_uart1_pads[] __initdata = {
{
    .name = "uart1_cts.uart1_cts",
    .enable = OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0,
},
{
    .name = "uart1_rts.uart1_rts",
    .enable = OMAP_PIN_OUTPUT | OMAP_MUX_MODE0,
},
{
    .name = "uart1_tx.uart1_tx",
    .enable = OMAP_PIN_OUTPUT | OMAP_MUX_MODE0,
},
{
    .name = "uart1_rx.uart1_rx",
    .flags = OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP,
    .enable = OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0,
    .idle = OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0,
},
};

Pinmux definition in arch/arm/mach-omap2/board-xxxx.c:

static struct omap_board_mux board_mux[] __initdata = {

OMAP4_MUX(I2C2_SDA, OMAP_MUX_MODE1 | OMAP_PIN_OUTPUT), /* UART1 TX */
OMAP4_MUX(I2C2_SCL, OMAP_MUX_MODE1 | OMAP_PIN_INPUT), /* UART1 RX */
OMAP4_MUX(MCSPI1_CS2, OMAP_MUX_MODE1 | OMAP_PIN_OUTPUT),/* UART1 CTS */
OMAP4_MUX(MCSPI1_CS3, OMAP_MUX_MODE1 | OMAP_PIN_INPUT), /* UART1 RTS */

}

Please let me know if there is any other information from the device that would be helpful.  For those who know better, I'm sure the answer is a simple flag somewhere, so I apologize for my lack of knowledge in the basic setup :)

Thanks in advance!

  • Here is some more information I found digging that is hopefully helpful.  This is also in the board-44xx-serial.c file:

    static struct omap_uart_port_info tablet_uart_info_uncon __initdata = {
        .use_dma = 0,
        .auto_sus_timeout = DEFAULT_AUTOSUSPEND_DELAY,
        .wer = 0,
    };

    static struct omap_uart_port_info tablet_uart_info __initdata = {
        .use_dma = 0,
        .auto_sus_timeout = DEFAULT_AUTOSUSPEND_DELAY,
        .wer = (OMAP_UART_WER_TX | OMAP_UART_WER_RX | OMAP_UART_WER_CTS),
    };

    void __init board_serial_init(void)
    {
        omap_serial_init_port_pads(0, tablet_uart1_pads, ARRAY_SIZE(tablet_uart1_pads), &tablet_uart_info_uncon);
        omap_serial_init_port_pads(1, tablet_uart2_pads, ARRAY_SIZE(tablet_uart2_pads), &tablet_uart_info);
        omap_serial_init_port_pads(2, tablet_uart3_pads, ARRAY_SIZE(tablet_uart3_pads), &tablet_uart_info);

    }

    Is is perhaps related to the fact that this port has a different info structure?  What do the different status flags represent?

    Thanks!

  • Hi Dave.

    If you are getting receive characters when you transmit, I'd not expect that the issue is with the pad mux setup.

    It has the appearance of an interrupt problem.  That is, that you are for some reason not getting receive interrupts.  And that you are able to receive when you transmit because the transmit causes the interrupt handler to get run and happen to notice that there are also receive characters available.  Without looking at the code, I'm not sure if that's possible in this case.

    I'd add some debugging to serial_omap_irq() to see what's happening.  That will at least tell you if the receive characters are not getting from the controller to the driver or if they are -- and getting buffered further up the stack.

    Regards,

        Steve

  • There is this issue with Idle state transition, it could help,

    http://e2e.ti.com/support/omap/f/849/t/214828.aspx

  • All -

    Thank you for your assistance so far.

    Steve, I will try to do some debugging and see if anything stands out.

    Manuel, I checked omap_hwmod_44xx_data.c and that flag is already set on UART1, which I believe to be the UART that we are trying to access, in the builds we are doing.

    I am surprised because we have not modified the kernel much from the version we pulled directly from git://git.omapzoom.org/kernel/omap.git, certainly not in ways that would affect the UARTs, as far as I can tell.  We are building from commit 4efe9994e0731a113b19bf42003ccb8f672e5ccb.

  • Alright, so I've done some further testing and I'm hoping the results are a bit more enlightening as to where the issue might be.  

    It seems to me that the UART is asleep and is not configured properly to wake up on receipt of bytes in its FIFO.  In addition to the previous test case I mentioned (shorting RX/TX) I have also been able to verify that the UART will happily receive bytes all the way up to the kernel level as a long as a transmit recently occurred (within about 2-3 second).  If I transmit data from the UART, that port will accept incoming data continuously as long as the receive began within that timing window.  After 2-3 seconds of idle time elapses on the port, it no longer receives characters until another transmit takes place.

    So in other words, we can receive characters as long as the transmit or receive line of the UART hasn't been idle for more than a few seconds.

    This leads me to believe that the IRQs and Pads are set up correctly, but the power management or wakeup of the UART has an issue.  Are there any port settings I can check that relate to these issues.  Is this a common problem based on the kernel version we are using (noted in the last message)?

    With the initial board-44xx-serial.c file looking like this:

    static struct omap_uart_port_info tablet_uart_info_uncon __initdata = {
        .use_dma = 0,
        .auto_sus_timeout = DEFAULT_AUTOSUSPEND_DELAY,
        .wer = 0,
    };

    static struct omap_uart_port_info tablet_uart_info __initdata = {
        .use_dma = 0,
        .auto_sus_timeout = DEFAULT_AUTOSUSPEND_DELAY,
        .wer = (OMAP_UART_WER_TX | OMAP_UART_WER_RX | OMAP_UART_WER_CTS),
    };

    void __init board_serial_init(void)
    {
        omap_serial_init_port_pads(0, tablet_uart1_pads, ARRAY_SIZE(tablet_uart1_pads), &tablet_uart_info_uncon);
        omap_serial_init_port_pads(1, tablet_uart2_pads, ARRAY_SIZE(tablet_uart2_pads), &tablet_uart_info);
        omap_serial_init_port_pads(2, tablet_uart3_pads, ARRAY_SIZE(tablet_uart3_pads), &tablet_uart_info);

    }

    I have also tried the following info options with no visible changes:

        omap_serial_init_port_pads(0, tablet_uart1_pads, ARRAY_SIZE(tablet_uart1_pads), &tablet_uart_info);

        omap_serial_init_port_pads(0, tablet_uart1_pads, ARRAY_SIZE(tablet_uart1_pads), NULL);

    The last item was an attempt to have the default port info loaded, which looks like this (according to mach-omap2/serial.c):

    static struct omap_uart_port_info omap_serial_default_info[] = {
        {
            .use_dma = 0,
            .dma_rx_buf_size = DEFAULT_RXDMA_BUFSIZE,
            .dma_rx_poll_rate = DEFAULT_RXDMA_POLLRATE,
            .dma_rx_timeout = DEFAULT_RXDMA_TIMEOUT,
            .auto_sus_timeout = DEFAULT_AUTOSUSPEND_DELAY,
            .wer = (OMAP_UART_WER_RLSI | \
                OMAP_UART_WER_RHRI | OMAP_UART_WER_RX | \
                OMAP_UART_WER_DCDCD | OMAP_UART_WER_RI | \
                OMAP_UART_WER_DSR | OMAP_UART_WER_CTS),
        },
    };

    Thanks again for any help.  We really need to be able to asynchronously receive data in without first transmitting it out.

  • I was able to find one source code reference for UART, it is shared under NDA, you can contact a TI representative to get access to these UART files, use UART_FS like reference file name.

    One point I read is that before the UART moves to Idle it is needed to make sure FIFOs are emptied before Idle state. The UART procedures are described in the TRM, but there is a document DMA_TX_disable_sequence.doc this document should be available with a TI representative, it describes a extra configuration to use when using DMA, in you case you are not using DMA but it describes too how to empty the FIFOs, I tried to identify this document has public or under NDA but I couldn't.

    Sorry for the delay in the answer.