OpenOCD在ARM硬件JTAG调试中的全面应用指南

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:OpenOCD是一个开源的芯片级调试工具,用于嵌入式系统中的调试,特别是通过JTAG接口进行ARM硬件调试。本资料集合详细介绍了OpenOCD的基础概念、安装与配置、以及如何通过GDB或其他IDE与OpenOCD连接进行程序调试。强调了OpenOCD在处理器内核支持、内核调试、内存映射、中断处理等方面的应用,以及其在自动化固件烧录和新协议支持方面的可扩展性。2019年2月最新版的OpenOCD为ARM JTAG调试提供了全面支持,是开发者的重要资源。 openocd for jtag

1. OpenOCD简介及其开源协议

OpenOCD(Open On-Chip Debugger)是一款开源的软件,旨在为各种芯片和处理器提供调试功能。它广泛应用于嵌入式系统开发和硬件调试领域,是连接软件调试器(如GDB)和目标硬件的桥梁。OpenOCD支持多种通信协议和接口,如JTAG(Joint Test Action Group)和SWD(Serial Wire Debug),并通过与处理器的通信协议直接交互,实现对目标设备的控制和数据交换。

1.1 OpenOCD的起源和发展

OpenOCD最初是为FPGA(现场可编程门阵列)和ASIC(应用特定集成电路)的调试而设计,随着开源社区的贡献和硬件技术的进步,它逐步发展成为一个成熟的调试工具,支持多种处理器架构和调试接口。它的核心优势在于其开源性质,允许开发者自定义和扩展调试功能以满足特定的调试需求。

1.2 开源协议和社区

OpenOCD遵循GNU通用公共许可证(GPL),这意味着用户可以自由地使用、修改和分发源代码。社区在推动OpenOCD发展方面发挥着至关重要的作用,不断有新的特性被贡献到项目中,同时社区也提供了一个平台供开发者交流和解决调试中遇到的问题。

总的来说,OpenOCD作为一款强大的调试工具,其开源性质和活跃的社区是其持续发展和适应新挑战的保证。接下来,我们将深入探讨它所支持的通信协议,例如JTAG和SWD,以及它们在硬件调试中的应用。

2. 通信协议:JTAG和SWD的细节

2.1 JTAG通信协议的原理和应用

2.1.1 JTAG的定义和历史背景

JTAG(Joint Test Action Group)通信协议,又称为IEEE 1149.1标准,是一种广泛应用于集成电路测试的协议。它最初由IEEE标准化,目的在于提供一种简单有效的方式来检测印刷电路板(PCB)上集成电路的焊点和内部逻辑。随着技术的发展,JTAG的应用范围已经扩展到硬件调试领域,成为嵌入式系统开发者不可或缺的工具之一。

JTAG标准在1990年正式发布,并持续得到更新和改进。JTAG利用一组固定数量的引脚作为测试访问端口(TAP),通过这些引脚提供对芯片内部逻辑电路的访问,便于开发者进行设计验证、生产测试以及后续的硬件调试。

2.1.2 JTAG在硬件调试中的作用和优势

JTAG的主要作用是在芯片生产后,对芯片的内部结构和芯片间的互连进行测试。它允许开发者通过一系列预定义的指令,对芯片内部的寄存器进行读写操作,从而实现对芯片功能的检查和调试。例如,可以对处理器的指令寄存器进行操作,执行特定的指令序列来验证CPU的功能。

使用JTAG进行硬件调试的优势在于: - 非侵入性 :JTAG允许在不影响设备正常运行的情况下进行观察和控制,这对于实时系统尤其重要。 - 对内部状态的全面访问 :开发者可以通过JTAG访问处理器内部的寄存器、内存以及特殊功能模块。 - 在线调试 :调试器可以与运行中的系统通信,实时读取系统状态和变量,设置断点和监控点。 - 支持多种调试模式 :如单步执行、断点、数据监视和修改等,极大提高了调试效率。

2.2 SWD通信协议的原理和应用

2.2.1 SWD的定义和特点

SWD(Serial Wire Debug)是一种与JTAG类似的调试通信接口,它被引入到ARM Cortex-M系列处理器中。SWD的主要目的是简化调试接口,减少所需的引脚数目,使其更适合于引脚数量有限的微控制器。

