为硬件调试器实现 µVision2 接口 DLL

本文档详细介绍了如何为μVision2开发硬件调试器接口DLL,包括AGDI接口、内存访问、断点管理、闪存编程等功能。开发者需要了解C/C++编程和MSVisual-C++6.00编程环境,以实现与硬件的连接、目标设置、调试命令处理等。此外,还提供了示例代码和步骤,帮助开发者实现目标驱动程序,包括设置远程调试、内存接口、执行控制和闪存编程等。
摘要由CSDN通过智能技术生成

本应用笔记告诉您如何为用户提供的硬件调试器编写 µVision2 接口 DLL。本文件、随附手册和软件中的信息版权所有 © Keil Software, Inc 和 Keil Elektronik GmbH。
版权所有。

前言

µVision2 调试器支持与监视器或仿真器等硬件调试器的直接接口。该接口是通过称为 AGDI 的高级通用调试器接口完成的。 AGDI 接口独立于控制器架构,灵活、易于实现并且只引入了最小的开销。它执行所有基本调试器功能的接口,允许复杂的断点,并且可以使用仿真器或目标特定命令、对话框或显示页面进行扩展,其显示方式与 µVision2 对话框相同。

Flash 编程接口还将目标 Flash 编程集成到 µVision2 IDE 中。为了使用此功能,仿真器必须支持目标设备的闪存编程 - 基于闪存的 cpu 或外部连接的闪存。要使用目标闪存编程,需要 µVision2 版本 V2.34 或更高版本。

为了简化目标驱动程序的开发,SampTarg 项目中提供了 AGDI 接口和配置框架。 SampTarg 是“Sample Target Driver”的同义词。它是一个准备好运行的驱动程序,具有远程设置和作为虚拟对象提供的所有 AGDI 接口功能。该驱动程序由 Visual-C++ (6.0) 项目文件和以下源文件组成:

        文件                                描述

        SampTarg.cpp,h         主文件,AppWizard 创建。提供目标设置和启动代码

        SetupT.cpp,h         调试设置对话框的代码示例

        SetupFD.cpp,h         闪存下载设置对话框的代码示例

        AGDI.H         AGDI 功能的原型(很少修改)

        BOM.H         各种原型和定义(不要修改!)

        ComTyp.H         一些类型和其他定义(不要修改!)

        Collect.h         本地驱动程序定义,供目标驱动程序程序员使用。

        TestDlg.cpp,h         无模式扩展对话框的模型。

为了开发目标驱动程序,需要有关 C/C++ 编程和 MS Visual-C++ 6.00 编程环境的知识。

如何使用示例目标驱动程序

为了使用示例目标驱动程序,您必须执行以下步骤:

        在您的机器上安装 µVision2 和 C51 编译器。

        创建一个文件夹,例如 D:\Src32\Target\

        将文件 SampTarg.zip 解压缩到该文件夹​​中。确保选中“使用文件夹名称”复选框,因为 SampTarg 使用了一些子文件夹。

        将以下行添加到文件 TOOLS.INI[C51] 部分:       

        注意:如果 TDRV0 已在使用中,则使用下一个空闲数字,例如 TDRV1。

        启动 Visual-C,选择“SampTarg.dsw”项目文件。

        选择“Build – Set active configuration”,选择 SampTarg Win32 Debug 配置。

        选择“Build – Rebuild All”来创建驱动程序。

        选择“项目 - 设置”。单击“调试”选项卡。浏览“调试会话的可执行文件”。您需要选择文件 Uv2.Exe。它通常位于 C:\Keil\Uv2 中,但这取决于您安装 µVision2 的位置。之后,关闭对话框。

        按 F5 键运行 µVision2。选择“Project – Open Project”,弹出选择项目对话框。选择“Measure.uv2”项目。它可以在文件夹中正常找到 - C:\Keil\C51\ExamplesMeasure。选择“重建所有目标文件”来构建项目。

        选择“目标选项 - 调试”。从组合框中,选择“Sample 8051 Target Driver”,这是我们的示例驱动程序。确保选中“使用:”单选按钮。如果一切正常,则对话框应如下所示:

 

        关闭对话框。

        选择“调试 - 启动/停止调试会话”。这将启动 µVision2 调试器。它初始化并加载我们的 SampTarg.DLL。在 µVision2 的文件选项卡中单击文件“Measure.c”。滚动到“main()”。您会注意到窗口左侧的浅灰色和深灰色区域,深灰色区域标识带有可执行代码的行。打开反汇编窗口(查看 - 反汇编窗口)。它显示了 Measure 应用程序的反汇编指令。

        打开内存窗口:从菜单中选择“查看 - 内存窗口”。在内存窗口的地址输入字段中输入“C:0x0000”。您应该看到从代码地址 0x0000 开始的代码内存字节。

