找回密码
 立即注册
楼主: 神农鼎

视频教学:【USB 原理及实战,16课时】,大学标准课程,有配套书籍

 火.. [复制链接]

14

主题

77

回帖

1152

积分

金牌会员

积分
1152
发表于 2026-8-12 11:57:21 | 显示全部楼层
感谢分享, 在学习过程中发现PDF中的setup阶段示例是有错误的
截图202608121156562387.jpg
应该是置1清零吧?
STC32G配置包:https://gitee.com/main.c/SxPackages.STC32G
STC8配置包:https://gitee.com/main.c/SxPackages.STC8
回复

使用道具 举报 送花

已绑定手机

872

主题

1万

回帖

2万

积分

管理员

积分
25428
 楼主| 发表于 2026-8-12 15:31:17 | 显示全部楼层
截图202608121531135899.jpg
回复

使用道具 举报 送花

已绑定手机

872

主题

1万

回帖

2万

积分

管理员

积分
25428
 楼主| 发表于 2026-8-12 15:31:32 | 显示全部楼层

我已经获取了CSR0寄存器的详细定义,和论坛帖子的内容。让我理解用户的需求。

用户提供的代码是 usb_setup() 函数,并通过 OCR 展示了代码内容,同时给出了一个论坛链接(USB教学视频帖子)。用户的问题核心是理解这个 usb_setup() 函数——它是对照 USB 教学视频中对着协议和代码一行一行讲解的内容。

结合CSR0寄存器的定义,我可以分析这段代码的逻辑是否准确、位操作是否正确。让我仔细核对代码与寄存器的关系。

让我分析用户提供的代码:

void usb_setup()
{
    BYTE csr;                          //csr 寄存器变量
    usb_write_reg(INDEX, 0);           //选择端点 0
    csr = usb_read_reg(CSR0);          //读取 USB 端点 0 控制状态寄存器
    if (csr & STSTL)                   //如果 STALL 信号发送完成
    {
        usb_write_reg(CSR0, csr & ~SDSTL);  //未接收到错误条件,SDSTL 清零
        Ep0State.bState = EPSTATE_IDLE;      //端点 0 设置 IDLE 状态
    }
    if (csr & SUEND)                   //如果 SETUP 阶段结束
    {
        usb_write_reg(CSR0, csr & ~SSUEND);  //清零 SSUEND
    }
}

让我核对代码逻辑与寄存器定义的一致性:

根据CSR0寄存器定义:

  • STSTL(Sent Stall,B2位):STALL信号发送完成标志。发送完成STALL信号后,硬件将该位置"1"。该位必须用软件清"0"。
  • SDSTL(Send Stall,B5位):当接收到错误的条件或者不支持的请求时,可以向此位写"1"来结束当前的数据传输。当STALL信号被发送后,硬件自动将此位清"0"。
  • SUEND(Setup End,B4位):SETUP安装包结束标志,只读位。
  • SSUEND(Serviced Setup End,B7位):SETUP结束事件处理完成标志。当处理完成SETUP结束事件(SUEND)后,软件需要设置SSUEND标志位,硬件检测到SSUEND被写入"1"时自动将SUEND位清"0"。

现在核对代码逻辑:

代码第一段:

if (csr & STSTL)  // STALL信号发送完成
{
    usb_write_reg(CSR0, csr & ~SDSTL);  // 清除 SDSTL
    Ep0State.bState = EPSTATE_IDLE;
}

这里有个疑问:当 STSTL 标志被设置(STALL发送完成),代码写入 csr & ~SDSTL。但根据寄存器定义,STALL 发送完成后需要清除的是 STSTL 位("该位必须用软件清'0'"),而代码中清除的是 SDSTL 位。

不过在USB控制器设计中,写"1"到某些位表示"服务"该事件。实际上在代码中向CSR0写入 csr & ~SDSTL 时,由于CSR0的某些位是"写1清零"或"写1触发",需要仔细分析。让我思考一下。

实际上,很多USB控制器的CSR0寄存器是对某些位采用"读-修改-写"或者"写1清除服务标志"的方式。用户提供的代码中,当检测到STSTL(STALL发送完成)时,它清除SDSTL位。但这似乎与手册不完全一致——手册说STALL发送完成后应清除STSTL位。

