打印
[AT32F405]

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

[复制链接]
4389|8
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
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代码如下:

#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[BUF_SIZE];

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();

/**
  * [url=home.php?mod=space&uid=247401]@brief[/url]  main function.
  * @param  none
  * @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();
        auto  speed = 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 | 只看该作者
写速度能达到多少呢?测试过吗?

使用特权

评论回复
板凳
Ketose|  楼主 | 2024-5-13 10:02 | 只看该作者
gouguoccc 发表于 2024-5-13 08:04
写速度能达到多少呢?测试过吗?

写入速度没有测试。回头测试一下。

使用特权

评论回复
地板
呐咯密密| | 2024-5-13 13:18 | 只看该作者
还不错的测试,实现的效果很好

使用特权

评论回复
5
micoccd| | 2024-5-13 14:30 | 只看该作者
这个速度还可以

使用特权

评论回复
6
Ketose|  楼主 | 2024-5-13 22:56 | 只看该作者
上位机写入测试代码:
// 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();
        auto  speed = 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代码:
/**
  **************************************************************************
  * [url=home.php?mod=space&uid=288409]@file[/url]     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[BUF_SIZE];

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();

/**
  * @brief  main function.
  * @param  none
  * @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里的内存复制过程,代码如下
/**
  * @brief  usb device class rx data process
  * @param  udev: to the structure of usbd_core_type
  * @param  recv_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[i_index] = p_winusb->g_rx_buff[i_index];
//  }

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

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


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


使用特权

评论回复
7
yangxiaor520| | 2024-5-14 07:59 | 只看该作者
做图算应用,MCU的USB带宽确定够吗?

使用特权

评论回复
8
LEDyyds| | 2024-5-14 11:00 | 只看该作者
楼主威武,真出了写入的测试

使用特权

评论回复
9
Ketose|  楼主 | 2024-5-14 12:45 | 只看该作者
yangxiaor520 发表于 2024-5-14 07:59
做图算应用,MCU的USB带宽确定够吗?

应用领域不一样,256*256的单色图像,USB2.0的速度可以了。

使用特权

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

本版积分规则

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

64

主题

3211

帖子

15

粉丝