请注意,示例驱动程序包含内存接口、寄存器接口和断点管理的代码。 Go 和 Step 的代码只是提供了虚拟程序,因此您无法开始执行用户程序。

调试驱动程序:所需步骤

为了将 SampTarg 驱动程序连接到您的硬件,您应该执行以下步骤:

        设置您的目标硬件

        编写代码以实现目标驱动程序和您的硬件之间的连接。您可以使用串行端口或任何其他资源。将文件添加到 SampTarg 项目。

        将您的驱动程序代码连接到 AGDI.CPP 中包含的相应函数。在 AGDI.CPP 中搜索以下注释:

        注释后面是一组函数,例如 ReadData()。这些功能需要连接到您的通信代码。需要完成的第一组函数是 InitTarget()、ReInitTarget() 和 StopTarget()。它们是驱动程序正确启动和关闭所必需的。然后应该连接内存访问函数,寄存器访问函数。

        所需的最后一组函数是 Step()、GoCmd() 和 SetClrBp()。这些处理用户程序的执行以及断点设置和清除。请注意,GoCmd() 在执行停止之前不应返回,无论是通过到达代码断点\或其他一些事件。

        测试你的驱动程序。如果基本功能正在运行,请将 SampTarg 切换到发布模式并重建它。如果完成,请再次测试驱动程序。请注意,“Release”文件夹包含驱动程序的发布版本。这需要您更改 TOOLS.INI 文件:

注意一般保护故障。例如,如果空指针或无效指针被第四次传递并返回,它们很可能会发生。

示例:SampTarg-51 接口

外部显示器 DLL 的 DLL 驱动程序名称存储在文件 C:\KEIL\TOOLS.INI 中。通过将名称和路径添加到 C:\KEIL\TOOLS.INI 文件来安装新驱动程序。每个 CPU 系列在 TOOLS.INI 文件中都有自己的部分。

TOOLS.INI 文件示例:

您需要修改 TOOLS.INI 文件。例如,如果要将 SampTarg 驱动程序添加到目标驱动程序列表中,请在 [C51] 部分中添加读取 TDRV0=xxx 的行。如果您没有 TRDV 条目,则以 TDRV0=xxx 开头(µVision2 最多接受 40 个驱动程序,TDRV0…TDRV39)。 TDRV0=SampTarg\SampTarg.DLL ("Sample 8051 Target Driver") 行指定 SampTarg 文件夹中的 SampTarg.DLL,该文件夹位于 C:\Keil\C51(由 PATH 指定)。您可以更改此文件夹以满足您的需要。 µVision2 使用包含的字符串(“Sample 8051 Target Driver”)在“目标选项”表的驱动程序列表中显示驱动程序:

可以在“目标选项”中选择在系统调试期间应使用的显示 DLL -使用下拉菜单下的调试页面。使用设置按钮,您可以为调试器界面实现配置对话框。配置数据可以直接存储在 µVision2 项目文件、注册表或单独的 INI 文件中。项目文件中的配置数据允许您项目指定调试器的设置。在 µVision2 调试器启动时,调试器 DLL 会自动加载和初始化。

目标驱动系统远程设置

一旦选择了目标驱动,按下“目标表选项”中的“设置”会导致 µVision2 加载驱动 DLL。

之后,µVision2 使用以下函数代码调用函数 DllUv3Cap

对于 nCode 2,如果是 8051 目标,则返回值必须是 8051 (0x1F73),如果是 80166/80167 目标,则返回值必须是 80167 (0x13927)。以下示例代码显示了如何执行远程设置。 QDLL 结构已从“Bom.h”中提取出来,以便轻松了解数据布局。请注意,在调用 DllUv3Cap() 时,µVision2 未处于调试模式。因此,您无法访问任何调试资源。

有关详细信息,请参阅 SampTarg.cpp 文件。此源文件包含远程设置和命令选项解析的示例代码。还提供了一个运行设置对话框的条目。设置对话框的源代码位于 SetupT.cpp 和 SetupT.h 中。该对话框用于指定 com 端口号、波特率和一些缓存选项。您可以更改此对话框以满足您的需要。

请注意,在远程设置时,您无法访问 µVision2 的任何调试资源,因为 µVision2 未处于调试模式。这也意味着 µVision2 不能访问任何 AGDI 功能。

AGDI 接口函数

所有以 AG_ 开头的函数都需要在目标驱动程序 DLL 中定义。如果函数执行正确,则将值 0 返回给 µVision2,否则应返回错误代码。请注意,必须定义以下导出函数,无论是全功能还是虚拟函数:

        函数                 描述

        AG_Init()         AGDI 初始化函数。

        AG_MemAtt()         内存属性访问函数。

        AG_BpInfo()         断点设置/重置/启用/禁用/终止功能。

        AG_BreakFunc()         断点访问函数。

        AG_GoStep()         执行 / 步进 / 停止命令。

        AG_Serial()         读取/写入串行窗口函数。

        AG_MemAcc()         访问目标内存函数。

        AG_RegAcc()         读/写单个寄存器函数。

        AG_AllReg()         读/写寄存器函数。

        AG_HistFunc()         跟踪历史访问函数。

如果不是这种情况,µVision2 会认为目标驱动程序无效并取消使用它。

开始调试

当 µVision2 调试器通过 Debug - Start/Stop Debug Session 启动时,会调用一个枚举函数。

根据目标架构,函数名称如下:

µVision2首先调用这个函数来匹配当前项目的cpu家族和目标驱动家族。然后使用 nCode = 2 再次调用此函数,并且指针 p 是指向 struct dbgblk 的指针(有关详细信息,请参阅 COMTYP.H)。

该代码可以在文件 SampTarg.cpp 中找到。

如果 EnumUv3xxx 函数成功完成,则 µVision2 通过多次调用 AG_Init 开始初始化 AGDI 接口,每次初始化或请求不同的项目。

所有 AG_ 函数的代码都可以在文件 AGDI.CPP 中找到。

第一次调用包含函数代码 nCode = AG_INITFEATURES 并要求目标驱动程序设置支持特性:

        supp.MemAccR = 0;         // 执行时内存访问

        supp.RegAccR = 0;         // 执行时寄存器访问

        supp.hTrace = 0;         // 跟踪支持

        supp.hCover = 0;         // 代码覆盖支持

        supp.hPaLyze = 0;         // 性能分析器支持

        supp.hMemMap = 0;         // 内存映射支持

        supp.ResetR = 0;         // 运行时重置支持

示例代码中显示的值是监视器的典型值,其中在执行用户程序时无法访问寄存器或内存等资源。

如果您的硬件支持此类功能,这当然可能会有所不同。如果您的仿真硬件有一个独立的通信控制器,这对于基于 USB 的仿真器来说是典型的,那么当用户应用程序运行时,可以中断/重置仿真控制器。在这种情况下,您应该设置:

        supp.ResetR = 1;         // 运行支持时重置

当仿真控制器集成了硬件跟踪功能时,也可以实现跟踪功能。在这种情况下,您应该启用跟踪支持:

        supp.hTrace = 1;         // 跟踪支持

您可以参考 SampTarg.cpp 文件,它提供了一个很好的起点。

使用 nCode = AG_INITITEM AG_Init 的下一次调用使用子代码重复数次。这些用于将句柄、指针和其他内容传输给您的驱动程序。
下一系列 AG_Init 调用具有 nCode = AG_GETFEATURES 以及用于查询实际特征的子代码:

 

系统重置

当给出 µVision2 - Reset 工具栏按钮时,AG_Init() 与 nCode = AG_EXECITEM | AG_RESET 被调用,然后又调用 ResetTarget(),这是一个空函数。

您应该在其中放置所需的任何代码来重置目标系统。 µVision2 假设在这个 AG_INIT 调用之后系统处于复位状态。

停止调试

当调试会话停止时,uVision2 使用 nCode = AG_EXECITEM | AG_UNINIT 激活 AG_Init() 。您应该关闭与目标的连接并释放任何已分配的动态内存。

CPU 寄存器接口

Project Window - Regs 选项卡布局在目标驱动程序中完全定义。

 

µVision2 期望目标驱动程序使用回调 pCbFunc (AG_CB_INITREGV, &dsc)。当调用带有 nCode = AG_GETFEATURE 的 AG_Init() 时。调用 pCbFunc(AG_CB_INITREGV, &dsc);可以在任何时候多次给出动态更改Project Window - Regs 选项卡的布局。

struct REGDSC 定义了寄存器布局(有关更多信息,请参阅文件 AGDI.H)。

 文件 AGDI.CPP 包含 8051 寄存器布局的代码。第一项是组定义:

 组名显示在注册视图中,这些项目充当子项目的父项。下一个定义代表寄存器项:

