-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Open
Description
在 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;
}以上仅为个人的一个见解,作为讨论,如有错误,欢迎指正
yangpengya
Metadata
Metadata
Assignees
Labels
No labels