SWD利用两根线(一条数据线和一条时钟线)实现调试功能,相比于JTAG的四线(或五线)配置,SWD的简化设计显著降低了布线的复杂性和成本。同时,SWD保持了与JTAG相似的调试能力和数据传输速率,使得开发人员在保持强大调试功能的同时,获得了更高的灵活性。

2.2.2 SWD与JTAG的对比和选择

当面对SWD和JTAG的选择时,开发人员需要根据项目需求和目标硬件平台来决定使用哪种调试协议。

JTAG的优势在于它的成熟性和通用性,几乎所有的微控制器、处理器和FPGA都支持JTAG接口。然而,对于资源受限的微控制器而言,SWD的优势变得十分明显:

  • 布线需求更少 :JTAG需要至少四根(或五根)引脚,而SWD仅需要两根。
  • 物理接口更简单 :由于引脚数量减少,SWD接口的物理设计更加简洁。
  • 兼容性好 :SWD与JTAG在大多数情况下可以共存,使得原有支持JTAG的系统更容易过渡到SWD。

最终选择哪种协议取决于具体的应用场景。如果开发环境对调试接口的物理空间有严格限制,或者希望减少布线数量以节省成本,SWD可能是更好的选择。而如果目标硬件平台是通用性较强的老式设备,或者对现有JTAG接口有较好的支持,JTAG可能更加适合。

3. ARM硬件调试与JTAG接口的使用

3.1 ARM硬件调试的步骤和技巧

3.1.1 ARM硬件调试的基本步骤

ARM硬件调试通常涉及以下步骤:

  1. 准备工作:确保调试环境已经搭建好,包括调试器、目标硬件板以及开发主机等。
  2. 连接目标硬件:通过JTAG接口将调试器与目标硬件连接起来。
  3. 启动调试器:打开调试软件,如OpenOCD,并开始加载配置文件。
  4. 初始化调试环境:在调试器中初始化环境,比如设置CPU频率、加载程序到目标设备等。
  5. 下载和运行程序:将编译好的程序下载到目标硬件中,并执行。
  6. 断点设置:在需要调试的位置设置断点。
  7. 运行和观察:运行程序并观察程序运行情况,检查断点是否被触发。
  8. 调试和修改:根据观察到的情况进行调试,比如查看寄存器、内存、变量的值,并进行必要的修改。
  9. 问题定位和解决:分析问题并实施解决方案,直至程序按预期运行。
  10. 调试结束:当调试完成,保存所有必要的日志、截图或配置信息,关闭调试器和目标硬件设备。

3.1.2 硬件调试中常见的问题和解决方法

在硬件调试过程中,常见的问题包括:

  • 目标设备未响应: 可能是因为连接问题、电源问题或硬件故障。检查JTAG线连接是否正确,确保电源供应稳定,并检查目标硬件是否损坏。
  • 调试器无法连接到目标设备: 确保调试器和目标设备支持相同的通信协议,且配置文件正确无误。
  • 程序无法下载或执行: 检查目标设备是否有足够的内存空间,或者是否存在权限限制。
  • 断点无法触发: 确保断点设置在正确的地址,并且没有被其他设置所覆盖。
  • 观察到的数据不符合预期: 可能是因为程序逻辑错误或硬件问题,需要结合代码逻辑和硬件状态进行综合分析。

对于上述问题,一般解决方法包括:

  • 重试连接: 多次尝试连接设备,确保连接稳固。
  • 检查配置: 仔细检查调试器配置文件,确保所有设置正确无误。
  • 更新固件: 如果目标设备固件过时或损坏,尝试更新固件。
  • 日志分析: 利用调试器提供的日志功能,记录调试过程中的详细信息,帮助定位问题。
  • 查阅文档: 参考相关硬件文档或调试工具的帮助文档,可能会提供问题的解决线索。

3.2 JTAG接口的使用和配置

3.2.1 JTAG接口的连接和配置