显示的寄存器项目分配到组 0,即“Regs”组。 “desc”成员必须初始化为 1。“nItem”成员是您分配的数字,应在 0x00…0xFF 范围内。 ‘szReg’成员代表寄存器的名称,如果寄存器只代表程序计数器,则必须设置‘isPC’成员。 “cc”项的意思是“可以更改”。应将其设置为 0 以避免通过寄存器视图更改值。 “iHigh”成员用于强制寄存器视图绘制突出显示的名称和值。

 前面显示的寄存器项目分配到组 1,即“Sys”组。请注意,“nItem”数字需要不同。

一种特殊情况由项目“psw”表示,它使用项目编号 0x100(任何是 0x100 的倍数的数字,例如 0x200、0x300……也可以)。在这种情况下,µVision2 将项目视为子项的父项。这样的父级可以折叠和展开。对孩子的要求是他们的号码必须在“parent-number + 1 ... parent-number + 0xFF”的范围内。示例代码使用数字 0x101 到 0x107 来表示 psw 的标志位:

请注意,您可以使用许多行为类似于“psw”的项目,只要每个项目的项目编号都是 0x100 的倍数。

当 µVision2 需要绘制寄存器视图时,它会访问 RegGet() 函数来获取寄存器的当前值。此时,您必须将寄存器值从目标中提取到描述符中。您应该学习 AGDI.CPP 中的函数 RegGet 和 RegSet()。

需要注意的是,µVision2 在获取各个寄存器项之前会向 RegGet() 发出通知:

该公告让您有机会一次性读取所有寄存器,可以避免对目标的重复访问。再一次看一下 AGDI.CPP 中 RegGet/RegSet 的实现。

通过设置 REGDSC 结构和使用 AG_CB_INITREGV 回调在 µVision2 中注册寄存器接口,如 InitRegs() 函数所示:

如果您想动态更改寄存器视图布局,只需在再次使用 AG_CB_INITREGV 回调之前设置具有另一组 rItems 和 rGroups 的 REGDSC 结构。

µVision2 使用 AG_AllReg() 函数来获取或存储由 AGDI.H 中的 RG51 typedef 定义的寄存器:

AG_RegAcc() 函数用于访问各个寄存器项的值。当寄存器的名称是 µVision2 命令行中表达式的一部分时,最有可能发生这种情况,例如:

'DPTR = 0x1200 | R7':

 

地址表示

地址的表示取决于体系结构。使用 80166/80167 架构时,µVision2 将所有地址转换为线性值,无论其类型如何,例如近、远、巨大或其他基于 DPPn 的地址。这意味着例如地址 0x20000 需要访问目标的物理内存地址 0x20000。

在 8051 世界中,情况有所不同:地址实际上是 8、16 或 24 位偏移量,具体取决于要访问的内存空间。 AGDI 接口和 µVision2 使用 32 位地址值,其中低 8 位或 16 位表示到给定内存空间的偏移量,地址的最高有效字节表示内存空间选择器值,如 AGDI 中所定义。H:

代码地址 C:0x1234 表示为‘(amCODE << 24) | 0x1234' 产生 0xFF001234
数据地址 D:0x72 表示为‘(amDATA << 24) | 0x0072' 产生 0xF0000072
外部数据地址 X:0x5678 表示为‘(amXDATA << 24) | 0x5678' 产生 0x01005678

如果目标支持超过 64K 的 xdata,则地址使用三个字节偏移量,其中第三个字节表示段,例如'(amXDATA << 24) | 0x12AAEE'。这也适用于支持超过 64K 代码的目标:'(amCODE << 24) | 0x035555' 是指定段 0x03 中的代码地址 0x5555 的示例。优点是内存空间选择器、段和偏移量组合成一个值。

看看 AGDI.CPP 中的 ReadMem() 和 WriteMem() 函数。它们都由 AG_MemAcc() 驱动,并展示了如何分散 8051 架构的不同内存空间。

内存接口

AGDI 接口使用函数 AG_MemAcc 来访问目标内存:

参数 'nCode' 指定函数子代码:

        AG_READ:        读取内存

        AG_WRITE:        写入内存

        AG_WROPC:        写入代码内存(在加载用户程序时使用)

        AG_RDOPC:        读取代码内存(用于反汇编)

虽然 AG_WROPC 和 AG_RDOPC 似乎重复 AG_WRITE 和 AG_READ,它们允许您区分代码和非代码访问。 AGDI.CPP 中的示例代码包含代码和数据缓存,以在无法访问目标时提供对内存的快速访问。这非常重要,因为例如反汇编窗口会多次访问代码内存,尤其是在您按下 PageUp 键时。

