RT-Thread USB虚拟串口收发调试

学习过程中参考博文:
记录——基于 RT-Thread 实现 USB 虚拟串口

但是遇到了两个问题:
1.串口有设备,但是不能发送;
2.串口能发送但不能接收;

第一个问题,是因为rtt的usb虚拟串口默认启用了RTS和DTR(终端准备好接收):

static rt_err_t _interface_handler(ufunction_t func, ureq_t setup)
{
    struct vcom *data;

    RT_ASSERT(func != RT_NULL);
    RT_ASSERT(func->device != RT_NULL);
    RT_ASSERT(setup != RT_NULL);

    data = (struct vcom*)func->user_data;
    
    switch(setup->bRequest)
    {
    case CDC_SEND_ENCAPSULATED_COMMAND:
        break;
    case CDC_GET_ENCAPSULATED_RESPONSE:
        break;
    case CDC_SET_COMM_FEATURE:
        break;
    case CDC_GET_COMM_FEATURE:
        break;
    case CDC_CLEAR_COMM_FEATURE:
        break;
    case CDC_SET_LINE_CODING:
        _cdc_set_line_coding(func->device, setup);
        break;
    case CDC_GET_LINE_CODING:
        _cdc_get_line_coding(func->device, setup);
        break;
    case CDC_SET_CONTROL_LINE_STATE:
        data->connected = (setup->wValue & 0x01) > 0?RT_TRUE:RT_FALSE;
        RT_DEBUG_LOG(RT_DEBUG_USB, ("vcom state:%d \n", data->connected));
        dcd_ep0_send_status(func->device->dcd);
        break;
    case CDC_SEND_BREAK:
        break;
    default:
        rt_kprintf("unknown cdc request\n",setup->request_type);
        return -RT_ERROR;
    }

    return RT_EOK;
}

参考RS协议232控制定义:
RT-Thread USB虚拟串口收发调试_第1张图片
代码中的data->connected = (setup->wValue & 0x01) > 0?RT_TRUE:RT_FALSE;中的0x01代表检查DTR,0x02代表检查RTS,如果不需要DTR或者RTS可以直接把这里的data->connected置1。
不介意的话就可以在串口工具上勾上DTR:
RT-Thread USB虚拟串口收发调试_第2张图片

第二个接收不到数据的问题,main.c是这样写的:

#include 
#include 

rt_device_t dev = RT_NULL;
static struct rt_semaphore rx_sem;

static rt_err_t uart_input(rt_device_t dev, rt_size_t size)
{
    /* 串口接收到数据后产生中断,调用此回调函数,然后发送接收信号量 */
    rt_sem_release(&rx_sem);
    rt_kprintf("rx:%d...\n", size);
    return RT_EOK;
}

static void serial_thread_entry(void *parameter)
{
    char ch;

    while (1)
    {
        /* 从串口读取一个字节的数据,没有读取到则等待接收信号量 */
        while (rt_device_read(dev, -1, &ch, 1) != 1)
        {
            /* 阻塞等待接收信号量,等到信号量后再次读取数据 */
            rt_sem_take(&rx_sem, RT_WAITING_FOREVER);

        }
        rt_kprintf("read:%d\n", ch);
    }
}


int main(void)
{

    char buf[] = "hello rt-thread!\r\n";

    dev = rt_device_find("vcom");

    rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO);

    if (dev)
        rt_device_open(dev, RT_DEVICE_FLAG_RDWR);
    else
        return -RT_ERROR;

    rt_device_set_rx_indicate(dev, uart_input);

    rt_thread_t thread = rt_thread_create("serial", serial_thread_entry, RT_NULL, 1024, 25, 10);
    rt_thread_startup(thread);

    while (1)
    {
        rt_device_write(dev, 0, buf, rt_strlen(buf));
        rt_thread_mdelay(500);

    }

    return RT_EOK;
}

实际情况是会调用uart_input,但得到的size却一直都是-979,Debug代码发现在函数void rt_hw_serial_isr(struct rt_serial_device *serial, int event)中,有如下代码:

 case RT_SERIAL_EVENT_RX_IND:
        {
            int ch = -1;
            rt_base_t level;
            struct rt_serial_rx_fifo* rx_fifo;

            /* interrupt mode receive */
            rx_fifo = (struct rt_serial_rx_fifo*)serial->serial_rx;
            RT_ASSERT(rx_fifo != RT_NULL);

            while (1)
            {
                ch = serial->ops->getc(serial);
                if (ch == -1) break;


                /* disable interrupt */
                level = rt_hw_interrupt_disable();

                rx_fifo->buffer[rx_fifo->put_index] = ch;
                rx_fifo->put_index += 1;
                if (rx_fifo->put_index >= serial->config.bufsz) rx_fifo->put_index = 0;

                /* if the next position is read index, discard this 'read char' */
                if (rx_fifo->put_index == rx_fifo->get_index)
                {
                    rx_fifo->get_index += 1;
                    rx_fifo->is_full = RT_TRUE;
                    if (rx_fifo->get_index >= serial->config.bufsz) rx_fifo->get_index = 0;
                }

                /* enable interrupt */
                rt_hw_interrupt_enable(level);
            }

            /* invoke callback */
            if (serial->parent.rx_indicate != RT_NULL)
            {
                rt_size_t rx_length;

                /* get rx length */
                level = rt_hw_interrupt_disable();
                rx_length = (rx_fifo->put_index >= rx_fifo->get_index)? (rx_fifo->put_index - rx_fifo->get_index):
                    (serial->config.bufsz - (rx_fifo->get_index - rx_fifo->put_index));
                rt_hw_interrupt_enable(level);

                if (rx_length)
                {
                    serial->parent.rx_indicate(&serial->parent, rx_length);
                }
            }
            break;
        }

其中ch = serial->ops->getc(serial);可以接收到数据(实质数据保存在了一个ringbuffer里面),但 rx_fifo->put_index += 1;执行后并没有变化,rx_fifo指向地址0,初步怀疑是rx_fifo没有分配空间,对比串口1的程序,发现在执行static rt_err_t rt_serial_open(struct rt_device *dev, rt_uint16_t oflag)的时候,仅当模式为RT_DEVICE_FLAG_DMA_RX和RT_DEVICE_FLAG_INT_RX的时候,会执行:

 rx_fifo = (struct rt_serial_rx_fifo*) rt_malloc (sizeof(struct rt_serial_rx_fifo) +
                    serial->config.bufsz);

否则会继续执行 serial->serial_rx = RT_NULL;,所以把main函数中的rt_device_open(dev, RT_DEVICE_FLAG_RDWR);改为rt_device_open(dev, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX);就可以实现USB串口的收发了~
RT-Thread USB虚拟串口收发调试_第3张图片

你可能感兴趣的:(rt-thread)