UART DMA problem for IMX6Q

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

UART DMA problem for IMX6Q

3,545 Views
biyaochen
Contributor I

Recently I'm using IMX6Q develop package (rel4.1.15) and rewrite the UART code to a char device driver.

There is a random error while accessing UART data (1 byte error/20 millions*(8~16)bytes):

My test code is a simple write-read cycle between IMX6Q UART1  and another board.The
random error is certainly found in last byte for a burst read.0x0 is received while expecting another byte 0xC0

I debuged and found the byte in DMA receive buffer was error. I have checked the register of UART and it's the same as that of orginal UART code(the result is got from xxperiment not code).

The hardware and test code should be OK, because the error won't reproduce if using the original UART code.

Do you have any idea where is the problem?

Labels (1)
Tags (1)
0 Kudos
Reply
11 Replies

2,851 Views
dtran11
Contributor I

I am also having issues related to uart and dma. Running on kernel 4.1 or 4.9 have the same results. 

I have uart communication between an stm32 and imx6dl. From the stm32 I send a 512 byte packet every 250 ms (4Hz). Turning on debug for imx uart driver, most of the time I will see 512 bytes received. However, there are times I would get under 512 bytes like 500 bytes. In those cases I would have expected to see 500 bytes received and then 12 bytes right after. But rather I don't see that so it loses those end bytes. 

Has anyone seen this with using uart and dma? I'm running at 115200 baud but it happens for any buad rate. Seems to be worse with lower baud rates ironically.

Also using interrupt based for uart rx works great for bauds 57600 and under.

Thanks

0 Kudos
Reply

2,851 Views
fabio_estevam
NXP Employee
NXP Employee

Hi Biyao,

Why do you need to rewrite the imx serial driver?

If I understand correctly you don't see errors with the original seria driver. Is that correct?

0 Kudos
Reply

2,851 Views
biyaochen
Contributor I

Can you reproduce the problem in your board?

0 Kudos
Reply

2,851 Views
fabio_estevam
NXP Employee
NXP Employee

I haven't tried reproducing the error because I don't have the driver your are using.

My understanding is that the error does not happen with the original imx serial driver.

It is also not clear why you can't use the original imx serial driver.

Thanks

0 Kudos
Reply

2,851 Views
biyaochen
Contributor I

Now ,It's midnight here and I am at home and have some trouble in accessing NXP community.

The testing code is listed in my reply in NXP community and is breifed:

dual ways write/read in 2 boards and data is headcounttail and will be checked in receiver.

Thanks

0 Kudos
Reply

2,851 Views
fabio_estevam
NXP Employee
NXP Employee

Does the error also happen with a 4.9 kernel?

Also, does the issue also happen if DMA is not used for the serial ports?

0 Kudos
Reply

2,851 Views
biyaochen
Contributor I

I don't have 4.9 kernal.

Two more testing are done in my board : poll mode read/write and DMA write and poll mode read.

Both are ok and no error found.

As I mentioned, I have read the DMA buffer in driver when error occured and found the data is error from DMA receive buffer.

0 Kudos
Reply

2,851 Views
biyaochen
Contributor I

Sorry, Maybe I didn't say it clear enough.

