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

建议添加异步发送数据功能 #16

Open
zcj20080882 opened this issue Dec 20, 2019 · 4 comments
Open

建议添加异步发送数据功能 #16

zcj20080882 opened this issue Dec 20, 2019 · 4 comments

Comments

@zcj20080882
Copy link

文档中说明建议不要打开RT_DEVICE_FLAG_DMA_TX,现实情况是一定不能打开该标志。原因是RTT串口发送时,是直接将数据地址传送给DMA(在打开DMA时并且开启RT_DEVICE_FLAG_DMA_TX),这样在DMA发送数据时,一定不能修改传给serial层的数据,如果是动态分配的内存更不能释放该内存,否则会导致发送数据出错或者崩溃。
但是,某些情况下,需要开启DMA以节省CPU资源,这时需要ppp_device能够保证数据不出错而且还能异步(DMA)发送,这就需要简单实现一下异步发送的功能。我简单写了一个串口异步发送数据的示例,你看是否可行或者是否有必要:

#define MIN(a,b)            (((a) > (b)) ? (b) : (a))
#define SEND_TIMEOUT 1000
uint8_t ppp_tx_buf[1500] = {0};
/*发送完成信号*/
rt_sem_t tx_sem;

rt_inline rt_err_t __send_complete_callback(rt_device_t dev, void *buffer)
{
    rt_sem_release(tx_sem);
    return RT_EOK;
}

int ppp_serial_write(rt_device_t dev, const uint8_t *data, int data_len)
{
    int ret = RT_EOK;

    if (!dev)
    {
        return -RT_EINVAL;
    }
    if (!data || data_len == 0)
    {
        log_w("Invalid data!");
        return 0;
    }
    
    ret = rt_sem_take(tx_sem, SEND_TIMEOUT);
    if (RT_EOK != ret)
    {
        log_e("Write %s failed,err: %d", uart->name, ret);
        return -RT_EBUSY;
    }
    ret = MIN(data_len,sizeof(ppp_tx_buf));
    memcpy(ppp_tx_buf, data, ret);
    
    ret = rt_device_write(dev, 0,tx_buf, ret);
    if (ret <= 0)
    {
        log_e("Write %s failed,err: %d", uart->name, ret);
    }
    else if (ret < data_len)
    {
       //待优化,连续发送大量数据可能导致栈溢出
        ret = ppp_serial_write(fd, data + ret, data_len - ret);
    }
    return ret;
}
@armink
Copy link
Member

armink commented Dec 20, 2019

@zcj20080882
Copy link
Author

可否跟 rbb 有些结合呢

https://www.rt-thread.org/document/api/group__ring__block__buffer.html#details
这不错,适合应用层做缓存。这个场景使用是不是有点复杂?这里其实不需要太复杂,只需要DMA发送数据,静态分配一个1500字节的内存就好了,保证DMA发送数据时数据不被破坏就好。
rbb确实很好用,我在其他项目里用了,而且rbb的使用场景也很广泛,只是这个场景貌似不需要。

@armink
Copy link
Member

armink commented Dec 23, 2019

主要感觉这个功能放在串口设备层去实现会更加通用一些,当时设计 RBB 最早也是考虑到了 DMA 发送的需求。

@zcj20080882
Copy link
Author

主要感觉这个功能放在串口设备层去实现会更加通用一些,当时设计 RBB 最早也是考虑到了 DMA 发送的需求。

是呢,最初接触到RTT也发现这个问题,串口驱动层对DMA发送的处理逻辑对应用层不是特别友好,尤其是新手,可能会直接使用rt_device_write写数据,函数返回后就直接复用了,导致数据发送出错。在实际项目中,串口这块基本上都需要再封一层使用(这里使用rbb就非常方便)。

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

2 participants