templeton 发表于 2026-1-16 14:37:50

对这个问题,个人比较感兴趣,猜想存在问题的地方可能在三个地方:
1、USB模块工作异常,2、对USB寄存器操作异常,3、芯片工作异常。

1、USB模块是独立的时钟,和主频无关。这个先排除。
2、系统时钟和USB的时钟差异大时,可能会导致读写寄存器不同步,可以考虑一下。
3、芯片工作异常。除了USB模块外,其他未发现异常,这个先排除。

对USB模块操作主要是通过两个函数usb_read_reg()和usb_write_reg()进行的。
BYTE usb_read_reg(BYTE addr)
{
      BYTE dat;
      while (USBADR & 0x80);
      USBADR = addr | 0x80;
      while (USBADR & 0x80);
      dat = USBDAT;
      return dat;
}
usb_read_reg()函数是有时序控制的。
void usb_write_reg(BYTE addr, BYTE dat)
{
      while (USBADR & 0x80);
      USBADR = addr & 0x7f;
      USBDAT = dat;
}
如果是操作时钟不匹配,大概率是usb_write_reg()的原因。USBADR还没有设置好,就设置了USBDAT。
于是在指令之间加入延时测试。
当主时钟为80MHz时,指令之间加一个nop后通信正常。
void usb_write_reg(BYTE addr, BYTE dat)
{
      while (USBADR & 0x80);
      USBADR = addr & 0x7f;
      NOP1();
      USBDAT = dat;
}
当主时钟为120MHz时,需要加多个时钟才能恢复通信正常。
void usb_write_reg(BYTE addr, BYTE dat)
{
      while (USBADR & 0x80);
      NOP5();
      USBADR = addr & 0x7f;
      NOP10();
      USBDAT = dat;
}
通过以上测试,个人认为应该是主频高时,内核对USB模块寄存器操作出现问题。
如果能加入设置寄存器完成判断,应该可以消除这个问题。

health 发表于 2026-1-16 15:32:49

分析的有道理。
遇到类似情况,密切关注。

ercircle 发表于 2026-1-16 15:51:38

templeton 发表于 2026-1-16 14:37
对这个问题,个人比较感兴趣,猜想存在问题的地方可能在三个地方:1、USB模块工作异常,2、对USB寄存器操作 ...

比较倾向于第二点,时钟域配合问题

但是usb_write_reg即便加上while (USBADR & 0x80);也会在120M下识别失败

举个反例:

一个碰巧能在120M下工作的HID例程,而且usb_write_reg未改变:

templeton 发表于 2026-1-16 16:01:30

ercircle 发表于 2026-1-16 15:51
比较倾向于第二点,时钟域配合问题

但是usb_write_reg即便加上while (USBADR & 0x80);也会在120M下识别 ...

usb_write_reg里加while (USBADR & 0x80);是无效的,我也测试过。USBADR中的BUSY是USB正在读取间接寄存器,而这个函数的USBDAT是外部操作的,和BUSY无关。所以我测试时是加延时的。

ercircle 发表于 2026-1-16 16:24:17

templeton 发表于 2026-1-16 16:01
usb_write_reg里加while (USBADR & 0x80);是无效的,我也测试过。USBADR中的BUSY是USB正在读取间接寄存器 ...

分析有道理,这里加了延时确实也会变正常

ercircle 发表于 2026-1-16 17:17:52

read函数也要加,试下这两120MHz HID&CDC:


templeton 发表于 2026-1-17 19:59:11

ercircle 发表于 2026-1-16 17:17
read函数也要加,试下这两120M HID&CDC:

usb_read_reg()函数按照原例程应该是可以的。原例程例在设置完add后,等待dat寄存器准备好后,才能读,这里的while (USBADR & 0x80);是有效的。这时的dat是USB模块准备的,所以可以通过查询USBADR的标志位来确定的。
BYTE usb_read_reg(BYTE addr)
{
        BYTE dat;

        while (USBADR & 0x80);
        USBADR = addr | 0x80;
      while (USBADR & 0x80);
        dat = USBDAT;

        return dat;
}

ercircle 发表于 2026-1-17 20:14:43

templeton 发表于 2026-1-17 19:59
usb_read_reg()函数按照原例程应该是可以的。原例程例在设置完add后,等待dat寄存器准备好后,才能读,这 ...

我这边测试,上面的例程删了read里的NOP改为while会HID识别失败。

templeton 发表于 2026-1-19 08:37:25

测试时加一些延时稳定点,会不会刚设置了USBADR,再去读会有问题,有可能USB模块内部还没有处理好。
USBADR和USBDAT这两个寄存器在设置后都稍微延时一下,感觉会稳妥一些。

神农鼎 发表于 2026-1-22 20:48:20

裴工:
USB-CDC/HID,CPU 可以 120MHz



页: 1 [2]
查看完整版本: STC32G144K246中USB模块和系统时钟的关系