不过,用户给出的代码可能来自官方例程(对照USB教学视频)。代码中的注释可能不完全是精确的寄存器行为描述。我应该指出代码与实际寄存器定义需要核对的地方。

让我把分析整理清楚,同时结合论坛帖子内容(USB教学视频、STC8H8K64U和STC32G12K128的USB演示程序)。

让我再看一下STC8H手册中关于CSR0的写操作说明,确认对CSR0写入时的行为。我已经有了足够的信息。让我整理回答。

我应该指出:

  1. 这段 usb_setup() 是USB设备枚举/控制传输处理中用于处理端点0状态机的重要函数。
  2. 代码中的位操作存在需要核对的地方——特别是关于清除STALL标志的位选择。
  3. 论坛帖子对应的是STC官方的USB原理及实战教学视频,这段代码很可能是其中讲解的内容。

让我补充查询一下USB控制器关于端点0中断使能和状态处理的官方例程描述,以更准确说明。

不过我已经有充分的手册依据来分析代码。让我组织回答。

需要说明的是,手册中关于CSR0写操作的机制是"写1触发/服务"。对于CSR0,向某些位写1会触发相应动作。代码中使用 csr & ~SDSTL 的方式,实际上是读取后再做位运算写回。

让我理清:

  • csr & ~SDSTL 表示保留所有位但清除SDSTL位(置0)。
  • STALL发送完成后,需要处理的是:清除STSTL(因为手册说STSTL必须软件清0)。

但代码清除的是SDSTL。这里我需要谨慎分析。在代码上下文中,csr 是刚读回来的值。当STSTL被置1时,代码准备处理STALL完成事件。写入 csr & ~SDSTL 会把SDSTL清0。

实际上,在很多USB设备端点0处理中,当一个STALL被发送后,后续如果希望恢复端点(比如处理完错误或重新进入IDLE状态),需要清除STALL相关标志。但手册明确说 STALL 发送完成后要清除的是 STSTL。

我认为这里代码可能存在笔误,或者该代码来自特定库的实现。我应该基于手册指出:手册规定 STALL 发送完成后应将 STSTL 位清"0"(写0),而示例代码中写的是清除 ~SDSTL。

不过,我要注意代码中实际写入的寄存器值。CSR0 的一些位是写1触发。让我谨慎地描述:代码的意图是处理STALL完成后的状态清理,但根据手册,STALL发送完成后应清除STSTL位。

让我给出平衡、基于手册的严谨回答,同时说明这段代码出自官方USB教学视频。

我要注意帮助用户,不要误导。我会说明:

  1. 函数作用
  2. 逐段逻辑分析
  3. 对照CSR0寄存器定义指出需要核对的地方

让我组织最终回答。我已有足够信息,不需要再查询了。

考虑到用户只是提供了代码和帖子,没有明确询问具体问题,我应该主动分析这段代码并提供解读,同时指出其与手册的对应关系。我已经仔细查阅了 STC8H / STC32G 手册中关于 USB 端点0 控制状态寄存器(CSR0) 的完整定义,以及您所附论坛帖子(STC 官方「USB 原理及实战,16课时」教学视频帖)。下面针对您贴出的这段 usb_setup() 代码做逐段解读,并逐位对照寄存器定义帮你核对逻辑。


一、这段代码是什么

usb_setup() 是 USB 设备端点0(控制端点)状态机的核心处理函数之一。端点0 承担所有的控制传输(SETUP 包收发)。该函数在 USB 中断里被调用,用于响应硬件上报给 CSR0 的几个关键事件,也是视频中「对着协议和代码一行一行讲」的典型片段。


二、CSR0 各位定义(据 STC8H / STC32G 手册)

位 符号 含义
B7 SSUEND SETUP 结束事件处理完成标志,软件写1后硬件自动清 SUEND
B6 SOPRDY OPRDY 事件处理完成标志
B5 SDSTL Send Stall,写1结束当前传输,STALL 发完后硬件自动清0
B4 SUEND Setup End,控制传输提前结束时硬件置1(只读),SSUEND 写1后清0
B3 DATEND Data End,数据结束标志
B2 STSTL Sent Stall,STALL 发送完成标志,必须由软件清0
B1 IPRDY IN 数据包准备完成
B0 OPRDY OUT 数据包准备完成