参数“pB”是一个指向缓冲区的指针,其大小至少为“nMany”字节。 “GADR”给出了要访问的内存地址,如地址表示部分所述。请注意,不使用两个成员“mSpace”和“nLen”。 “nMany”参数指定要传输的字节数。

AGDI 内存接口使用了另外一项功能来加速 µVision2 对内存属性的访问:

AG_MemAtt 背后的故事是 µVision2 需要快速访问内存属性,例如:地址位置包含“可执行代码”或设置了“启用或禁用断点”等等。此类信息显示在所有 µVision2 的编辑器窗口或反汇编窗口的装订线区域(左侧的灰色部分),并且访问量很大。快速访问属性在这里是一个非常重要的问题,否则重绘编辑器窗口的内容需要相当长的时间,这实际上可能导致编辑器或反汇编窗口变得几乎无法使用。

重要的子代码是 AG_GETMEMATT,其中 µVision2 请求属性段。示例代码包含代码和数据缓存。它保存每个内存位置的内存值和属性:

AGDI.CPP 中的 SlotNo() 函数将地址映射到分配的缓存槽之一。

以下是 AGDI.H 中定义的可能属性:

请注意,并非所有给定的属性都需要实现。对于目标驱动程序,属性 AG_ATR_EXEC、AG_ATR_BREAK 和 AG_ATRBPDIS 很重要,因为这些信息反映在编辑器视图和反汇编窗口中。

注意:不要更改AGDI.H中的属性定义,以免与属性发生冲突µVision2 中使用的值!

AG_ATR_EXEC 属性可以在执行带有 nCode AG_WROPC 的 AG_MemAcc 时为每个位置设置。

AGDI.CPP 源文件包含完整的内存接口,其中所有的读写操作都分散到不同的函数中,例如 ReadCode()、ReadXdata()、WriteData()、WriteSFR() 等。您应该添加特定代码的位置标有:

属性 AG_ATR_JTAKEN 和 AG_ATR_EXECD 标记指令的当前执行状态,用于在 µVision2 Debugger 中显示 CODE COVERAGE 信息。根据位显示以下颜色:

AG_ATR_EXECD         AG_ATR_JTAKEN         颜色         说明

0                                         0                                 灰色        指令根本不执行

1                                         0                                 橙色        条件 jmp 到地址从未被占用

0                                         1                                 青色        条件 jmp 到地址总是被占用

1                                         1                                 绿色        指令(续 jmp)完全执行

注意:只有条件跳转指令单独设置 AG_ATR_EXECD 和 AG_ATR_JTAKEN。

所有其他指令始终设置 AG_ATR_EXECD 和 AG_ATR_JTAKEN 位。

执行程序代码

uVision2 使用 AG_GoStep() 函数控制程序执行。 AG_GoStep() 获取以下 nCode 值:

AG_GoStep() 在单独的线程中运行,直到执行停止才返回。在输入 AG_GoStep() 之前,µVision2 启用停止工具栏按钮。

当 AG_GoStep() 返回时,停止按钮被禁用。当应该停止执行时(使用停止工具栏按钮),再次调用 AG_GoStep() 并使用 nCode = AG_STOPRUN。 AGDI.CPP 中的示例实现在开始执行 AG_GOTILADR 或 AG_GOFORBRK 情况下的用户程序之前设置地址断点。执行停止后,断点被删除。

需要填写AGDI.CPP中的SetClrBp()函数来设置和清除地址断点。此处的详细信息取决于您的目标硬件。您还需要填写两个函数,Step() 和 GoCmd()。

Step() 应该执行一个指令步骤。

 GoCmd() 应该开始执行用户程序,直到遇到地址断点或检测到某些停止条件。

当按下工具栏上的 Stop 按钮时,AG_GoStep() 将使用 AG_STOPRUN 子代码激活。此时,您应该停止执行用户程序。

断点

当用户定义或修改断点时,µVision2调用Target Driver函数AG_BpInfo()

此功能不在硬件中设置断点,但允许 µVision2 编辑器查询和更改当前活动的断点并终止或禁用所有断点。断点信息使用属性段存储,如内存接口部分所述。 AG_BpInfo 子代码显示在以下列表中:

        #define AG_BPQUERY 0x01         // 与 AG_BPEXQUERY 相同

        #define AG_BPTOGGLE 0x02         // 不与目标驱动程序一起使用

        #define AG_BPINSREM 0x03         // 不与目标驱动程序一起使用

        #define AG_BPACTIVATE 0x04         // 不与目标驱动程序一起使用

        #define AG_BPDISALL 0x05         // 通知:需要禁用所有地址中断

        #define AG_BPKILLALL 0x06 /        / 通知:需要终止所有地址中断

        #define AG_BPEXQUERY 0x07         // 获取属性:AG_ATR_BREAK、AG_ATR_BPDIS、AG_ATR_EXECD

        #define AG_BPENABLE 0x08         // 通知:在地址处启用断点

        #define AG_BPDISABLE 0x09         // 通知:在地址处禁用断点

        #define AG_BPKILL 0x0A         // 通知:在地址处终止断点

        #define AG_BPSET 0x0B         // 通知:在地址处设置断点

查看文件 AGDI.CPP 中的 AG_BpInfo() 函数了解详细信息。

另一个函数是函数 AG_BreakFunc(),它与 ​​AG_BpInfo() 非常相似:

不同之处在于子代码,因为它接收指向断点定义的指针,即 AG_BP 结构。功能代码是:

        0x01:新断点已链接

        0x02:断点未链接,应更新属性

        0x04:断点更改其启用/禁用属性

        0x05:目标硬件可接受断点

断点列表由 µVision2 维护.应该注意的是,函数 AG_BpInfo() 和 AG_BreakFunc() 都应该只处理属性。在通过 AG_GoStep() AG_GOTILADR 或 AG_GOFORBRK 开始执行之前,应在目标硬件中设置实际断点。

扩展菜单

通过使用 AGDI,您可以将自己的菜单条目添加到 µVision2 的外围设备菜单中。如果您想在目标驱动程序中有对话框,这是必需的。

您需要设置一组“DYMENU”结构。 AGDI.CPP 文件包含 2 个菜单项的示例代码,第一个是配置对话框,第二个是无模式对话框:

每个菜单条目由分隔符代码 (1,2,-2,-1)、菜单项标题和显示或隐藏对话框的函数地址组成。对于无模式对话框,菜单条目有一个称为“DIAD”结构的附加描述符,用于处理更新和终止对话框功能。

菜单结构在 AG_Init() 函数中注册,AG_INITITEM 带有子代码 AG_INITMENU。子代码 AG_INITEXTDLGUPD 期望通用对话框更新函数的地址:

在单步执行或执行停止后,µVision2 通知所有相关窗口和对话框更新自身以反映当前值。在目标对话框的情况下,它调用 DlgUpdate() 函数,如上面注册的那样。

请注意,在关闭驱动程序之前,您还需要一个“CloseAllDlg”函数来关闭所有当前打开的对话框。 AGDI.CPP 示例代码包含扩展所需的所有函数和数据。

创建自己的无模式对话框时,应使用 TestDlg.cpp,h 中的模板代码作为参考。这很重要,因为这些对话框必须使用不同的构造函数和析构函数代码。

注意:为无模式对话框创建自己的对话框资源时,请确保“可见” style 已设置,否则对话框框将始终不可见。无模式对话框在这方面与模式对话框不同。

追踪历史

追踪历史是一个非常有用的工具,用于在执行停止后评估用户程序的执行情况。要使用此功能,必须提供仿真器硬件指令记录,并且必须启用驱动程序跟踪支持。

跟踪记录在调试会话中通过单击工具栏记录按钮激活。

当用户程序执行停止时,可以通过单击工具栏的“显示历史记录”按钮来显示跟踪历史记录。这是由 SamplTarg DLL 驱动程序生成的跟踪显示示例。

请注意,此 Trace 历史记录已作为示例硬编码到 SamplTarg 项目中,并未真正重新编码。

实现跟踪历史

当跟踪历史记录被激活时,AG_HistFunc() 被频繁调用,参数 nCode 设置为以下值:

频繁调用的原因是 Windows 'OnUpdate()' 处理。函数 CalcNumRecords() 应该尽可能快。

仿真硬件现在应该记录所有执行指令的程序计数器。当程序执行在无条件中断被触发时到达断点停止时,可以显示跟踪历史记录。

现在多次调用 AG_HistFunc() 来检索记录的 TracePC[] 列表。首先调用它以使用以下参数检索当前的 Hist 索引:

现在找到执行的最后一条指令的 Hist 索引,再次调用 AG_HistFunc() 以检索该指令的程序计数器,以便从代码内存中反汇编它:

AG_HistFunc() 被一次又一次地调用,直到所有记录的 TracePC[] 都被反汇编并显示在反汇编窗口中。

AGDI 回调

AGDI 可以借用 µVision2 的一些功能。这可以通过使用“pCbFunc”回调指针、函数代码和适当的参数来完成。请注意,这里只描述了最重要的回调函数。附加的可以在文件末尾附近的 AGDI.H 中找到。

执行 µVision2 调试命令

        除了“Exit”之外,几乎所有命令都可以执行。

        例子:

强制 µVision2 更新所有 Windows

        导致所有当前打开的调试窗口和对话框的更新。该函数在更新完成时返回。

        例子:

更改 µVision2 的状态栏消息字符串

        示例:

FLASH 存储器概述

FLASH 存储器和 EEPROM 是广泛用于嵌入式系统应用的非易失性存储器解决方案。它们既可以在片上使用,也可以作为外部独立存储器使用。

FLASH 存储器的使用

        将 FLASH 存储器用于程序代码

        程序代码可以使用多种方案中的任何一种存储在 FLASH 中。必须更新的嵌入式应用程序受益于闪存。这些系统可以很容易地由设备编程器在外部进行编程,并且许多系统可以在系统内重新编程。

        使用 FLASH 存储器进行数据存储

        FLASH 还可用于配置数据和大容量存储。这些系统通常在系统内即时更新。由于 FLASH 是非易失性的(除非它被损坏),这些系统可以在电源故障或复位后恢复配置参数。

访问闪存

在任何一种情况下,您的应用程序都必须包含允许您读取(或执行)和写入闪存的代码。

读取 FLASH 存储器的工作方式与读取任何其他类型的存储器一样。与 FLASH 的唯一区别是您可能对它所保存的数据有一种特殊的格式。这最好用 C 结构来表示。

从 FLASH 存储器执行也像从任何其他类型的存储器执行一样工作。您的 FLASH 设备(及其包含的代码)从特定地址开始。当您创建加载到 FLASH 中执行的程序时,您可能需要在对器件进行编程时重新定位该代码(例如,上传到 XDATA/RAM 然后写入 FLASH)。

写入 FLASH 存储器涉及一些实际工作。您必须具有擦除 FLASH 和写入字节或块的例程。由于不同设备的数量,必须为每个不同的设备定制这些例程。

µVision2 闪存编程

闪存加载是一项附加功能,可使用 µVision2 调试器对目标闪存器件进行直接编程。为了使用此功能,目标硬件必须支持 Flash 编程。 µVision2 版本 V2.34 或更高版本也是必需的。

目标仿真硬件可以支持:

        用于并行/串行闪存设备编程的插入插座

        A ZIF - 零插入力插座是首选。仿真硬件充当外部设备编程器。

        仿真板上的集成闪存设备

        当应用硬件被设计为同时支持仿真模式和与 µVision2 的连接时,就会出现这种情况。在这种情况下,同一块板可用于调试,然后用于应用​​程序控制。如果不需要额外的硬件来支持此功能(即已经实现 RS232 端口),这是一个不错的选择。

Flash 加载:必需步骤

为了使用 Flash 编程,将 SampTarg 驱动程序连接到您的硬件,如主题调试驱动程序:必需步骤中所述。

设置您的目标硬件

编写代码以实现目标驱动程序和您的硬件之间的连接。您可以使用串行端口或任何其他资源。将文件添加到 SampTarg 项目。

将您的驱动程序代码连接到 AGDI.CPP 中包含的相应函数。在 AGDI.CPP 中搜索以下注释:

注释后面是一组用于闪存编程的函数。这些功能暂时被提供为假人。您需要修改它们以实现您的 Flash 设备编程算法。闪存编程过程非常依赖于硬件,因此在实现闪存编程算法时请仔细阅读闪存设备文档。这些功能需要连接到您的通信代码。

需要完成的第一组函数是 InitProgrammer() ExitProgrammer()。它们是正确启动和关闭编程硬件所必需的。然后应该连接闪存设备初始化、写入和读取功能。

请注意,ExitProgrammer() 应将所有 Flash 器件引脚上的电压电平设置为低电平,并断开器件电源,以便安全地从 ZIF 插槽插入和移除 Flash 器件。

然后应该实现 InitDevFlash()FlashLoad() 函数。

InitDevFlash() 函数用于初始化 Flash 存储器。此时,Flash 器件被擦除并准备好进行 Flash 编程。如果需要对不同类型的设备进行编程,可以执行 CheckDevID() 函数来读取设备 ID 并选择合适的编程算法进行 Flash 编程。一些 Flash 器件需要特殊的程序来激活器件的 Flash 编程模式。这是通过函数 EnterProgMode() 完成的。

FlashLoad() 函数用于实际的闪存编程和验证。如果仿真硬件有足够的 SRAM 资源来保存完整的 Flash 图像数据,那么将其用作缓冲区是一个很好的做法。当数据被写入闪存时,它也被存储到 SRAM 并在以后重新用于数据验证。如果使用“慢速”RS232 通信接口对大文件进行编程,这可以大大加快闪存加载过程。

测试你的驱动程序。如果基本功能正在运行,请将 SampTarg 切换到发布模式并重建它。如果完成,请再次测试驱动程序。请注意,“Release”文件夹包含驱动程序的发布版本。这需要您更改 TOOLS.INI 文件:

注意一般保护故障。例如,如果空指针或无效指针被第四次传递并返回,它们很可能会发生。

Flash编程远程设置

选择用于Flash编程的“目标驱动程序”时,Uvision加载DLL驱动程序,并通过调用DLLUV3CAP()函数使用以下代码来检查设备家族:

有关详细信息,请参阅远程设置。

然后使用以下代码再次调用函数:

Target Driver ComboBox 中仅列出了支持 Flash-Download Capabilities 的驱动程序。如果您的驱动程序不支持 Flash 编程,此时 DllUv3Cap() 应返回 0。
选择目标驱动程序后,在“目标表选项”中按“设置”会导致 µVision2 加载驱动程序 DLL。

之后再次调用函数 DllUv3Cap() 以匹配设备系列。有关详细信息,请参阅远程设置。

SampTarg.cpp 源文件包含远程设置和命令选项解析的示例代码。还提供了一个运行设置对话框的条目。设置对话框的源代码位于 SetupFD.cpp 和 SetupFD.h 中。该对话框用于指定要执行的闪存编程功能。您可以更改此对话框以满足您的需要。

使用该对话框选择 Flash 编程功能。如果您只想验证闪存设备,请取消选中“擦除闪存”和“编程闪存”复选框。

注意:某些 Flash 设备还需要设备配置。这通常是基于 Flash 的控制器的情况。在这种情况下,“写入配置”复选框非常有用,应该添加。如果需要,这增加了稍后禁用设备配置的可能性。

Flash 编程接口函数

Flash 编程所需的所有函数都可以在 AGDI.cpp 中找到。暂时定义并提供了以下函数:

        函数                                 说明

        InitProgrammer()         初始化 Flash 编程器

        ExitProgrammer()         关闭 Flash 编程器

        EnterProgMode()         激活 Flash 器件的 Flash 编程模式

        CheckDevID()         检查器件标识字节

        EraseFlash()         擦除 Flash Memory

        WriteToFlash()         写入 Flash 存储器

        VerifyFlash()         验证 Flash 的内容

        InitDevFlash()         初始化 Flash 设备以写入

        FlashLoad()         写入/验证 Flash 设备

请注意,Flash 编程算法取决于 Flash 设备,因此在实施时应仔细阅读设备文档它。

Flash 设备编程

µVision2 Flash Load 可以从 Flash 菜单启动:

或从工具栏:

当 µVision2 Flash Load 启动时,一个枚举函数被调用。 DLL 驱动程序的启动方式与调试会话完全相同。有关详细信息,请参阅开始调试。

当驱动程序正确加载和初始化后,再次调用 AgInit() 函数来初始化 Flash Load,参数如下:

此时,Target Programmer 被初始化。所有 Flash 器件引脚都被驱动为低电平,并且 VCC 电源断开。如果使用 ZIF 插座连接 Flash 设备,则可以插入和移除安全设备。

然后调用 InitDevFlash() 函数。如果需要,这将激活器件 Flash 编程模式,并在 Flash 下载功能对话框中启用时擦除 Flash 存储器。

再次调用函数 AgInit() 以使用以下参数对设备闪存进行编程:

这将开始实际的 Flash 编程和验证程序。

FlashLoad() 将首先初始化 µVision2 进度条,然后通过回调函数从 µVision2 获取 Flash 编程参数。

现在 Flash Load 参数是已知的,所以我们使用回调函数在 while 循环中从 µVision2 请求数据:

器件 Flash 存储器刚刚被编程,现在我们需要验证编程数据。

如果仿真器 SRAM 缓冲区已经被使用,那么验证函数应该被修改为只向仿真器发送一个命令。这将返回“验证正常”或“验证失败”状态以及验证失败的错误地址。

Flash 设备擦除

如果只需要 Flash Memory 擦除,则有一个菜单选项,仅启动 Initialize Flash Load:

DLL 驱动程序的启动方式与 Flash 编程完全相同。有关详细信息,请参阅 Flash 下载。

如果启动闪存擦除,则不调用带有参数 AG_STARTFLASHLOAD 的 AgInit() 函数。闪存设备仅被初始化,然后驱动程序被关闭。

请注意,闪存下载功能“擦除闪存”必须在闪存下载设置中启用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值