【AT-START-F405测评】WinUSB速度测试
本帖最后由 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代码如下:
#include "at32f402_405_board.h"
#include "at32f402_405_clock.h"
#include "usb_conf.h"
#include "usb_core.h"
#include "usbd_int.h"
#include "winusb_class.h"
#include "winusb_desc.h"
/** @addtogroup AT32F405_periph_examples
* @{
*/
/** @addtogroup 405_USB_device_custom_hid USB_device_custom_hid
* @{
*/
/* usb global struct define */
otg_core_type otg_core_struct;
#if defined ( __ICCARM__ ) /* iar compiler */
#pragma data_alignment=4
#endif
#define BUF_SIZE 512
uint8_t usb_buffer;
void usb_clock48m_select(usb_clk48_s clk_s);
void usb_gpio_config(void);
void usb_low_power_wakeup_config(void);
void button_exint_init(void);
void init_buffer();
/**
* @briefmain function.
* @paramnone
* @retval none
*/
int main(void)
{
uint16_t data_len;
uint8_t send_zero_packet = 0;
nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
system_clock_config();
at32_board_init();
/* usb gpio config */
usb_gpio_config();
#ifdef USB_LOW_POWER_WAKUP
crm_periph_clock_enable(CRM_PWC_PERIPH_CLOCK, TRUE);
button_exint_init();
usb_low_power_wakeup_config();
#endif
/* enable otg clock */
crm_periph_clock_enable(OTG_CLOCK, TRUE);
/* select usb 48m clcok source */
usb_clock48m_select(USB_CLK_HEXT);
/* enable otg irq */
nvic_irq_enable(OTG_IRQ, 0, 0);
/* Initialization buffer */
init_buffer();
/* init usb */
usbd_init(&otg_core_struct,
USB_HIGH_SPEED_CORE_ID,
USB_ID,
&winusb_class_handler,
&winusb_desc_handler);
while(1)
{
if(usbd_connect_state_get(&otg_core_struct.dev) == USB_CONN_STATE_CONFIGURED)
{
usb_winusb_send_data(&otg_core_struct.dev,usb_buffer,BUF_SIZE);
}
}
}
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++写一个简单的上位机,测试下速度如何。
// winusb_demo.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include <chrono>
#include <format>
#include <thread>
#include "CWinUSBProxy.h"
int main()
{
std::cout << "Hello AT32!\n";
CWinUSBProxy winUSBDevice;
winUSBDevice.OpenWinUsb();
winUSBDevice.GetUSBDeviceSpeed();
winUSBDevice.QueryDeviceEndpoints();
while (true)
{
int readCount = 0;
auto startTime = std::chrono::steady_clock::now();
/** 进行数据发包统计,发送1MB数据包,统计速率 */
for (int i = 0; i < 1024; i++)
{
BOOL status = winUSBDevice.ReadFromBulkEndpoint(1024);
/** 正确发包计数 */
if (status)
readCount++;
}
auto entTime = std::chrono::steady_clock::now();
/** 计算速率 */
auto dr_s = std::chrono::duration<double, std::milli>(entTime - startTime).count();
autospeed = floor(readCount * 1000 / dr_s) ;
/** 输出统计信息 */
std::cout << std::format("read speed:{} KB/S",speed) << std::endl;
/** 等待1秒 */
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
system("pause");
}
最终经过优化后速度达到31MB,达到USB2.0理论速度的一半,还是非常不错。
参考链接:
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
写速度能达到多少呢?测试过吗?
写入速度没有测试。回头测试一下。 还不错的测试,实现的效果很好 这个速度还可以 上位机写入测试代码:
// winusb_demo.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include <chrono>
#include <format>
#include <thread>
#include "CWinUSBProxy.h"
#define BUF_SIZE 1024
int main()
{
std::cout << "Hello AT32!\n";
CWinUSBProxy winUSBDevice("{13EB360B-BC1E-46CB-AC8B-EF3DA47B4062}");
winUSBDevice.InitWinUsbDevicePath();
winUSBDevice.OpenWinUsb();
winUSBDevice.GetUSBDeviceSpeed();
winUSBDevice.QueryDeviceEndpoints();
while (true)
{
int readCount = 0;
auto startTime = std::chrono::steady_clock::now();
/** 进行数据发包统计,发送1MB数据包,统计速率 */
for (int i = 0; i < 1024; i++)
{
#if 0
BOOL status = winUSBDevice.ReadFromBulkEndpoint(BUF_SIZE);
#else
BOOL status = winUSBDevice.WriteToBulkEndpoint(BUF_SIZE);
#endif
/** 正确发包计数 */
if (status)
readCount++;
}
auto entTime = std::chrono::steady_clock::now();
/** 计算速率 */
auto dr_s = std::chrono::duration<double, std::milli>(entTime - startTime).count();
autospeed = floor(readCount * 1000 / dr_s) ;
/** 输出统计信息 */
std::cout << std::format("transter speed:{} KB/S",speed) << std::endl;
/** 等待1秒 */
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
system("pause");
}
MCU代码:
/**
**************************************************************************
* @file main.c
* @brief main program
**************************************************************************
* Copyright notice & Disclaimer
*
* The software Board Support Package (BSP) that is made available to
* download from Artery official website is the copyrighted work of Artery.
* Artery authorizes customers to use, copy, and distribute the BSP
* software and its related documentation for the purpose of design and
* development in conjunction with Artery microcontrollers. Use of the
* software is governed by this copyright notice and the following disclaimer.
*
* THIS SOFTWARE IS PROVIDED ON "AS IS" BASIS WITHOUT WARRANTIES,
* GUARANTEES OR REPRESENTATIONS OF ANY KIND. ARTERY EXPRESSLY DISCLAIMS,
* TO THE FULLEST EXTENT PERMITTED BY LAW, ALL EXPRESS, IMPLIED OR
* STATUTORY OR OTHER WARRANTIES, GUARANTEES OR REPRESENTATIONS,
* INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
*
**************************************************************************
*/
#include "at32f402_405_board.h"
#include "at32f402_405_clock.h"
#include "usb_conf.h"
#include "usb_core.h"
#include "usbd_int.h"
#include "winusb_class.h"
#include "winusb_desc.h"
/** @addtogroup AT32F405_periph_examples
* @{
*/
/** @addtogroup 405_USB_device_custom_hid USB_device_custom_hid
* @{
*/
/* usb global struct define */
otg_core_type otg_core_struct;
#if defined ( __ICCARM__ ) /* iar compiler */
#pragma data_alignment=4
#endif
#define BUF_SIZE 512
uint8_t usb_buffer;
void usb_clock48m_select(usb_clk48_s clk_s);
void usb_gpio_config(void);
void usb_low_power_wakeup_config(void);
void button_exint_init(void);
void init_buffer();
/**
* @briefmain function.
* @paramnone
* @retval none
*/
int main(void)
{
uint16_t data_len;
uint8_t send_zero_packet = 0;
nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
system_clock_config();
at32_board_init();
/* usb gpio config */
usb_gpio_config();
#ifdef USB_LOW_POWER_WAKUP
crm_periph_clock_enable(CRM_PWC_PERIPH_CLOCK, TRUE);
button_exint_init();
usb_low_power_wakeup_config();
#endif
/* enable otg clock */
crm_periph_clock_enable(OTG_CLOCK, TRUE);
/* select usb 48m clcok source */
usb_clock48m_select(USB_CLK_HEXT);
/* enable otg irq */
nvic_irq_enable(OTG_IRQ, 0, 0);
/* Initialization buffer */
init_buffer();
/* init usb */
usbd_init(&otg_core_struct,
USB_HIGH_SPEED_CORE_ID,
USB_ID,
&winusb_class_handler,
&winusb_desc_handler);
while(1)
{
if(usbd_connect_state_get(&otg_core_struct.dev) == USB_CONN_STATE_CONFIGURED)
{
#if 0
usb_winusb_send_data(&otg_core_struct.dev,usb_buffer,BUF_SIZE);
#else
uint32_t count = usb_winusb_get_rxdata(&otg_core_struct.dev,usb_buffer);
//printf("count:%d\r\n",count);
#endif
}
}
}
测试结果:
这个写入速度15MB/S,这个速度是在注释掉了usb_winusb_get_rxdata里的内存复制过程,代码如下
/**
* @briefusb device class rx data process
* @paramudev: to the structure of usbd_core_type
* @paramrecv_data: receive buffer
* @retval receive data len
*/
uint16_t usb_winusb_get_rxdata(void *udev, uint8_t *recv_data)
{
uint16_t i_index = 0;
uint16_t tmp_len = 0;
usbd_core_type *pudev = (usbd_core_type *)udev;
winusb_struct_type *p_winusb = (winusb_struct_type *)pudev->class_handler->pdata;
if(p_winusb->g_rx_completed == 0)
{
return 0;
}
p_winusb->g_rx_completed = 0;
tmp_len = p_winusb->g_rxlen;
//for(i_index = 0; i_index < p_winusb->g_rxlen; i_index ++)
//{
// recv_data = p_winusb->g_rx_buff;
//}
usbd_ept_recv(pudev, USBD_WINUSB_BULK_OUT_EPT, p_winusb->g_rx_buff, p_winusb->maxpacket);
return tmp_len;
}开启内存复制,大概速度在8-9MB/S左右。
以上测试结果和官方的测试结果有点出入。总体来说好于官方数据。
做图算应用,MCU的USB带宽确定够吗? 楼主威武,真出了写入的测试 yangxiaor520 发表于 2024-5-14 07:59
做图算应用,MCU的USB带宽确定够吗?
应用领域不一样,256*256的单色图像,USB2.0的速度可以了。
页:
[1]