简体   繁体   English

我无法在基于自定义 USB CDC class 的 STM32 设备上接收超过 64 个字节

[英]I can't receive more than 64 bytes on custom USB CDC class based STM32 device

currently I try to sent 720 bytes from Windows application to custom STM32 device (now for testing purposes I use Blue Pill - STM32F103xxx).目前我尝试将 720 个字节从 Windows 应用程序发送到自定义 STM32 设备(现在出于测试目的,我使用 Blue Pill - STM32F103xxx)。 Ah, I forgot to point that I am totally newbie into programming:).啊,我忘了指出我完全是编程新手:)。 So on device side I have 1000 bytes buffers for receiving and sending (Thanks to STMCube for this).所以在设备端,我有 1000 字节的缓冲区用于接收和发送(感谢 STMCube)。 Testing device with terminal program ( packets < than 64 bytes) works.带有终端程序(数据包<64字节)的测试设备工作正常。 Then I rework one of Microsoft examples to be able to sent more data to device.然后我重新设计了一个 Microsoft 示例,以便能够向设备发送更多数据。 Used device driver on Windows is "usbser.sys". Windows 上使用的设备驱动程序是“usbser.sys”。 In short my console program do following:简而言之,我的控制台程序执行以下操作:

  1. Calculate SINE weave (360) samples - 16 bytes size计算 SINE weave (360) 样本 - 16 字节大小
  2. Sent them to USB Device as 720 bytes (byte size protocol for COM port) My problem is that no more than 64 bytes comes into device.将它们作为 720 字节发送到 USB 设备(COM 端口的字节大小协议)我的问题是进入设备的字节数不超过 64。 Somewhere I read that reason for this can be into built in Rx,Tx Windows buffers (64 bytes long by mention somewhere on internet) and for this into code below I insert:在某处我读到这个原因可能是内置在 Rx,Tx Windows 缓冲区(64 字节长,在互联网上某处提到),为此我在下面的代码中插入:
    • SetupComm(hCom,1000,1000) in hope that this will solve my troubles but nope. SetupComm(hCom,1000,1000) 希望这能解决我的麻烦,但没有。 Below is "my" code, any ideas how I can fix this?下面是“我的”代码,有什么想法可以解决这个问题吗?
    #include <windows.h>
    #include <tchar.h>
    #include <stdio.h>
    #include <math.h>  
    
    #define PI 3.14159265
  
    void PrintCommState(DCB dcb)
    {
        //  Print some of the DCB structure values
        _tprintf(TEXT("\nBaudRate = %d, ByteSize = %d, Parity = %d, StopBits = %d\n"),
            dcb.BaudRate,
            dcb.ByteSize,
            dcb.Parity,
            dcb.StopBits);
    }
    
    
    int _tmain(int argc, TCHAR* argv[])
    {
        DCB dcb;
        HANDLE hCom;
        BOOL fSuccess;
        const TCHAR* pcCommPort = TEXT("COM3"); //  Most systems have a COM1 port
        unsigned __int8 aOutputBuffer[720];// Data that will sent to device
        unsigned __int16 aCalculatedWave[360];// Data that will sent to device
        int iCnt; // temp counter to use everywhere 
    
        for (iCnt = 0; iCnt < 360; iCnt = iCnt + 1)
        {
            aCalculatedWave[iCnt] = (unsigned short)(0xFFFF * sin(iCnt * PI / 180));
            if (iCnt > 180) aCalculatedWave[iCnt] = 0 - aCalculatedWave[iCnt];
        }
    
        // 16 bit aCalculatedWaveto to 8 bit aOutputBuffer
        for (int i = 0, j = 0; i < 720; i += 2, ++j)
        {
            aOutputBuffer[i] = aCalculatedWave[j] >> 8; // Hi byte
            aOutputBuffer[i + 1] = aCalculatedWave[j] & 0xFF; // Lo byte
        }
    
        //  Open a handle to the specified com port.
        hCom = CreateFile(pcCommPort,
            GENERIC_READ | GENERIC_WRITE,
            0,      //  must be opened with exclusive-access
            NULL,   //  default security attributes
            OPEN_EXISTING, //  must use OPEN_EXISTING
            0,      //  not overlapped I/O
            NULL); //  hTemplate must be NULL for comm devices
    
        if (hCom == INVALID_HANDLE_VALUE)
        {
            //  Handle the error.
            printf("CreateFile failed with error %d.\n", GetLastError());
            return (1);
        }
        if (SetupComm(hCom,1000,1000) !=0)
            printf("Windows In/Out serial buffers changed to 1000 bytes\n");
        else
            printf("Buffers not changed with error %d.\n", GetLastError());
    
        //  Initialize the DCB structure.
        SecureZeroMemory(&dcb, sizeof(DCB));
        dcb.DCBlength = sizeof(DCB);
    
        //  Build on the current configuration by first retrieving all current
        //  settings.
        fSuccess = GetCommState(hCom, &dcb);
    
        if (!fSuccess)
        {
            //  Handle the error.
            printf("GetCommState failed with error %d.\n", GetLastError());
            return (2);
        }
    
        PrintCommState(dcb);       //  Output to console
    
        //  Fill in some DCB values and set the com state: 
        //  57,600 bps, 8 data bits, no parity, and 1 stop bit.
        dcb.BaudRate = CBR_9600;     //  baud rate
        dcb.ByteSize = 8;             //  data size, xmit and rcv
        dcb.Parity = NOPARITY;      //  parity bit
        dcb.StopBits = ONESTOPBIT;    //  stop bit
    
        fSuccess = SetCommState(hCom, &dcb);
    
        if (!fSuccess)
        {
            //  Handle the error.
            printf("SetCommState failed with error %d.\n", GetLastError());
            return (3);
        }
    
        //  Get the comm config again.
        fSuccess = GetCommState(hCom, &dcb);
    
        if (!fSuccess)
        {
            //  Handle the error.
            printf("GetCommState failed with error %d.\n", GetLastError());
            return (2);
        }
    
        PrintCommState(dcb);       //  Output to console
    
        _tprintf(TEXT("Serial port %s successfully reconfigured.\n"), pcCommPort);
        if (WriteFile(hCom, aOutputBuffer, 720, NULL, 0) != 0)
            _tprintf(TEXT("720 bytes successfully writed to Serial port %s \n"), pcCommPort);
        else
            _tprintf(TEXT("Fail on write 720 bytes to Serial port %s \n"), pcCommPort);
        return (0);
    }

