1. 目的

调试STM32F407支持USB CDC与PC之间的通信;

STM32 USB转串口的驱动, 官方下载地址: STSW-STM32102 - STM32虚拟COM端口驱动程序 - STMicroelectronics

2. 环境
2.1 软件
Win10, STM32CubeIDE Version: 1.6.1 Build: 9958_20210326_1446 (UTC)

2.2 硬件
我采用的是STM32F407 工控板;

3. 调试
3.1 使用STM32Cube生成项目

需要用到的IO口资源:连接了外部8MHz晶振的PH0和PH1。连接到USB插座的PB14和PB15。连接到STLINK仿真器的PA13、PA14。

3.1.1 晶振
Peripherals中需要配置RCC,未焊接外部低速晶振。因此LSE默认disable,使用外部8MHz晶振,因此配置为Crystal/Ceramic。

RCC配置为外部晶振:

3.1.2 仿真/下载
由于使用的是STLINK, 配置debug模式为Serial Wire

3.1.3 USB设备
STM32F407芯片支持USB2.0 Fullspeed。但是usb2.0 high speed需要外接控制器如usb3300。这里的方式是STM32F407的引脚pa11和pa12经过电阻直接连接USB插座。需要配置为usb_device_fullspeed。

配置USB_OTG_FS如下:PC为usb host,而STM32作为usb device。

选好了device_only后,Configuration栏的USB_DEVICE即有效。把USB_DEVICE中,配置Class For FS IP为Communication Device Class(CDC);

坑:

由于购买的工控板Full Speed是Type A, 无法连接PC; High Speed没有外接USB330, 所以没法配置未High Speed用;

所以解决方案是把High Speed USB口配置为Full Speed来用, 具体如下:

(1.) USB Port

(2). Middleware

3.1.4 时钟树配置

STM32F407使用外部的8MHz晶振,Input frequency输入8后,选菜单栏中的clock Configuration -> Resolve Clock Issues即可自动为芯片内部的各个模块配置好时钟频率。这里需要注意,STM32F4内置的usb controller时钟需要48HMz才能正常工作。

在这个页面没有红色字体后,这个页面的配置也就完成了。

3.1.5 生成代码
在Project Manager页面记得把mimimum heap size和mimmum stack size提高。有网友反映这个size低了是会出error的。我把两个size都改大了,分别设为0x1500和0x1000。其他默认,点击OK。

然后点Project -> Generate Code。工程初始化已经完成。

4. 用户代码修改
在main.c的合适区域增加以下代码:

4.1  引用头文件以及参数声明
顾名思义,第一个参数是接受数据,双缓冲数组结构。第二个参数是发送数据。cdc每接收一个包,会刷新接收数据。需要把其当前数据包的长度记录。

#include "usbd_cdc_if.h"

extern uint8_t UserRxBufferFS[2][2048];
extern uint8_t UserTxBufferFS[2048];
 
extern uint32_t nRxLength;         //接收到的数据长度
extern uint8_t uRxBufIndex;         //当前使用的缓冲区索引号
extern uint8_t  uLastRxBufIndex; //上次使用的接收缓冲区索引号
int bSendMark = 0;                 发送数据的标志
4.2 main函数内的参数初始化区域
我想知道上传到电脑的数据是否准确连续。故自行按顺序初始化了发送数组中的每个数值。
  for(i=0;i<APP_TX_DATA_SIZE;i++)
  {
      UserTxBufferFS[i]=i;
  }
4.3 main函数内的死循环

// 每次CDC_Itf_Receive()接收到新数据都会更换缓存,所以发现缓存切换过就是有新的数据。
// 这里必须保证数据处理的速度足够快,否则缓存切换了两次才处理的话,就没法识别有新数据到来了。
if (uLastRxBufIndex != uRxBufIndex)
{
    // --> 指令译码开始。
    for (int i=0; i<nRxLength; i++)
    {
        if (UserRxBufferFS[uLastRxBufIndex][i] == 0x55)    // 0x55, 开始发送数据指令
            bSendMark = 1;
        if (UserRxBufferFS[uLastRxBufIndex][i] == 0xAA)    // 0xAA, 停止发送数据指令
            bSendMark = 0;
    }
    // <-- 指令译码结束。
    uLastRxBufIndex = (uLastRxBufIndex + 1) & 1;
}
 