The error can be reproduced in original imx driver in setting of 4000000/8/n/2.(I didn't run testing in other setting)

Testing code is ran at 2 boards with tx/rx connected.

0 Kudos
Reply

2,851 Views
biyaochen
Contributor I

I rewrote the code for efficiency because in my case I want get the response ASAP after writing. So if the UART driver is a char device driver that I can control, I can use poll mode in some senario.

I'm not sure if the original seria driver is ok for all application cases because my application code is a very simple case : read after write in 1 thread.(1000000/8/N/2)

I designed a test case for 2 IMX6Q boards : dual ways 4000000/8/N/2

hardware:2 IMX6Q boards with rx/tx of UART1 connected

software:2 threads for read and write data, the data is made up of head/counts/tail. Counts will be checked in read thread and there is a sync mechanism that write is haused if 10 steps ahead of read operation.

The same error can be reproduced also about 1 error / 20millions test rounds.

Test code is listed below:

using std::cout;
using std::string;
#define START (static_cast<char>(0x7f))

unsigned long long g_revcount = 0;
int g_sendcount = 10;

void writeUart()
{
    char wrbuf[1000];
    std::ofstream log("wrlog", std::ofstream::app);

    std::uniform_int_distribution<unsigned> u(2, 10);
    std::default_random_engine e(std::time(0));

    unsigned long long count = 0;
    string data;
    while (g_delay)
    {
        std::this_thread::sleep_for(std::chrono::microseconds(100));
    }
    
    while (g_writeEnable)
    {
        if (g_sendcount > 0){
            data = std::to_string(count);
            int sample = u(e);
            
            wrbuf[0] = START;
            wrbuf[1] = data.size() + sample;
            
            for (int i = 2; i < sample+2; ++i)
            {
                wrbuf[i] = '0';
            }            
            
            for (int i = 0, j = 2 + sample; i < data.size(); ++i,++j)
            {
                wrbuf[j] = data.c_str()[i];
            }
            
            int size = write(g_fd, wrbuf, wrbuf[1] + 2);

            
            if (count % 10000 == 0)
            {
                log << "writetest:  count:" << data << " sendlength: " << size << std::endl;
                log << "receive test: count:" << g_revcount << std::endl;
            }
            ++count;
            --g_sendcount;
        }
        else{
            std::this_thread::sleep_for(std::chrono::microseconds(100));
        }
    }    
}

void readUart()
{    
    int numflag = 1;
    const int maxsize = 500;
    char rdbuf[maxsize];
    char handbuf[200];

    std::ofstream log("log", std::ofstream::app);
    int nget=0,nput = 0;

    int ndata;

    while (true)
    {
        try{
            if (nput >= nget){
                ndata = nput - nget;
            }
            else{
                ndata = nput + maxsize - nget;
            }

            if (ndata > 0){
                if (rdbuf[nget] != START){
                    log << "receive test: read head eror! count:" << g_revcount << std::endl;
                    cout << "receive test: read head eror! count:" << g_revcount << std::endl;
                    cout << "receive test: nget:" << nget << " nput:" << nput << std::endl;
                    g_writeEnable = false;
                    return;
                }
                int cmdlengpos = (nget + 1) % maxsize;
                int cmdsize = rdbuf[cmdlengpos] + 2;
                
                if (ndata > cmdsize){
                    
                    for (int i = 0; i < cmdsize; ++i) {
                        handbuf[i] = rdbuf[nget];
                        ++nget;
                        if (nget == maxsize) {
                            nget = 0;
                        }
                    }
                    
                    string num(handbuf + 2, handbuf[1]);
                    if(numflag)
                    {
                        g_revcount = std::stoull(num);
                        cout << "find first message : " << g_revcount <<  std::endl;
                        numflag = 0;
                    }
                    else
                    {
                        if (g_revcount != std::stoull(num)) {
                            log << "receive test: count:" << g_revcount << " receive count:" << std::stoull(num) << " receive string:" << num << " count eror!" << std::endl;
                            //cout << "receive test: count:" << g_revcount << " receive count:" << std::stoull(num) << " receive string:" << num << " count eror!" << std::endl;
                            log << "receive test: nget:" << nget << " nput:" << nput << std::endl;
                            g_writeEnable = false;
                            cout << std::showbase;
                            
                            for (int i = 0; i < maxsize; ++i)
                            {
                                //printf("%x ", rdbuf[i]);
                                cout << std::hex << rdbuf[i];
                            }
                            cout << std::noshowbase;
                            //printf("\n");
                            return;
                        }
                    }
                    
                    ++g_revcount;
                    g_sendcount = 5;                    
                    g_delay = false;

                }
                else{
                    throw int(ndata);
                }
            }
            else{
                throw int(ndata);
            }

        }catch(int&) {
            int nread = read(g_fd, rdbuf + nput, maxsize - nput);
            nput += nread;
            if (nput == maxsize){
                nput = 0;
            }
            //    cout << "receive test: receive size :" << nread << std::endl;
        }
    }
}

int main(int argc, char *argv[])
{
    char devname[1024];
    
    sprintf(devname, "/dev/ttymxc%d", atoi(argv[1]));    

    mlockall(MCL_FUTURE | MCL_CURRENT);
    
    if ((g_fd = open_port(devname)) < 0) {
        perror("open_port error");
        return -1;
    }
    
    if ( set_opt(g_fd, atoi(argv[2]), 8, 'N', 1) < 0) {
        perror("set_opt error");
        return -1;
    }

    auto rd = std::async(std::launch::async, readUart);
    auto wt = std::async(std::launch::async, writeUart);
    
    rd.get();
    wt.get();
      
    close(g_fd);
        
    return 0;
}

0 Kudos
Reply

2,851 Views
igorpadykov
NXP Employee
NXP Employee

Hi biyao 

what bsp used in the case, one can try with nxp official releases described on

https://www.nxp.com/support/developer-resources/run-time-software/i.mx-developer-resources/i.mx-6ser...

linux-imx - i.MX Linux kernel 

Best regards
igor
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos
Reply

2,851 Views
biyaochen
Contributor I

As I mentioned, I rewrote code from rel_imx_4.1.15_2.0.0_ga\drivers\tty\serial\imx.c

0 Kudos
Reply