USB bulk endpoints implement a stream-based protocol, ie an endless stream of bytes. USB 批量端点实现了基于流的协议,即无穷无尽的 stream 字节。 This is in contrast to a message-based protocol.这与基于消息的协议形成对比。 So USB bulk endpoints have no concept of messages, message start or end.所以 USB 批量端点没有消息、消息开始或结束的概念。 This also applies to USB CDC as it is based on bulk endpoints.这也适用于 USB CDC,因为它基于批量端点。

At the lower USB level, the stream of bytes is split into packets of at most 64 bytes.在较低的 USB 级别,stream 字节被拆分为最多 64 字节的数据包。 As per USB full-speed standard, packets cannot be larger than 64 bytes.根据 USB 全速标准,数据包不能大于 64 字节。

If the host sends small chunks of data that are more than 1ms apart, they will be sent and received in separate packets and it looks as if USB is a message-based protocol.如果主机发送间隔超过 1 毫秒的小数据块,它们将在单独的数据包中发送和接收,看起来 USB 是基于消息的协议。 However, for chunks of more than 64 bytes, they are split into smaller packets.但是,对于超过 64 字节的块,它们被分成更小的数据包。 And if small chunks are sent with less than 1ms in-between, the host will merge them into bigger packets.如果小块的发送间隔小于 1 毫秒,主机会将它们合并成更大的数据包。

Your design seems to require that data is grouped, eg the group of 720 bytes mentioned in the question.您的设计似乎要求对数据进行分组,例如问题中提到的 720 字节组。 If this is a requirement, the grouping must be implemented, eg by first sending the size of the group and then the data.如果这是一个要求,则必须实施分组,例如首先发送组的大小,然后发送数据。

Since larger groups are split into chunks of 64 bytes and the receive callback is called for every packet, the packets must be joined until the full group is available.由于较大的组被分成 64 字节的块,并且为每个数据包调用接收回调,因此必须加入数据包,直到整个组可用。

Also note a few problems in your current code (see usbd_cdc_if.c, line 264 ):还要注意当前代码中的一些问题(参见usbd_cdc_if.c,第 264 行):

  USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
  USBD_CDC_ReceivePacket(&hUsbDeviceFS);
  NewDataFromUsb = *Len;

USBD_CDC_SetRxBuffer sets the buffer for the next packet to be received. USBD_CDC_SetRxBuffer为要接收的下一个数据包设置缓冲区。 If you always use the same buffer – as in this case – it's not needed.如果您总是使用相同的缓冲区(如本例所示),则不需要。 The initial setup is sufficient.初始设置就足够了。 However, it could be used to set a new buffer if the current packet does not contain a full group.但是,如果当前数据包不包含完整组,则可以使用它来设置新缓冲区。

Despite its name, USBD_CDC_ReceivePacket does not receive a packet.尽管它的名字, USBD_CDC_ReceivePacket不接收数据包。 Instead, it gives the OK to receive the next package.相反,它允许接收下一个 package。 It should only be called if the data in the buffer has been processed and the buffer is ready to receive the next packet.仅当缓冲区中的数据已被处理并且缓冲区已准备好接收下一个数据包时才应调用它。 Your current implementation runs the risk that the buffer is overwritten before it is processed, in particular if you send a group of more than 64 bytes, which will likely result in a quick succession of packets.您当前的实现存在缓冲区在处理之前被覆盖的风险,特别是如果您发送超过 64 个字节的组,这可能会导致快速连续的数据包。

Note that Windows hasn't been mentioned here.请注意,此处未提及 Windows。 The Windows code seems to be okay. Windows 代码似乎没问题。 And changing to Winusb.sys will just make your life harder but not get you packets bigger than 64 bytes.更改为 Winusb.sys 只会让您的生活更加艰难,但不会让您的数据包大于 64 字节。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM