[AT32F405] 【AT-START-F405测评】WinUSB速度测试

[复制链接]
 楼主| Ketose 发表于 2024-5-12 18:03 | 显示全部楼层 |阅读模式
本帖最后由 Ketose 于 2024-5-12 18:10 编辑

我所在的公司是做图像传感器的感存算一体的芯片,所以做调试工具的时候要用到USB2.0把图像处理结果输出至上位机进行显示,观察计算结果。而且又用到QSPI,一直在选择一个合适的主控,之前主控使用的是NXP的LPC4357,这款芯片又贵,又不好买。有幸试用国产雅特力AT32F405的芯片,把这段时间试用和调试过程遇到的问题做个总结和分享。

首先对于雅特力国产芯片这几年的进步真的是非常大,不管是资料、例子代码、还是开发工具都做的相当不错,再过几年估计要把ST卷死都有可能。

拿到开发板首先是看原理图,到官方网站找到相关资料,关于USB的资料雅特力其实官方已经给出了很多的例子,我这里用到官方给的两个例子:<SC0090 AT32F4xx WinUSB>,<SC0125 USB Composite HID>。先跑了一下SC0125,没啥问题电脑识别出了,打开计事本,按下蓝色按钮,会输出“ Keyboard Demo”字样。跑一下SC0090,这个例子是基于AT32F435芯片的,而且里面的WinUSB中间件从函数名字来看是从VCP上改过来的,名字都还没来得及改。那我们改造SC0125吧。
1、首先在项目里加入winusb_class.c 和winusb_desc.c这两个文件
2、修改usb_conf.h加入对WinUSB的支持
3、修改main.c

main.c代码如下:

  1. #include "at32f402_405_board.h"
  2. #include "at32f402_405_clock.h"
  3. #include "usb_conf.h"
  4. #include "usb_core.h"
  5. #include "usbd_int.h"
  6. #include "winusb_class.h"
  7. #include "winusb_desc.h"


  8. /** @addtogroup AT32F405_periph_examples
  9.   * @{
  10.   */

  11. /** @addtogroup 405_USB_device_custom_hid USB_device_custom_hid
  12.   * @{
  13.   */

  14. /* usb global struct define */
  15. otg_core_type otg_core_struct;
  16. #if defined ( __ICCARM__ ) /* iar compiler */
  17.   #pragma data_alignment=4
  18. #endif

  19. #define BUF_SIZE 512


  20. uint8_t usb_buffer[BUF_SIZE];

  21. void usb_clock48m_select(usb_clk48_s clk_s);
  22. void usb_gpio_config(void);
  23. void usb_low_power_wakeup_config(void);
  24. void button_exint_init(void);

  25. void init_buffer();

  26. /**
  27.   * [url=home.php?mod=space&uid=247401]@brief[/url]  main function.
  28.   * @param  none
  29.   * @retval none
  30.   */
  31. int main(void)
  32. {
  33.         uint16_t data_len;
  34.         uint8_t send_zero_packet = 0;
  35.         
  36.   nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);

  37.   system_clock_config();

  38.   at32_board_init();

  39.     /* usb gpio config */
  40.   usb_gpio_config();

  41. #ifdef USB_LOW_POWER_WAKUP
  42.   crm_periph_clock_enable(CRM_PWC_PERIPH_CLOCK, TRUE);
  43.   button_exint_init();
  44.   usb_low_power_wakeup_config();
  45. #endif

  46.   /* enable otg clock */
  47.   crm_periph_clock_enable(OTG_CLOCK, TRUE);

  48.   /* select usb 48m clcok source */
  49.   usb_clock48m_select(USB_CLK_HEXT);

  50.   /* enable otg irq */
  51.   nvic_irq_enable(OTG_IRQ, 0, 0);
  52.         
  53.         /* Initialization buffer */
  54.         init_buffer();

  55.   /* init usb */
  56.         usbd_init(&otg_core_struct,
  57.                                                 USB_HIGH_SPEED_CORE_ID,
  58.                                                 USB_ID,
  59.                                                 &winusb_class_handler,
  60.                                                 &winusb_desc_handler);
  61.                
  62.   while(1)
  63.   {
  64.                 if(usbd_connect_state_get(&otg_core_struct.dev) == USB_CONN_STATE_CONFIGURED)
  65.                 {
  66.                         usb_winusb_send_data(&otg_core_struct.dev,usb_buffer,BUF_SIZE);
  67.                 }
  68.   }
  69. }