JTAG接口的连接通常包括以下几个步骤:

  1. 确定JTAG接口的引脚定义,这通常可以在硬件的官方文档中找到。
  2. 使用标准的20针连接器将调试器和目标设备连接起来,确保所有引脚正确对齐并固定。
  3. 在调试器软件(例如OpenOCD)中指定JTAG设备的连接设置,这包括设备的JTAG链路配置和可能的时钟频率设置。

配置JTAG接口时需要注意:

  • 设备兼容性: 调试器必须与目标设备的JTAG接口兼容。
  • 电压级别: 确保调试器的输出电压与目标设备的要求相匹配。
  • 连接器类型: 通常使用14针或20针的连接器,选择正确的类型和配置。

3.2.2 JTAG接口在硬件调试中的应用实例

下面是一个JTAG接口在硬件调试中的应用实例,该实例中我们将使用OpenOCD来调试一个基于ARM Cortex-M3的微控制器。

准备工作:

  • 安装OpenOCD软件。
  • 配置好目标硬件和开发主机之间的连接。
  • 确保目标硬件板已经连接到主机并且电源供应正常。

调试步骤:

  1. 启动OpenOCD: 使用带有特定配置文件的OpenOCD命令启动调试会话。 bash openocd -f interface/stlink-v2.cfg -f target/stm32f1x_stlink.cfg 这里 -f 选项指定了配置文件,用于指示OpenOCD如何与ST-LINK v2接口通信,并设置目标设备为STM32F1系列。

  2. 验证连接: 一旦OpenOCD启动,它会连接到调试器并输出状态信息。我们可以使用以下命令来验证连接状态。 ```bash

    adapter_khz 1000 Info : clock speed 1000 kHz jtag_khz 1000 Info : JTAG speed set to 1000 kHz targets TargetName Current fSys fTap fInf fXtal


STM32F1x.cpu 0x08000140 7200000 7200000 7200000 8000000 ``` 这些命令和输出确保了调试器已经正确地连接到了目标设备,并且获取了有关目标的信息。

  1. 下载程序: 使用OpenOCD命令行工具下载编译好的程序到目标设备中。 ```bash

    program firmware.elf `` 这里的 firmware.elf`是编译后的固件文件。

  2. 设置断点并运行: 设置一个断点并运行程序,例如在 main() 函数的入口处。 ```bash

    bp 0x08000140 resume `` 现在程序将在 main()`函数开始处暂停,等待进一步的调试指令。

通过这个简单的实例,我们可以看到JTAG接口在硬件调试中的实际应用。硬件调试中JTAG提供了强大的工具来测试和验证嵌入式系统的功能,是开发流程中不可或缺的一环。

4. OpenOCD的安装与配置及集成使用

4.1 OpenOCD的安装和配置步骤

4.1.1 OpenOCD的安装环境和依赖

OpenOCD(Open On-Chip Debugger)是一个开源项目,用于调试各种微控制器和系统芯片。安装OpenOCD之前,需要准备适合的开发环境,一般情况下,你需要在Unix-like系统中进行安装,如Linux或macOS。对于Windows用户,可以使用Cygwin或者Windows Subsystem for Linux (WSL) 来创建一个类Unix环境。

在安装OpenOCD前,还需要安装一些依赖包,包括但不限于:

  • libusb-1.0-0-dev: USB通信库
  • libtool: 工具链自动化库
  • telnet: 远程登录协议客户端
  • libncurses5-dev: 用于构建和运行使用ncurses库的程序
  • libhidapi-dev: USB和HID设备库

你也可以通过包管理器来安装这些依赖,例如在Ubuntu或Debian系统中,你可以使用以下命令:

sudo apt-get install libusb-1.0-0-dev libtool telnet libncurses5-dev libhidapi-dev

4.1.2 OpenOCD的配置文件和参数设置

OpenOCD通过配置文件来定义目标设备的接口、端点、调试器配置等。配置文件通常位于 /usr/share/openocd/scripts/ 目录下,或者在你自己创建的目录中。

一个基本的配置文件,例如针对一个特定的ARM Cortex-M系列微控制器,可能包括如下内容:

# 端口和连接配置
interface   cmsis-dap
adapter_khz 1000

# 目标设备配置
transport select swd
source [find target/stm32f4x.cfg]

# 使能调试器日志输出
log_output openocd.log