if (bSendMark)
{
    int32_t k = 0;
    while (CDC_Transmit_FS(UserTxBufferFS, APP_TX_DATA_SIZE) != USBD_OK)
    k++;
}
 
// 处理接收到的数据:解码数据流中的指令。可以改成你自己的数据处理过程。
// 每次CDC_Itf_Receive()接收到新数据都会更换缓存,所以发现缓存切换过就是有新的数据。
// 这里必须保证数据处理的速度足够快,否则缓存切换了两次才处理的话,就没法识别有新数据到来了。
if (uLastRxBufIndex != uRxBufIndex)
{
    // --> 指令译码开始。
    for (int i=0; i<nRxLength; i++)
    {
        if (UserRxBufferFS[uLastRxBufIndex][i] == 0x55)    // 0x55, 开始发送数据指令
            bSendMark = 1;
        if (UserRxBufferFS[uLastRxBufIndex][i] == 0xAA)    // 0xAA, 停止发送数据指令
            bSendMark = 0;
    }
    // <-- 指令译码结束。
    uLastRxBufIndex = (uLastRxBufIndex + 1) & 1;
}
if (bSendMark)
{
    int32_t k = 0;
    while (CDC_Transmit_FS(UserTxBufferFS, APP_TX_DATA_SIZE) != USBD_OK)
    k++;
}
4.4 usbd_cdc_if.c
4.4.1:1维数组重新定义为2维。
uint8_t UserRxBufferFS[2][APP_RX_DATA_SIZE];
4.4.2:定义全局变量
 
uint32_t BuffLength;
uint32_t nRxLength;
uint8_t uRxBufIndex = 0;                     当前使用的缓冲区索引号
uint8_t  uLastRxBufIndex = 0;                 上次使用的接收缓冲区索引号
4.4.3:static int8_t CDC_Init_FS(void)这个函数内:
  USBD_CDC_SetRxBuffer(&hUsbDeviceFS, UserRxBufferFS);
改为:

USBD_CDC_SetRxBuffer(&hUsbDeviceFS, UserRxBufferFS[0]);
4.4.4:CDC_Receive_FS函数

USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
 
  USBD_CDC_ReceivePacket(&hUsbDeviceFS);
  return (USBD_OK);
改为:

//USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
 
    nRxLength = *Len;
     接收到的数据在main()函数中处理
     这里只是简单地切换缓存
    uRxBufIndex++;
    uRxBufIndex &= 0x01;
    USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &UserRxBufferFS[uRxBufIndex][0]);
 
  USBD_CDC_ReceivePacket(&hUsbDeviceFS);
  return (USBD_OK);

5 试验结果
测得发送速度为500KB/s。接收速度为800KB/s。

打开XCOM串口调试助手。

往STM32发送55,STM32接收到0x55后,会把发送数据内的数据上传到电脑。然后对STM32发送0xaa即可停止STM32的发送。

可以看到,数据是0x00-0xff,试验中没看到明显的丢包、以及误码。但仍需进一步验证。

7. 小结
本文记录了基于STM32F4的USB2.0FS数据传输的试验过程。采用了最新的HAL库

参考资料有:

1. http://bbs.21ic.com/icview-811704-1-1.html