OK,编译,烧入MCU Reset。windows11 竟然认不到这个设备,在其它设备里显示AT32 WinUSB,加载不了WinUSB的驱动。这个问题花了很多时间,又是抓包,又是加调试输出,把整个USB的枚举流程跟了一遍,也没发现什么问题,就是看不到操作系统检索0xEE位置的OS设备字串描述符,但是usb_conf.h文件里已经添加了USBD_SUPPORT_WINUSB宏定义。
最后在网上找到一篇文章和我一样的问题,它是这样解释:由于我之前跑的例子是HID设备,改为WinUSB后它的VID和PID其实是没有改变过,Windows会缓存VID和PID信息,在下一次枚举设备的时候直接加载HID驱动。找到原因就好办了,两种办法:1、清除windows的驱动缓存。2、改PID。这里我选择第一种办法

删除注册表中USB设备信息的方法:
1、下载PStools工具包 https://technet.microsoft.com/en-us/sysinternals/bb897553.aspx,解压到C:\pstools

2、以管理员身份运行CMD,输入命令:cd C:\pstools ,切换到pstools目录,再输入命令:psexec.exe -i -d -s regedit.exe

3、进入HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB\删除相关设备(以本文为例,VID PID分别为 2E3C 5780)

进入HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\UsbFlags\删除相关设备(以本文为例,VID PID分别为 2E3C 5780)

4、OK,此时再插入该Device,即被当做全新设备插入,装载驱动。


用VC++写一个简单的上位机,测试下速度如何。
  1. // winusb_demo.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
  2. //

  3. #include <iostream>
  4. #include <chrono>
  5. #include <format>
  6. #include <thread>

  7. #include "CWinUSBProxy.h"

  8. int main()
  9. {
  10.     std::cout << "Hello AT32!\n";

  11.     CWinUSBProxy winUSBDevice;

  12.     winUSBDevice.OpenWinUsb();
  13.     winUSBDevice.GetUSBDeviceSpeed();
  14.     winUSBDevice.QueryDeviceEndpoints();

  15.     while (true)
  16.     {
  17.         int readCount = 0;
  18.         auto startTime = std::chrono::steady_clock::now();
  19.         /** 进行数据发包统计,发送1MB数据包,统计速率 */
  20.         for (int i = 0; i < 1024; i++)
  21.         {
  22.             BOOL status = winUSBDevice.ReadFromBulkEndpoint(1024);
  23.             /** 正确发包计数 */
  24.             if (status)
  25.                 readCount++;
  26.         }
  27.         auto entTime = std::chrono::steady_clock::now();

  28.         /** 计算速率 */
  29.         auto dr_s = std::chrono::duration<double, std::milli>(entTime - startTime).count();
  30.         auto  speed = floor(readCount * 1000 / dr_s) ;
  31.         /** 输出统计信息 */
  32.         std::cout << std::format("read speed:{} KB/S",speed) << std::endl;
  33.         /** 等待1秒 */
  34.         std::this_thread::sleep_for(std::chrono::milliseconds(1000));
  35.     }
  36.    
  37.     system("pause");
  38. }
最终经过优化后速度达到31MB,达到USB2.0理论速度的一半,还是非常不错。
屏幕截图 2024-05-12 175734.png

参考链接:
https://github.com/pbatard/libwdi/wiki/WCID-Devices
https://www.codenong.com/41644081/
https://blog.csdn.net/bingwueyi/article/details/121622001
gouguoccc 发表于 2024-5-13 08:04 来自手机 | 显示全部楼层
写速度能达到多少呢?测试过吗?
 楼主| Ketose 发表于 2024-5-13 10:02 | 显示全部楼层
gouguoccc 发表于 2024-5-13 08:04
写速度能达到多少呢?测试过吗?

写入速度没有测试。回头测试一下。
呐咯密密 发表于 2024-5-13 13:18 | 显示全部楼层
还不错的测试,实现的效果很好
micoccd 发表于 2024-5-13 14:30 | 显示全部楼层
这个速度还可以
 楼主| Ketose 发表于 2024-5-13 22:56 | 显示全部楼层
上位机写入测试代码:
  1. // winusb_demo.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
  2. //

  3. #include <iostream>
  4. #include <chrono>
  5. #include <format>
  6. #include <thread>

  7. #include "CWinUSBProxy.h"

  8. #define BUF_SIZE            1024

  9. int main()
  10. {
  11.     std::cout << "Hello AT32!\n";

  12.     CWinUSBProxy winUSBDevice("{13EB360B-BC1E-46CB-AC8B-EF3DA47B4062}");

  13.     winUSBDevice.InitWinUsbDevicePath();
  14.     winUSBDevice.OpenWinUsb();
  15.     winUSBDevice.GetUSBDeviceSpeed();
  16.     winUSBDevice.QueryDeviceEndpoints();

  17.     while (true)
  18.     {
  19.         int readCount = 0;
  20.         auto startTime = std::chrono::steady_clock::now();
  21.         /** 进行数据发包统计,发送1MB数据包,统计速率 */
  22.         for (int i = 0; i < 1024; i++)
  23.         {
  24. #if 0
  25.             BOOL status = winUSBDevice.ReadFromBulkEndpoint(BUF_SIZE);
  26. #else
  27.             BOOL status = winUSBDevice.WriteToBulkEndpoint(BUF_SIZE);
  28. #endif
  29.             /** 正确发包计数 */
  30.             if (status)
  31.                 readCount++;
  32.         }
  33.         auto entTime = std::chrono::steady_clock::now();

  34.         /** 计算速率 */
  35.         auto dr_s = std::chrono::duration<double, std::milli>(entTime - startTime).count();
  36.         auto  speed = floor(readCount * 1000 / dr_s) ;
  37.         /** 输出统计信息 */
  38.         std::cout << std::format("transter speed:{} KB/S",speed) << std::endl;
  39.         /** 等待1秒 */
  40.         std::this_thread::sleep_for(std::chrono::milliseconds(1000));
  41.     }
  42.    
  43.     system("pause");
  44. }

MCU代码:
  1. /**
  2.   **************************************************************************
  3.   * [url=home.php?mod=space&uid=288409]@file[/url]     main.c
  4.   * @brief    main program
  5.   **************************************************************************
  6.   *                       Copyright notice & Disclaimer
  7.   *
  8.   * The software Board Support Package (BSP) that is made available to
  9.   * download from Artery official website is the copyrighted work of Artery.
  10.   * Artery authorizes customers to use, copy, and distribute the BSP
  11.   * software and its related documentation for the purpose of design and
  12.   * development in conjunction with Artery microcontrollers. Use of the
  13.   * software is governed by this copyright notice and the following disclaimer.
  14.   *
  15.   * THIS SOFTWARE IS PROVIDED ON "AS IS" BASIS WITHOUT WARRANTIES,
  16.   * GUARANTEES OR REPRESENTATIONS OF ANY KIND. ARTERY EXPRESSLY DISCLAIMS,
  17.   * TO THE FULLEST EXTENT PERMITTED BY LAW, ALL EXPRESS, IMPLIED OR
  18.   * STATUTORY OR OTHER WARRANTIES, GUARANTEES OR REPRESENTATIONS,
  19.   * INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
  20.   * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
  21.   *
  22.   **************************************************************************
  23.   */


  24. #include "at32f402_405_board.h"
  25. #include "at32f402_405_clock.h"
  26. #include "usb_conf.h"
  27. #include "usb_core.h"
  28. #include "usbd_int.h"
  29. #include "winusb_class.h"
  30. #include "winusb_desc.h"


  31. /** @addtogroup AT32F405_periph_examples
  32.   * @{
  33.   */

  34. /** @addtogroup 405_USB_device_custom_hid USB_device_custom_hid
  35.   * @{
  36.   */

  37. /* usb global struct define */
  38. otg_core_type otg_core_struct;
  39. #if defined ( __ICCARM__ ) /* iar compiler */
  40.   #pragma data_alignment=4
  41. #endif

  42. #define BUF_SIZE                                                512


  43. uint8_t usb_buffer[BUF_SIZE];

  44. void usb_clock48m_select(usb_clk48_s clk_s);
  45. void usb_gpio_config(void);
  46. void usb_low_power_wakeup_config(void);
  47. void button_exint_init(void);

  48. void init_buffer();

  49. /**
  50.   * @brief  main function.
  51.   * @param  none
  52.   * @retval none
  53.   */
  54. int main(void)
  55. {
  56.         uint16_t data_len;
  57.         uint8_t send_zero_packet = 0;
  58.        
  59.   nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);

  60.   system_clock_config();

  61.   at32_board_init();

  62.     /* usb gpio config */
  63.   usb_gpio_config();

  64. #ifdef USB_LOW_POWER_WAKUP
  65.   crm_periph_clock_enable(CRM_PWC_PERIPH_CLOCK, TRUE);
  66.   button_exint_init();
  67.   usb_low_power_wakeup_config();
  68. #endif

  69.   /* enable otg clock */
  70.   crm_periph_clock_enable(OTG_CLOCK, TRUE);

  71.   /* select usb 48m clcok source */
  72.   usb_clock48m_select(USB_CLK_HEXT);

  73.   /* enable otg irq */
  74.   nvic_irq_enable(OTG_IRQ, 0, 0);
  75.        
  76.         /* Initialization buffer */
  77.         init_buffer();

  78.   /* init usb */
  79.         usbd_init(&otg_core_struct,
  80.                                                 USB_HIGH_SPEED_CORE_ID,
  81.                                                 USB_ID,
  82.                                                 &winusb_class_handler,
  83.                                                 &winusb_desc_handler);
  84.                                                
  85.        
  86.                
  87.   while(1)
  88.   {
  89.                 if(usbd_connect_state_get(&otg_core_struct.dev) == USB_CONN_STATE_CONFIGURED)
  90.                 {
  91.                 #if 0
  92.                         usb_winusb_send_data(&otg_core_struct.dev,usb_buffer,BUF_SIZE);
  93.                 #else
  94.                         uint32_t count = usb_winusb_get_rxdata(&otg_core_struct.dev,usb_buffer);
  95.                         //printf("count:%d\r\n",count);
  96.                 #endif
  97.                 }
  98.   }
  99. }