在该配置文件中:

  • interface 指定了所使用的调试器硬件接口类型, cmsis-dap 是CMSIS-DAP协议,它支持通过USB进行通信。
  • adapter_khz 设置了连接的频率(以kHz为单位)。
  • transport select 指定了传输层协议,SWD(Serial Wire Debug)是一种常用的接口类型。
  • source 命令用于包含额外的配置文件,这些文件定义了特定的微控制器配置。
  • log_output 可用于将日志输出到指定的文件,有助于调试配置错误。

安装OpenOCD的步骤可能如下:

# 下载OpenOCD源码包
wget http://sourceforge.net/projects/openocd/files/openocd/0.10.0/openocd-0.10.0.tar.gz
# 解压源码包
tar -xzf openocd-0.10.0.tar.gz
cd openocd-0.10.0
# 编译安装
./configure
make
sudo make install

安装完成后,你可以通过 openocd -f your_configuration_file.cfg 来启动OpenOCD,并指定你的配置文件。

4.2 OpenOCD与GDB或IDE的集成使用

4.2.1 OpenOCD与GDB的集成使用

OpenOCD与GDB集成使用时,OpenOCD主要负责与目标硬件进行通信,而GDB则负责执行实际的调试操作。集成步骤大致如下:

  1. 首先启动OpenOCD服务并连接到目标硬件:
openocd -f path/to/openocd.cfg
  1. 在另外一个终端中启动GDB,并指定你的程序的ELF文件:
gdb path/to/your_program.elf
  1. 在GDB中连接到OpenOCD,使用以下命令:
target extended-remote :3333

这里 3333 是默认的OpenOCD端口号,它用于与GDB通信。

  1. 一旦连接,你可以使用GDB的命令开始调试,例如设置断点、单步执行、查看变量等。
break main
continue
next
print var_name

这样,GDB通过OpenOCD与目标硬件进行通信,实现了程序的调试。

4.2.2 OpenOCD与IDE的集成使用

OpenOCD也可以与集成开发环境(IDE)如Eclipse、Keil等集成,提供图形化的界面进行调试。以Eclipse为例,集成步骤如下:

  1. 安装Eclipse CDT插件,用于C/C++开发。

  2. 安装Eclipse的GDB插件,或在Eclipse中配置GDB作为调试器。

  3. 在Eclipse中创建一个调试配置,指定使用GDB,并配置GDB连接到OpenOCD。

  4. 启动OpenOCD服务,并确保它侦听在预期端口。

  5. 在Eclipse中开始调试,设置断点,运行程序。

通过以上步骤,你可以利用Eclipse的可视化界面进行源代码级别的调试。

在这一章节中,我们详细介绍了OpenOCD的安装和配置,以及它与GDB和IDE的集成使用方法。理解这些内容对于在嵌入式开发中实现有效的调试至关重要。在下一章节中,我们将探讨OpenOCD的优势、灵活性和可扩展性。

5. OpenOCD的优势、灵活性和可扩展性

OpenOCD(Open On-Chip Debugger)是一个开源的调试软件,它支持多种类型的处理器核心,同时具有很高的灵活性和可扩展性。本章将深入探讨OpenOCD在不同处理器核心支持、JTAG在裸机编程和固件开发中的应用、以及OpenOCD的灵活性和可扩展性,并提供自定义脚本和命令的编写指导。

5.1 OpenOCD对ARM处理器内核系列的支持

OpenOCD广泛应用于ARM处理器的调试,它支持ARM的多个核心系列,包括Cortex-A、Cortex-R和Cortex-M。每一系列处理器都有其特定的应用场景和优势。

5.1.1 Cortex-A系列的支持和应用

Cortex-A系列是针对高计算需求的高性能应用设计的处理器核心,广泛应用于智能手机、平板电脑以及多媒体设备。OpenOCD通过其丰富的接口和协议支持,可以用于调试这些设备上的操作系统、应用程序以及固件。

示例命令如下:

openocd -f /usr/share/openocd/scripts/interface/jlink.cfg -f /usr/share/openocd/scripts/target/cortex-a9_1x.cfg

5.1.2 Cortex-R系列的支持和应用

