Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

serial_v2 框架中 DMA 发送完成逻辑处理的一个讨论 #8854

Open
WKJay opened this issue Apr 24, 2024 · 0 comments
Open

serial_v2 框架中 DMA 发送完成逻辑处理的一个讨论 #8854

WKJay opened this issue Apr 24, 2024 · 0 comments

Comments

@WKJay
Copy link
Contributor

WKJay commented Apr 24, 2024

rt_hw_serial_isr 中的 RT_SERIAL_EVENT_TX_DMADONE 分支逻辑如下:

        case RT_SERIAL_EVENT_TX_DMADONE:
        {
            struct rt_serial_tx_fifo *tx_fifo;
            tx_fifo = (struct rt_serial_tx_fifo *)serial->serial_tx;
            RT_ASSERT(tx_fifo != RT_NULL);

            tx_fifo->activated = RT_FALSE;

            /* Trigger the transmit completion callback */
            if (serial->parent.tx_complete != RT_NULL)
                serial->parent.tx_complete(&serial->parent, RT_NULL);

            if (serial->parent.open_flag & RT_SERIAL_TX_BLOCKING)
            {
                rt_completion_done(&(tx_fifo->tx_cpt));
                break;
            }

            rt_serial_update_read_index(&tx_fifo->rb, tx_fifo->put_size);
            /* Get the length of the data from the ringbuffer.
             * If there is some data in tx_ringbuffer,
             * then call the transmit interface for transmission again */
            if (rt_ringbuffer_data_len(&tx_fifo->rb))
            {
                tx_fifo->activated = RT_TRUE;

                rt_uint8_t *put_ptr  = RT_NULL;
                /* Get the linear length buffer from rinbuffer */
                tx_fifo->put_size = rt_serial_get_linear_buffer(&(tx_fifo->rb), &put_ptr);
                /* Call the transmit interface for transmission again */
                serial->ops->transmit(serial,
                                    put_ptr,
                                    tx_fifo->put_size,
                                    RT_SERIAL_TX_NON_BLOCKING);
            }

            break;
        }

可以看到尾部加入了再次发送的逻辑,本意是在 ringbuffer 中的数据未发送完成的情况下继续发送。这个逻辑没有任何问题,但是传输完成回调却是进入该分支就会被调用。个人认为虽然这个分支是 DMA 发送完成逻辑,但是实际上驱动在某些情况下(如 ringbuffer 有效数据在 buffer 尾部不连续)会分包发送,这种情况严格意义上并不能称之为发送完成,只能叫做“部分完成”。

虽然在多数情况下这个也不是什么问题,但如果遇到一些需要严格判断数据发送完成的情况下,如 RS485 需要在所有数据发送完成后才能操作使能脚,就会出现问题,即数据发到一半就触发完成回调,并在回调中操作使能脚,此时数据实际才发送了一部分。
仅个人观点,这里的发送完成回调既然是通知应用层的,那就应该是应用层的数据完全发送完成后才被调用,而不是应用层数据传输到驱动层后被驱动分包,然后驱动层的一包发送完成后就调用。

个人在使用时进行了如下修改:

case RT_SERIAL_EVENT_TX_DMADONE:
{
    struct rt_serial_tx_fifo *tx_fifo;
    tx_fifo = (struct rt_serial_tx_fifo *)serial->serial_tx;
    RT_ASSERT(tx_fifo != RT_NULL);
    tx_fifo->activated = RT_FALSE;
    rt_serial_update_read_index(&tx_fifo->rb, tx_fifo->put_size);
    /* Get the length of the data from the ringbuffer.
     * If there is some data in tx_ringbuffer,
     * then call the transmit interface for transmission again */
    if (rt_ringbuffer_data_len(&tx_fifo->rb))
    {
        tx_fifo->activated = RT_TRUE;
        rt_uint8_t *put_ptr  = RT_NULL;
        /* Get the linear length buffer from rinbuffer */
        tx_fifo->put_size = rt_serial_get_linear_buffer(&(tx_fifo->rb), &put_ptr);
        /* Call the transmit interface for transmission again */
        serial->ops->transmit(serial,
                            put_ptr,
                            tx_fifo->put_size,
                            RT_SERIAL_TX_NON_BLOCKING);
    }
    else
    {
        /* Trigger the transmit completion callback */
        if (serial->parent.tx_complete != RT_NULL) 
            serial->parent.tx_complete(&serial->parent, RT_NULL);

        if (serial->parent.open_flag & RT_SERIAL_TX_BLOCKING) 
        {
            rt_completion_done(&(tx_fifo->tx_cpt));
            break;
        }
    }
    break;
}

以上仅为个人的一个见解,作为讨论,如有错误,欢迎指正

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant