打印

STM32 USB发送问题请教. 64B倍数时无法发送...

[复制链接]
10476|11
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
Swd21ic|  楼主 | 2010-3-3 15:17 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 Swd21ic 于 2010-3-3 15:28 编辑

因为PC软件是用串口编写的..所以仍想保持不变..但硬件上使用USB通信. CDC类.
根据官方2.2.1版(IAR5.30自带)的Vitrual_Com_Port例程修改了一个USB程序.


端点1.程序里封装了一个发送函数.并且在EP1_IN_Callback回调里做了"发送完成"标志位的处理

Bool SendOverFlag = true;      // 第一次时允许发送数据的.

void EP1_IN_Callback (void)
{
    SendOverFlag = ture;         // 通知一次发送完成
}

void USB_SendData (UINT8 *p_data, UINT32 num)
{
    UINT32 remain = num;
    UINT32 index   = 0;

    while (remain > 64)                        //一次最多发送64字节
    {
        while (SendOverFlag != ture);     //等待上一次发送完
        SendOverFlag = false;         

        UserToPMABufferCopy(&p_data[index], ENDP1_TXADDR, 64);
        SetEPTxCount(ENDP1, 64);
        SetEPTxValid(ENDP1);

        index  += 64;                           //计算偏移和剩余字节数
        remain -= 64;
    }

    while (SendOverFlag != ture);         
    SendOverFlag = false;
                                                      //发送最后<=64字节的数据
    UserToPMABufferCopy(&p_data[index], ENDP1_TXADDR, remain);
    SetEPTxCount(ENDP1, remain);
    SetEPTxValid(ENDP1);
}


杯具的是... 如果发送的数据个数是64的倍数时,PC上什么都收不到.
如USB_SendData(&Data[0], 64); USB_SendData(&Data[0], 256);
但发送63/65, 255/257都可以正确的受到数据.

找了半天确定了"最后一次当remain = 64的时候就不行"..如果剩下不时64的倍数就可以发送..(而且貌似前面几次的发送都是假的,并没有发送到PC,只有最后一次非64的Valid后.串口才受到数据).

现在的改进方法是将 if (remain > 64) 改为 (remain > 63) 这样每一次Valid都可以真正的将数据发送到PC..

对USB基本搞不懂.. 对程序的更改都时做了一些假设.. 想弄清楚为什么64字节就是发不出呢??...

谢过
来自 2楼
lxyppc| | 2010-3-3 16:05 | 只看该作者
对USB基本搞不懂.. 对程序的更改都时做了一些假设.. 想弄清楚为什么64字节就是发不出呢??...
Swd21ic 发表于 2010-3-3 15:17


USB的Bulk传输有两种方式认为数据传输完成
1. 发送的数据小于MaxPacketSize,这里MaxPacketSize是64
2. 发送的数据刚好等于请求的数据。即Windows中ReadFile()的size参数

如果发送的包全为64,则驱动认为接下来还有数据,会继续去读取USB的Bulk Endpoint,所以你感觉上收不到数据

使用特权

评论回复
板凳
lxyppc| | 2010-3-3 15:54 | 只看该作者
Bool SendOverFlag = true;      // 第一次时允许发送数据的.

void EP1_IN_Callback (void)
{
    SendOverFlag = ture;         // 通知一次发送完成
}

void USB_SendData (UINT8 *p_data, UINT32 num)
{
    UINT32 remain = num;
    UINT32 index   = 0;

    while (remain >= 64)                        //一次最多发送64字节
    {
        while (SendOverFlag != ture);     //等待上一次发送完
        SendOverFlag = false;         

        UserToPMABufferCopy(&p_data[index], ENDP1_TXADDR, 64);
        SetEPTxCount(ENDP1, 64);
        SetEPTxValid(ENDP1);

        index  += 64;                           //计算偏移和剩余字节数
        remain -= 64;
    }

    while (SendOverFlag != ture);         
    SendOverFlag = false;
                                                      //发送最后<=64字节的数据
    UserToPMABufferCopy(&p_data[index], ENDP1_TXADDR, remain);
    SetEPTxCount(ENDP1, remain);
    SetEPTxValid(ENDP1);
}

原因要从USB的Bulk传输协议说起

使用特权

评论回复
地板
Swd21ic|  楼主 | 2010-3-3 16:00 | 只看该作者
????? 按LS所说 >= 64.  那如果是64的倍数. 那么最后一次也是在while()循环内发送64个字节.
好像跟之前没区别的...

那下面的代码还需要吗? remain最后=0了. 最后发送一次空的吗??

使用特权

评论回复
5
Swd21ic|  楼主 | 2010-3-3 16:55 | 只看该作者
楼上高人!.. 果然如其所说...
看了下usb_20.pdf, bulk传输结束的条件是 传输小于wMaxPacketSize个数据或传输Size=0的包.
所以当跳出while()循环后, 最后的那次发送0字节包长的作为一个结束动作.

测试了一下发送1024个数据是正确的!
另外我观察了一下PC这边的串口助手, 只有最后0字节包发出去后. 才显示收到的1024个字节.
而while ()循环里的那些发送都不会显示.  请问到底是PC每次都收到了数据只是没有显示出来(难道我不发完..PC就永远不显示吗?). 还是STM32把数据到缓存起来了? PMA总共才512B啊.. 应该不可能才对...

能解释一下实质么? 谢谢了.

使用特权

评论回复
6
lxyppc| | 2010-3-3 21:45 | 只看该作者
另外我观察了一下PC这边的串口助手, 只有最后0字节包发出去后. 才显示收到的1024个字节.
而while ()循环里的那些发送都不会显示.  请问到底是PC每次都收到了数据只是没有显示出来(难道我不发完..PC就永远不显示吗?). 还是STM32把数据到缓存起来了? PMA总共才512B啊.. 应该不可能才对...
能解释一下实质么?
Swd21ic 发表于 2010-3-3 16:55

这个和Windows中USB的总线驱动有关,实际上数据是发出去了的,只是被总线驱动暂时保存起来了,直到遇到之前所述的结束条件总线驱动才返回数据
如果你用BusHound也会看到这样的情况,因为BusHound的过滤驱动在总线驱动之后

使用特权

评论回复
7
Swd21ic|  楼主 | 2010-3-3 22:02 | 只看该作者
非常感谢!.

使用特权

评论回复
8
lianxi47| | 2010-3-4 09:02 | 只看该作者
学习啦!

使用特权

评论回复
9
icer1| | 2010-3-4 12:22 | 只看该作者
mark

使用特权

评论回复
10
liudan_new| | 2010-3-4 13:12 | 只看该作者
64倍数的数据,最后需要发送一个0长度的包。

使用特权

评论回复
11
penguin_cc| | 2012-5-30 15:57 | 只看该作者
SetEPTxCount(ENDP1, 64);可不可以每次发一个更大的值呢,例如,SetEPTxCount(ENDP1, 128);

使用特权

评论回复
12
easylwl| | 2013-4-10 15:33 | 只看该作者
我用 STM32F207   usb发送 数据,情况和你刚好相反 ,我只能发送64倍数的字节 ,如果不是64字节倍数 就不能发送????
我的发送函数:
uint16_t VCP_DataTx (uint8_t* Buf, uint32_t Len)
{
uint8_t i;
for (i=0;i<64;i++)      //这里如果不是64,就不能发送成功,必须是64的倍数,
        {
        APP_Rx_Buffer[APP_Rx_ptr_in] = g_ucaHeartbeat;
        APP_Rx_ptr_in++;
         
          /* To avoid buffer overflow */
          if(APP_Rx_ptr_in == APP_RX_DATA_SIZE)
          {
            APP_Rx_ptr_in = 0;
          }  
        }
return USBD_OK;
}


usb_cdc_core.c里面的代码我没修改,使用的是ST公司的USB库2.0版本.
/**
  * @brief  usbd_audio_SOF
  *         Start Of Frame event management
  * @param  pdev: instance
  * @param  epnum: endpoint number
  * @retval status
  */
static uint8_t  usbd_cdc_SOF (void *pdev)
{      
  static uint32_t FrameCount = 0;
  
  if (FrameCount++ == CDC_IN_FRAME_INTERVAL)
  {
  
    FrameCount = 0;

    /* Check the data to be sent through IN pipe */
    Handle_USBAsynchXfer(pdev);
  }
  
  return USBD_OK;
}





/**
  * @brief  Handle_USBAsynchXfer
  *         Send data to USB
  * @param  pdev: instance
  * @retval None
  */
static void Handle_USBAsynchXfer (void *pdev)
{
  uint16_t USB_Tx_ptr;
  uint16_t USB_Tx_length;
  
  if(USB_Tx_State != 1)
  {
    if (APP_Rx_ptr_out == APP_RX_DATA_SIZE)
    {
      APP_Rx_ptr_out = 0;
    }
   
    if(APP_Rx_ptr_out == APP_Rx_ptr_in)
    {
      USB_Tx_State = 0;
      return;
    }
   
    if(APP_Rx_ptr_out > APP_Rx_ptr_in) /* rollback */
    {
      APP_Rx_length = APP_RX_DATA_SIZE - APP_Rx_ptr_out;
   
    }
    else
    {
      APP_Rx_length = APP_Rx_ptr_in - APP_Rx_ptr_out;
     
    }
#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
     APP_Rx_length &= ~0x03;
#endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
   
    if (APP_Rx_length > CDC_DATA_IN_PACKET_SIZE)
    {
      USB_Tx_ptr = APP_Rx_ptr_out;
      USB_Tx_length = CDC_DATA_IN_PACKET_SIZE;
      
      APP_Rx_ptr_out += CDC_DATA_IN_PACKET_SIZE;        
      APP_Rx_length -= CDC_DATA_IN_PACKET_SIZE;
    }
    else
    {
      USB_Tx_ptr = APP_Rx_ptr_out;
      USB_Tx_length = APP_Rx_length;
      
      APP_Rx_ptr_out += APP_Rx_length;
      APP_Rx_length = 0;
    }
    USB_Tx_State = 1;

    DCD_EP_Tx (pdev,
               VL8461_IN_EP,
               (uint8_t*)&APP_Rx_Buffer[USB_Tx_ptr],
               USB_Tx_length);       //这里的 USB_Tx_length 只要不是 64,就发送不成功????
  }  
  
}

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

71

主题

781

帖子

1

粉丝