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.

Write interrupt based uart driver (kernel module)

Hello everybody,

I need to write my own uart driver, which use interrupts, to communicate with microcontroller. I have custom board based on c6a816x and need to use uart2 (ttyO2). But i can't read uart registers, even after request_mem_region was successful. I tried to disable omap-serial driver for this uart, but it seems unsuccessfully. Each attempt to read registers cause a kernel error.

 I use EZSDK 5_04_00_11 and kernel from it. 

I wrote a user space program which works fine, but now i need to write kernel module.

I will be grateful for any help. 

  • Hello,

    Could you report the CM_ALWON_UART_2_CLKCTRL register (address 0x48181558) and CM_ALWON_L3_SLOW_CLKCTRL register (address 0x48181400) values?

    Also, which UART2 register, at which address, is causing the error? 

    Best Regards,

    Pavel

  • Thank you for quick response. 

    I'm trying to read base uart2 register at 0x48024000.

    How i can report values of this registers? Do i need to try to read this addresses in my driver?

    UPD: I read this registers from my driver: both are equal 2.

  • Hi,

    The UART2 base register (at address 0x48024000) can not be read successfully from my side also. But all other UART2 registers (from 0x48024004 to the end) can be read with no errors. Is that valid for you also?

    Best Regards,

    Pavel

  • Hi,

    Yes, i have read few registers from 0x48024004 with no errors.

  • Hi,

    If you need to configure the UART2 base register (at address 0x48024000) RHR/THR, we have the following workaround described in the Errata doc:

    Advisory 2.0.19 Kernel Crashes in Software While Accessing UART RHR Register
    Revisions Affected: 2.0, 1.1, 1.0
    Details: In the software while accessing the UART receive holding register (RHR) register, the kernel crashes. If the Rx FIFO is empty before a UART RHR read and the Tx FIFO is full before a UART THR write, an error response results.
    Workaround: The software should ensure that the Rx FIFO is not empty before reading RHR and the Tx FIFO not full before writing to THR.
    The RHR read on receive FIFO empty can be avoided as follows:
    1. Read the UART Line Statue Register (LSR).
    2. Check to see if the Receiver Data Ready (DR) bit (bit 0) is set to 1.
    3. If yes, proceed to read RHR, otherwise there is no data to be read and the RHR read should be skipped.
    The THR write on transmit FIFO full can be avoided as follows:
    1. Read the UART Line Statue Register (LSR).
    2. Check to see if the Transmit Hold Register Empty (THRE) bit (bit 5) is set to 1.
    3. If yes, proceed to write to THR, otherwise loop until THRE is set before writing to THR.
    4. It may be desirable to implement a few milliseconds timeout for the loop to poll to avoid long busy waits for THR.

  • Thank you, now i understand how to operate with this register and will continue my research of uart further.

  • Hello again,

    I have question about RX FIFO. I configured it's size to 60, but it seems this is not enough. I have overrun error. And, as a result, wrong bytes in my RX buffer.

    I have only one interrupt - RHR interrupt. What settings i should change to avoid such behavior and get all data?

    I will be grateful for any help.  

     

  • Hello,

    Please have a look in the DM816x TRM:

    23.2.3.1 Hardware Flow Control

    23.2.3.4 UART Configuration Example, 23.2.3.4.2 UART FIFO Configuration

    23.2.6 FIFO Management

    Regards,

    Pavel

  • Thank you for quick response, your answer was very useful for me.

    I read this sections and configured RX FIFO to interrupt after each byte to avoid overrun, but it doesn't help.

    I use a cycle in my interrupt handler to save each byte while LSR[0] is equal 1, is it right or i need to quit from interrupt handler after receiving some bytes?

     

     

  • Hello,

    Can you share your code?

    Meanwhile here is a link to some test code for DM816x: http://support.spectrumdigital.com/boards/evm816x/revg/ See DM816x/C6A816x/AM389x EVM Software Resources, Test Code

    evm816x/tests/uart_loopback.c

    evm816x/lib/evm816xbsl/evm816x_uart.c

    Regards,

    Pavel

  • Hello, here is a part of my code:

    config uart:

    // Disable interrupts
    Uart2_reg_write(0x00, UART_IER);

    // Enables the granularity of 1 for trigger RX level SCR[7] = 1
    Uart2_reg_write(0x80, UART_OMAP_SCR);
    // Configutation mode B
    Uart2_reg_write(UART_LCR_CONF_MODE_B, UART_LCR);
    // EFR[4] = 1
    Uart2_reg_write(UART_EFR_ECB, UART_EFR);
    // Configutation mode A
    Uart2_reg_write(UART_LCR_CONF_MODE_A, UART_LCR);
    // MCR[6] = 1
    Uart2_reg_write(UART_MCR_TCRTLR, UART_MCR);
    // baudrate 115200
    Uart2_reg_write(0x1A, UART_DLL);
    Uart2_reg_write(0x00, UART_DLM);
     // Configutation mode B
    Uart2_reg_write(UART_LCR_CONF_MODE_B, UART_LCR);
    // clear TLR
    Uart2_reg_write(0x00 ,UART_TI752_TLR);
    // EFR = 0
    Uart2_reg_write(0x00, UART_EFR);
    // 8 Bits, No Parity, 1 Stop Bit
    Uart2_reg_write(UART_LCR_WLEN8, UART_LCR);
    // Enable FIFO, clear rx & tx FIFO, rx FIFO size - 1
    Uart2_reg_write(0x47, UART_FCR);
    // Clear MCR
    Uart2_reg_write(0x00, UART_MCR);

    // Enable recept interrupt
    Uart2_reg_write(0x01, UART_IER); 

     

    irq handler:

    unsigned char counter;
    unsigned char lsr;

    counter = 0;
    lsr = Uart2_reg_read(UART_LSR);
    while (lsr & UART_LSR_DR)
     {

       printk("0x%02X, 0x%02X\n", Uart2_reg_read(UART_RX), lsr);
       counter++;
       if (counter == 4) // read 4 bytes and quit
           break;
       lsr = Uart2_reg_read(UART_LSR);
    }
    printk("counter is %d\n", counter);

     return IRQ_HANDLED;  

     

    With this code i got overrun error in second interrupt after reading 2 bytes. So i think my config of uart is wrong.

  • Hi Evgeniy,

    The first thing I noticed in your code, is that you are using printk function invokes inside your interrupt handler. The interrupt handler should be as fast/short as possible, and printk is increasing the service time significantly, which is most probably the reason for the overrun condition. Can you try without printk function invokes ?

    Best Regards,

    Pavel

     

  • Hi Pavel,

    Thank you very much. I commented all printk and added condition to use it only in case of overrun error, and now it works without error.

    I didn't think that printk can slow interrupt so much.

    Thanks again.