klanet 发表于 2010-08-30 17:49

串口问题求助,请兄弟们支援

我的主机芯片是at91rm9200,现在发现了一个问题。
我的主机通过串口采集另外一个模块的数据,发现数据采集出错。时常有数据丢失。
后来修改了协议的代码。
协议开始读数据是通过一个buffer来读取的,就是read一个buffer,buffer大小为1024。有数据就返回。这样是会丢数据的。
后来把buffer改为1,也就是变为一个一个数据的读取,数据的正常了。

请问这是为啥?我总不能规定以后所有的采集协议读取都是一个一个字节读取吧。:em16:

dreamice 发表于 2010-08-31 08:56

回复 1# klanet


    这个估计跟你的中断处理程序有关,你一个一个字节的读取,可能是串行阻塞型的,而开了软件buffer,有可能就是中断处理程序直接非阻塞的往里面塞数据,中断处理的优先级很高,一旦buffer满了就丢弃数据,具体还要仔细结合代码分析,方便的话可以贴一下代码。

yikaikai 发表于 2010-08-31 09:56

读写有没有加锁?

klanet 发表于 2010-08-31 10:45

本帖最后由 klanet 于 2010-08-31 10:56 编辑

回复 2# dreamice


    版主要的是那部分的代码?
驱动的还是协议层的?
协议层的    // 找头字符:
    int i=0;
    sRecStr = 0;
    do
    {
      ReadFile( hComm, (char*)sRecStr, 1, &lRead, NULL );
      i++;
    }while( lRead==1 && sRecStr!=bySOI && i<nMaxDllBufNum-1 );

    // 读后续数据串
    if( lRead && sRecStr==bySOI )
    {
      // 读取到数据段长度字符,以便决定本包总数据量.
      ReadFile( hComm, (char*)sRecStr+1, 12, &lRead, NULL );
      if( lRead==12 )
      {
            int nLen=0;
            sscanf( (char *)sRecStr+9,"%04x", &nLen );
            nLen = nLen & 0x0FFF;         // 去掉校验位
            if( nLen+18 < nMaxDllBufNum-1 ) // 缓冲区溢出判断
            {
                ReadFile( hComm, (char*)sRecStr+13, nLen+5, &lRead, NULL );
            }
            lRead += 12;
      }
      lRead++;
    }

    sRecStr = 0;

    // 跟踪调试的接收信息处理:回应信息记录。上面的是buffer读取,改为一个一个字节读取就不贴出来了,都差不多。

驱动代码在 drivers/serial/atmel_serial.c
下面是中断发的代码static void atmel_tx_chars(struct uart_port *port)
{
        struct circ_buf *xmit = &port->info->xmit;

        if (port->x_char) {
                UART_PUT_CHAR(port, port->x_char);
                port->icount.tx++;
                port->x_char = 0;
                return;
        }
        if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
                atmel_stop_tx(port);
                return;
        }

        while (UART_GET_CSR(port) & ATMEL_US_TXRDY) {
                UART_PUT_CHAR(port, xmit->buf);
                xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
                port->icount.tx++;
                if (uart_circ_empty(xmit))
                        break;
        }

        if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
                uart_write_wakeup(port);

        if (uart_circ_empty(xmit))
                atmel_stop_tx(port);
}
下面是中断收static void atmel_rx_chars(struct uart_port *port)
{
        struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
        struct tty_struct *tty = port->info->tty;
        unsigned int status, ch, flg;

        status = UART_GET_CSR(port);
        while (status & ATMEL_US_RXRDY) {
                ch = UART_GET_CHAR(port);

                port->icount.rx++;

                flg = TTY_NORMAL;

                /*
               * note that the error handling code is
               * out of the main execution path
               */
                if (unlikely(status & (ATMEL_US_PARE | ATMEL_US_FRAME
                                     | ATMEL_US_OVRE | ATMEL_US_RXBRK)
                             || atmel_port->break_active)) {
                        UART_PUT_CR(port, ATMEL_US_RSTSTA);        /* clear error */
                        if (status & ATMEL_US_RXBRK
                          && !atmel_port->break_active) {
                                status &= ~(ATMEL_US_PARE | ATMEL_US_FRAME);        /* ignore side-effect */
                                port->icount.brk++;
                                atmel_port->break_active = 1;
                                UART_PUT_IER(port, ATMEL_US_RXBRK);
                                if (uart_handle_break(port))
                                        goto ignore_char;
                        } else {
                                /*
                               * This is either the end-of-break
                               * condition or we've received at
                               * least one character without RXBRK
                               * being set. In both cases, the next
                               * RXBRK will indicate start-of-break.
                               */
                                UART_PUT_IDR(port, ATMEL_US_RXBRK);
                                status &= ~ATMEL_US_RXBRK;
                                atmel_port->break_active = 0;
                        }
                        if (status & ATMEL_US_PARE)
                                port->icount.parity++;
                        if (status & ATMEL_US_FRAME)
                                port->icount.frame++;
                        if (status & ATMEL_US_OVRE)
                                port->icount.overrun++;

                        status &= port->read_status_mask;

                        if (status & ATMEL_US_RXBRK)
                                flg = TTY_BREAK;
                        else if (status & ATMEL_US_PARE)
                                flg = TTY_PARITY;
                        else if (status & ATMEL_US_FRAME)
                                flg = TTY_FRAME;
                }

                if (uart_handle_sysrq_char(port, ch))
                        goto ignore_char;

                uart_insert_char(port, status, ATMEL_US_OVRE, ch, flg);

        ignore_char:
                status = UART_GET_CSR(port);
        }

        tty_flip_buffer_push(tty);
}

klanet 发表于 2010-08-31 10:49

回复 3# yikaikai


    没有

lelee007 发表于 2010-08-31 10:51

buffer的管理肯定有问题,把代码贴上来呗

ricks_wu 发表于 2010-08-31 11:02

为一个陌生人无偿看这么长长的代码
这是一种怎样的神经病精神
页: [1]
查看完整版本: 串口问题求助,请兄弟们支援