测试结果:
屏幕截图 2024-05-13 223753.png

这个写入速度15MB/S,这个速度是在注释掉了usb_winusb_get_rxdata里的内存复制过程,代码如下
  1. /**
  2.   * @brief  usb device class rx data process
  3.   * @param  udev: to the structure of usbd_core_type
  4.   * @param  recv_data: receive buffer
  5.   * @retval receive data len
  6.   */
  7. uint16_t usb_winusb_get_rxdata(void *udev, uint8_t *recv_data)
  8. {
  9.   uint16_t i_index = 0;
  10.   uint16_t tmp_len = 0;
  11.   usbd_core_type *pudev = (usbd_core_type *)udev;
  12.   winusb_struct_type *p_winusb = (winusb_struct_type *)pudev->class_handler->pdata;

  13.   if(p_winusb->g_rx_completed == 0)
  14.   {
  15.     return 0;
  16.   }
  17.   p_winusb->g_rx_completed = 0;
  18.   tmp_len = p_winusb->g_rxlen;
  19. //  for(i_index = 0; i_index < p_winusb->g_rxlen; i_index ++)
  20. //  {
  21. //    recv_data[i_index] = p_winusb->g_rx_buff[i_index];
  22. //  }

  23.   usbd_ept_recv(pudev, USBD_WINUSB_BULK_OUT_EPT, p_winusb->g_rx_buff, p_winusb->maxpacket);

  24.   return tmp_len;
  25. }
开启内存复制,大概速度在8-9MB/S左右。


以上测试结果和官方的测试结果有点出入。总体来说好于官方数据。


yangxiaor520 发表于 2024-5-14 07:59 来自手机 | 显示全部楼层
做图算应用,MCU的USB带宽确定够吗?
LEDyyds 发表于 2024-5-14 11:00 | 显示全部楼层
楼主威武,真出了写入的测试
 楼主| Ketose 发表于 2024-5-14 12:45 | 显示全部楼层
yangxiaor520 发表于 2024-5-14 07:59
做图算应用,MCU的USB带宽确定够吗?

应用领域不一样,256*256的单色图像,USB2.0的速度可以了。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:我最讨厌两种人:一是有种族歧视的; 二是黑人;三是不识数的!

66

主题

3258

帖子

15

粉丝
快速回复 在线客服 返回列表 返回顶部
个人签名:我最讨厌两种人:一是有种族歧视的; 二是黑人;三是不识数的!

66

主题

3258

帖子

15

粉丝
快速回复 在线客服 返回列表 返回顶部