STM32F407 USB CDC调试与经验总结相关推荐

  1. stm32f407 usb cdc设备无法启动问题

    最新要做一个项目,要求基于STM32F407实现USB CDC设备,首先想到的就是直接用STM32CUBEMX工具来生成,OK,话不多说,直接上过程: RCC配置: Sys配置 USB_OTG_FS配 ...

  2. am335x usb linux配置,AM335xUSB调试的经验小结.PDF

    AM335x USB 调试的经验小结 Yaoming 硬件调试 • 首先,将USB设备放到PC等设备上以确认该设备本身是否正常. • 可以根据AM335x 的Schematics Check list ...

  3. USB CDC 4G Module 调试问题总结

    USB CDC 4G Module ESP32S2 自定义开发板 SIM7600C1 其他按照github USB CDC 4G Module 使用说明 确保硬件正确SIM卡正常 编译注意做好在4.4 ...

  4. 在进行USB CDC类开发时,无法发送64整数倍的数据(续)

    1 前言 此文延续之前相同文章的话题,是对上篇文章的补充,之所以会有此文,主要是之前发现问题是在STM32F4上,解决方案也是基于CubeF4,但是,当相同问题出现在STM32F0上时,使用之前的代码 ...

  5. STM32F407 USB虚拟双串口

    STM32F407 USB 虚拟双串口 文章目录 STM32F407 USB 虚拟双串口 准备工作 代码修改 端点配置修改 描述符修改 数据处理 准备工作 通过STM32CubeMX生成一份标准的US ...

  6. USB CDC从理论到实践

    本文摘自ST官网的"USB CDC类入门培训".整理的内容是我能够看得懂的,认为比较实用的,记录下来,以便以后查阅,同时也把原文档中的笔误给更正了一下.若要看更详细的可以去ST技术 ...

  7. STM32开发笔记33:解决USB CDC “该设备无法启动”问题

    单片机型号:STM32F401 调试STM32的USB CDC设备已经有好多次了,可以看一下前面写的日志,针对不同的STM32 MCU都进行了调试.原本以为STM32F4会很简单,可处处是坑,已经调到 ...

  8. USB CDC 可变形参

    控制台的三种连接方式: 1.IP网络 2.USB 3.UART 一:介绍USB CDC方式: 1.控制台配置如下: 2.USB Product ID 可以是:0x0000/0x5300/0x0238 ...

  9. Linux下通过CCID协议与USB设备进行交互经验总结

    Linux下通过CCID协议与USB设备进行交互经验总结 1.目标 2. 实现方法 2.1 安装libudev 2.1.1 编译安装 2.1.2 安装提示错误 2.2 编译安装libusb 2.2.1 ...

  10. USB复合设备调试 STM32

    空间 STM32 USB复合设备调试过程, 复合设备一般要用到IAD(接口关联描述符),但是我在网上下载的几个例程都没有用到IAD,最后发现如 果USB复合设备只用到两个接口,即复合的两个功能(MSC ...

最新文章

  1. 跨越十年,我的重要时刻它从未离开过
  2. C语言中side的用法,C语言 side effect和sequence point
  3. VTK+MFC 系列教程 非常强大
  4. Python 递归函数 - Python零基础入门教程
  5. DataGrid中的超级链接列使用注意点
  6. aspnet 后台调用前台js函数
  7. 大数据_Flink_Java版_状态管理(2)_算子状态---Flink工作笔记0061
  8. HTML示例06---水平线
  9. STM32F103mini基础知识归纳
  10. 自学-Linux-老男孩Linux77期-day2
  11. Pspice for TI取消默认打开方式
  12. Python反序列化免杀上线CS:两次编码绕过
  13. python excel表格的导入和excel中插入折线图
  14. Minecraft Mod 开发:4-创造模式物品栏
  15. swoole 协程与go 协程对比
  16. 人民币对美元汇率中间价报6.7854元 下调80个基点
  17. 自建speedtest测速服务器教程,Linux/Windows/群晖
  18. 游戏开发的专业术语整理
  19. php 成语接龙api,再谈Weiphp公众平台开发——1、成语接龙插件
  20. 模型通道剪枝汇总(channel pruning)

热门文章

  1. 一文搞懂深度学习所有工具——Anaconda、CUDA、cuDNN
  2. idea社区版 html,利用IntelliJ IDEA社区版开发servlet
  3. 单词语音音标正则式查询分析JavaScript应用
  4. pdf签名无效解决办法_我花了一整天测试了20+款PDF工具,进来评评谁是MVP
  5. 在【使用QNX Momentics IDE构建的(只读QNX系统)】中搭建SSH方法
  6. 文法规则自顶向下分析
  7. 数电笔记:触发器的基础知识
  8. Music Collector Mac破解版——你身边的音乐收藏专家
  9. FANUC机器人示教器介绍
  10. linux消息队列 性能,消息队列消息总大小的问题