Cortex-R系列专为实时应用而设计,它能够提供极低的延迟和高效的处理能力,适用于汽车、工业和网络等领域。OpenOCD提供了这些领域的实时调试功能,使得开发者能够有效地对实时应用程序进行调试。

示例命令如下:

openocd -f /usr/share/openocd/scripts/interface/jtag_swd.cfg -f /usr/share/openocd/scripts/target/cortex-r5.cfg

5.1.3 Cortex-M系列的支持和应用

Cortex-M系列针对成本和功耗敏感的应用,如物联网(IoT)设备、消费电子产品等。OpenOCD提供了广泛的支持,特别是在低成本的调试解决方案中非常流行。

示例命令如下:

openocd -f /usr/share/openocd/scripts/interface/stlink-v2.cfg -f /usr/share/openocd/scripts/target/stm32f1x_stlink.cfg

5.2 JTAG在裸机编程和固件开发中的优势

JTAG作为一种硬件调试技术,其在裸机编程和固件开发中表现出了显著的优势,这包括了对芯片内部资源的完全控制能力、方便进行在线编程和调试、以及实时监控和分析芯片的运行状态等。

5.2.1 裸机编程中的JTAG应用和优势

在裸机编程中,开发者直接与硬件交互,而JTAG提供了一种直接访问处理器内部资源的方式。例如,它可以用来下载代码到片上RAM中执行,这对于测试或演示新功能特别有用。

5.2.2 固件开发中的JTAG应用和优势

固件开发过程中,JTAG可以实现对嵌入式设备的非侵入式调试。开发者可以监控和修改处理器的寄存器、内存以及其他内部状态,同时不需要对目标设备的软件环境做任何修改。

5.3 OpenOCD的灵活性和可扩展性

OpenOCD之所以受到众多开发者的青睐,很大程度上归功于它的灵活性和可扩展性。它能够适应各种开发环境和需求,用户可以轻松地添加新的调试器接口、目标芯片配置,甚至是开发特定的脚本和命令。

5.3.1 OpenOCD的灵活性和应用场景

OpenOCD可以与各种类型的调试器硬件接口协同工作,包括但不限于JTAG、SWD和SWV。它可以在不同的操作系统上运行,并且可以与多种开发工具如GDB、Eclipse等集成。

5.3.2 OpenOCD的可扩展性研究和发展方向

随着新的硬件和新的调试需求不断涌现,OpenOCD社区持续研究和开发新的功能。例如,对于ARMv8-M架构的支持,和提高调试效率的改进等。

5.4 自定义脚本和命令的编写

OpenOCD的一个强大功能是支持自定义脚本和命令,这使得开发者可以根据自己的需要扩展OpenOCD的功能。

5.4.1 OpenOCD脚本的基本语法和结构

OpenOCD脚本语言基于Tcl语言,具有简单的语法结构,易于编写和理解。脚本一般以 .cfg 作为文件扩展名,并且可以通过 source 命令在其他脚本中被引用。

5.4.2 OpenOCD自定义命令的编写和应用实例

自定义命令可以用于执行一系列的操作,从简单的状态检查到复杂的调试任务。下面是一个简单的自定义命令示例,该命令用于检查处理器是否停止在复位状态。

proc check_reset_state {} {
    set state [target halted]
    if {![string match "*Reset*" $state]} {
        puts "Processor is not halted in reset state!"
    } else {
        puts "Processor is halted in reset state."
    }
}

在使用自定义命令前,需要在OpenOCD配置文件中添加对该命令文件的引用,如下所示:

source reset_check.tcl

在启动OpenOCD后,可以使用 reset_check 命令来执行这个自定义的检查过程。

OpenOCD通过其对不同处理器的支持、在裸机编程和固件开发中的应用优势,以及其灵活性和可扩展性,使得它成为嵌入式系统开发和调试不可或缺的工具。自定义脚本和命令的编写能力又为开发者提供了一种强大的方式来定制和优化自己的调试工作流,进一步提高了调试工作的效率和效果。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:OpenOCD是一个开源的芯片级调试工具,用于嵌入式系统中的调试,特别是通过JTAG接口进行ARM硬件调试。本资料集合详细介绍了OpenOCD的基础概念、安装与配置、以及如何通过GDB或其他IDE与OpenOCD连接进行程序调试。强调了OpenOCD在处理器内核支持、内核调试、内存映射、中断处理等方面的应用,以及其在自动化固件烧录和新协议支持方面的可扩展性。2019年2月最新版的OpenOCD为ARM JTAG调试提供了全面支持,是开发者的重要资源。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