手册明确:「当需要获取/设置此信息时,首先必须使用 INDEX 来选择目标端点 0」——这正是代码第一行 usb_write_reg(INDEX, 0) 的原因。


三、逐段逻辑解读

① 选择端点0 + 读取 CSR0

usb_write_reg(INDEX, 0);   // 用 INDEX 选中端点 0
csr = usb_read_reg(CSR0);  // 读回当前 CSR0 状态

符合手册要求(操作 CSR0 前必须先选 INDEX)。

② STALL 处理

if (csr & STSTL)   // 硬件报告“STALL 已发送完成”
{
    usb_write_reg(CSR0, csr & ~SDSTL); // 对 CSR0 作读-改-写
    Ep0State.bState = EPSTATE_IDLE;    // 端点回到空闲
}
  • STSTL 是 STALL 发送完成标志(B2),一旦硬件把 STALL 发送出去就会置1,且手册强调该位必须用软件清0。
  • 代码在检测到该位后把端点0状态机切回 IDLE,让端点准备好接收下一个 SETUP——这是标准做法,逻辑方向正确。

③ SETUP 阶段结束处理

if (csr & SUEND)   // SETUP 阶段已结束(控制传输提前结束时由硬件置1)
{
    usb_write_reg(CSR0, csr & ~SSUEND); // 通知硬件“已服务完 SETUP 结束事件”
}
  • SUEND(Setup End,B4)为只读硬件标志;当一次控制传输在软件写 DATEND 之前就结束时由硬件置1。
  • 处理它的正确方式是写 SSUEND(B7) =1,硬件检测到后会自动清 SUEND。代码中 csr & ~SSUEND 把 SSUEND 置1(读回值该位为0,取反后写1),SR 符合手册机制。

四、需要特别核对的一处(重点/红色下划线行)

对照手册定义,STALL 发送完成后应当清除的是 STSTL 位(B2),手册原文为:

STSTL(Sent Stall):发送完成 STALL 信号后,硬件将该位置"1"。该位必须用软件清"0"。

而示例代码第二段写的是 csr & ~SDSTL(清除的是 B5 的 SDSTL)。

请注意 SDSTL(Send Stall)的含义是「软件写1去发起一个 STALL」,硬件发送完毕后会自动把它清0,通常不需要软件去清它。

所以这里红色下划线标注的那行 csr & ~SDSTL,从寄存器语义上更可能应为 csr & ~STSTL(清除 STALL 已发送完成标志)。当然,具体以您手上的官方例程包(STC8H8K64U / STC32G12K128 的 USB 演示程序,见帖子回复 3/6)为准——不同版本的库实现细节略有差异,建议对照您实际使用的例程再确认一遍这一位,避免「STALL 完成标志未被清掉、端点卡在 STALL 状态」的隐患。


五、信息来源说明

  • CSR0 寄存器位定义及写机制(SSUEND/SDSTL/SUEND/DATEND/STSTL/IPRDY/OPRDY):STC8H 系列手册「28 USB 2.0-FS 通用串行总线」、STC32G 系列手册「28 USB 2.0-FS 通用串行总线」(两手册该节内容一致)。
  • 所附链接为 STC 官方《USB 原理及实战,16课时》教学视频帖,回复中提到的 STC8H8K64U / STC32G12K128 的 USB 演示程序包(含该端点0驱动),可从 www.STCAI.com 或 STC-ISP 辅助开发工具包中获取。

如果您希望,我可以:

  1. 基于官方例程,把这段 usb_setup() 连同 SETUP 包解析 + 控制传输状态机(IDLE → IN/OUT → STATUS)完整梳理成一张流程图;
  2. 或给出一个针对 STC8H8K64U / STC32G12K128 的、已修正 STALL 标志清理的端点0 处理示例代码。

需要我继续哪一部分?


🔍 搜索 "https://www.stcaimcu.com/thread-4526-1-1.html"

📌 相关论坛讨论

  1. 今天开始学习STC-USB-CDC

⏱️ 查找用时 7.9s | 总回答用时 31.9s

回复

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2026-11-7 10:39 , Processed in 0.068610 second(s), 52 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表