内容概要:本文档介绍了Intel oneAPI工具集及其行业倡议,旨在提供跨架构编程解决方案,支持加速计算并打破专有锁定。oneAPI允许开发者选择最佳硬件加速技术,实现跨CPU、GPU、FPGA及其他加速器的性能优化。它兼容多种编程语言和模型(如C++、Python、SYCL、OpenMP等),并通过开放标准确保未来兼容性和代码重用。文档详细描述了oneAPI工具包的功能,包括渲染、高性能计算(HPC)、物联网(IoT)、AI分析等领域的应用。此外,还介绍了DPC++(数据并行C++)编程语言及其在不同硬件架构上的执行方式,以及Intel提供的各种优化库和分析工具,如Intel MKL、IPP、VTune Profiler等。最后,通过实际案例展示了oneAPI在医疗成像和超声产品中的成功应用。 适合人群:软件开发人员、硬件工程师、系统架构师、OEM/ODM厂商、ISV合作伙伴,特别是那些需要在多种硬件平台上进行高效编程和性能优化的专业人士。 使用场景及目标:①为跨架构编程提供统一的编程模型,简化多硬件平台的应用开发;②利用开放标准和工具集,提高代码可移植性和重用性;③通过优化编译器和技术库,提升应用程序的性能表现;④借助分析和调试工具,快速识别并解决性能瓶颈。 其他说明:Intel oneAPI工具集不仅支持现有编程语言和模型,还提供了强大的中间件和框架支持,适用于多样化的应用负载需求。开发者可以通过Intel DevCloud获取实际操作经验,同时利用DPC++兼容性工具将现有CUDA代码迁移到SYCL环境。此外,文档还提供了详细的性能优化指南和未来产品路线图,帮助用户更好地规划技术演进路径。
“班级网站设计源代码”项目是网页设计初学者及有一定基础的设计师的理想学习资源。它提供了完整的源代码,涵盖构建可运行班级网站所需的所有文件。网页设计包含前端开发、后端开发和用户体验设计等多个方面,而这个项目能帮助你深入理解这些技术的实际应用。 首先,HTML是网页的基础,它通过标签定义网页的结构,如标题、段落、图片和链接等。在这个项目中,你可以清晰地看到如何利用HTML搭建网页的框架。其次,CSS用于控制网页的样式和布局,赋予网页视觉美感。通过设置颜色、字体、布局以及响应式设计,CSS确保网站能在不同设备上良好显示。项目中的源代码展示了如何运用CSS实现多样化的样式效果。 JavaScript则是实现网页动态功能的关键,它能够处理用户交互、数据操作和动画效果。在这个班级网站中,JavaScript代码可能用于实现按钮点击事件、表单验证或页面动态更新等功能。此外,响应式设计是现代网页设计的重要组成部分。借助媒体查询和流式布局,该班级网站能够自动适应手机、平板和桌面电脑等不同设备的屏幕尺寸。 为了提高开发效率,现代网页设计常常会引入前端框架和库,如Bootstrap或Vue.js。这些工具提供了一套预设的样式和组件,简化了网页的构建过程。虽然具体是否使用了这些框架需要查看源代码,但了解它们的工作原理对于提升网页设计能力至关重要。 如果班级网站包含用户登录、留言等功能,那么后端技术(如PHP、Node.js或Python)和数据库(如MySQL或MongoDB)也会被涉及。这部分代码主要负责处理数据的提交、验证和存储,以及与服务器的通信。 用户体验(UX)和界面设计也是网页设计的重要方面。一个优秀的网站不仅要有美观的外观,还要具备良好的易用性。通过观察和分析这个班级网站的布局和交互设计,你可以学习如何提升用户体验,例如如何设计清晰的导航、易读的信息和直观的操作流程。 通过深入研究“
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值