TI C6000 DSP SYSCFG模块详解:从寄存器配置到系统级调试实战

TI C6000 DSP SYSCFG模块详解:从寄存器配置到系统级调试实战
1. 项目概述为什么你需要关注SYSCFG模块如果你正在基于TI C6000系列DSP比如C674x做嵌入式开发尤其是涉及实时信号处理、多核通信或者复杂外设管理那么你迟早会跟一个叫SYSCFGSystem Configuration的模块打交道。它不是某个具体的外设驱动而是整个芯片的“总控制台”。很多工程师初期会忽略它觉得这是芯片初始化时配置一次就完事的东西但真正踩过坑的人都知道对SYSCFG理解不透彻系统稳定性、性能优化乃至一些诡异的中断问题都无从下手。简单来说SYSCFG模块提供了一组内存映射寄存器MMR让你能用软件“布线”芯片内部的许多关键硬件资源。比如一个外部事件如何触发DSP核心的中断EDMA传输数据时一次能搬多少字节效率最高USB PHY的时钟到底该用外部晶振还是内部PLL这些看似底层的问题答案都藏在SYSCFG的各个配置寄存器里。它的技术价值在于将许多硬连线或需要复杂外部电路实现的控制逻辑抽象成了可编程的寄存器位极大地提升了系统设计的灵活性和可维护性。无论是做电机控制、音频处理还是通信网关理解并善用SYSCFG是从“代码能跑”到“系统稳定高效”的必经之路。2. 核心思路SYSCFG模块的设计哲学与寄存器地图解析2.1 模块定位与访问方式SYSCFG模块在TI DSP的存储器映射中通常位于一个固定的地址段。以我常用的C6748为例其基地址是0x01C1 4000。你不需要记住每个寄存器的绝对地址TI的芯片支持包Chip Support Library, CSL或者寄存器定义头文件如c6748.h会提供结构体映射方便以SYSCFG-CHIPSIG这样的方式访问。这个模块的设计哲学是“集中管理分散控制”。它管理的是跨外设、影响系统级行为的全局性资源而非某个具体外设的功能。因此它的寄存器往往扮演着“开关”、“选择器”或“信号路由器”的角色。在阅读数据手册时你会看到大量类似“CFGCHIPx”的寄存器它们的位域Bit Field可能控制着毫不相关的几个功能这恰恰体现了其作为系统级“接线板”的特性。2.2 关键寄存器族概览根据提供的资料我们可以将SYSCFG的关键寄存器分为几个功能族中断信号管理族主要包括CHIPSIG和CHIPSIG_CLR。这是实现核间通信IPC或由外部逻辑如FPGA触发DSP中断的核心。芯片全局配置族即CFGCHIP0到CFGCHIP4。这是SYSCFG的精华所在功能庞杂包括时钟与锁相环PLL控制如CFGCHIP0的PLL锁存CFGCHIP3的DIV4.5分频器和EMIF时钟源选择。外设互连与事件路由如CFGCHIP1它能将McASP的DMA事件、EMAC的中断事件路由到eCAP模块作为捕获源或将GPIO中断路由给McASP作为静音信号。这实现了硬件级的事件联动无需CPU干预。高速接口PHY配置如CFGCHIP2全面管理USB 2.0 OTG PHY的时钟、电源、模式和复位。专用功能清除如CFGCHIP4用于清除McASP的AMUTEIN中断锁存状态。启动配置寄存器BOOTCFG资料中提及但未展开它锁存了芯片上电时Boot引脚的状态决定了DSP从何处NOR Flash, NAND Flash, UART, SPI等加载初始代码。理解这个分类有助于你在调试时快速定位问题。比如USB枚举失败首先应该查CFGCHIP2如果eCAP捕获不到某个串口事件则应该去CFGCHIP1检查事件源路由配置。3. 核心细节解析关键寄存器位域深度剖析3.1 CHIPSIG与CHIPSIG_CLR软件触发中断的“门铃”这两个寄存器是理解SYSCFG中断机制的关键。它们通常用于多核DSP如OMAP-L138的双核C674xARM9之间的通信或者让一个协处理器如FPGA来“敲门”通知DSP。CHIPSIG (Chip Signal Register)这是一个“置位”寄存器。向CHIPSIG[4]NMI、CHIPSIG[3]或CHIPSIG[2]位写入1会立即在DSP核心产生一个对应的中断NMI或SYSCFG_CHIPINTx。写入0无效。这个设计很巧妙它允许发送方另一个CPU或硬件简单地写一个1过来就能触发中断无需“读-改-写”操作避免了竞态条件。你可以把CHIPSIG的这几个位看作连接DSP中断输入线的几个“按钮”按一下写1就触发。CHIPSIG_CLR (Chip Signal Clear Register)这是一个“清除”寄存器。它的位与CHIPSIG一一对应。当中断服务程序ISR处理完事件后需要向CHIPSIG_CLR的对应位写入1来清除CHIPSIG寄存器中对应的位。这个清除操作是给接收中断的处理器DSP用的用于告知发送方“事情已处理完”。发送方可以通过轮询PollingCHIPSIG寄存器的对应位是否为0来判断DSP是否已完成服务。实操心得核间通信的典型范式假设ARM核要通知DSP核一个消息已就绪ARM核SYSCFG-CHIPSIG (1 2);// 触发DSP的SYSCFG_CHIPINT2中断。DSP核的SYSCFG_CHIPINT2中断被触发进入ISR。DSP ISR读取共享内存中的消息进行处理。DSP ISRSYSCFG-CHIPSIG_CLR (1 2);// 清除中断标志通知ARM。ARM核循环检测while (SYSCFG-CHIPSIG (1 2)) {};// 等待DSP清除。ARM核检测到标志清除知道DSP已处理完毕可以进行下一步操作。关键点CHIPSIG的位是“粘性的”Sticky一旦被置1会一直保持直到被CHIPSIG_CLR明确清除。这确保了中断信号不会丢失。3.2 CFGCHIP0PLL锁与EDMA3性能调优CFGCHIP0虽然位数不多但管的两件事都至关重要。PLL_MASTER_LOCK (Bit 4)这是一个安全特性。当系统时钟通过PLL配置稳定后将此位置1可以锁住所有PLL控制器的内存映射寄存器防止后续软件尤其是存在潜在bug的代码意外修改PLL配置导致系统时钟紊乱而死机。这是一个“保险丝”通常在系统初始化后期确认所有时钟配置无误后一次性设置之后不再改动。TCxDBS (Transfer Controller Default Burst Size, Bits [3:2]和[1:0])这是影响EDMA3控制器性能的关键参数之一。它决定了每个传输控制器TC发起一次读写命令时数据总线上的突发传输大小。可选16、32或64字节。为什么需要配置更大的突发长度能提高总线利用率减少仲裁开销从而提升纯理论带宽。例如从连续内存搬移大量数据到某个外设时64字节突发可能比16字节快。但是并非越大越好数据手册的警告非常中肯The DBS value can significantly impact the standalone throughput performance depending on the source and destination (bus width/frequency/burst support etc) and the TC FIFO size。你需要考虑目标外设的支持你的DDR内存控制器是否支持64字节突发你的目标外设如McASP的FIFO深度是否足够容纳一次突发数据系统实时性更大的突发意味着单次传输占用总线时间更长可能会阻塞其他高优先级主设备如CPU的访问增加访问延迟。在强实时系统中有时需要牺牲一点带宽来换取确定性的低延迟。数据对齐突发传输通常对地址有对齐要求如64字节突发要求地址是64字节对齐。如果数据缓冲区地址不对齐EDMA3控制器会自动拆分成多个非对齐的小传输反而可能降低效率。如何选择没有银弹。对于大多数流式数据处理如音频buffer搬运32字节是一个不错的折中起点。对于需要极致低延迟的控制环路可以考虑16字节。最终需要通过实际场景的压力测试如同时运行多个DMA传输和CPU任务来验证和调整。3.3 CFGCHIP1硬件事件路由的“十字路口”这个寄存器是SYSCFG灵活性的集中体现。它不产生新功能而是将已有的硬件事件信号“导线”重新连接实现高效的硬件协作。CAPxSRC (Bits [31:27], [26:22], [21:17])分别控制eCAP0, eCAP1, eCAP2模块的事件输入源。默认是来自自身的输入引脚eCAPx Pin。但通过此配置你可以将其改为McASP TX/RX DMA事件这意味着当McASP通过DMA发送或接收完一个数据块时会自动触发eCAP模块进行一次时间戳捕获。应用场景精确测量音频流的吞吐率或两个音频流之间的相对延迟无需CPU干预。EMAC的各种中断事件可以将网络数据包的到达RX、发送完成TX等事件作为eCAP的触发源。应用场景为网络数据包打上高精度的时间戳用于网络同步或协议分析。配置方法查阅数据手册中CFGCHIP1寄存器CAPxSRC位的详细编码表如0x1代表McASP0 TX DMA事件。在初始化eCAP前先配置此路由。TBCLKSYNC (Bit 12)eHRPWM增强型高分辨率PWM模块的时间基准时钟全局同步位。当系统中有多个eHRPWM模块需要输出完全同步的PWM波时例如三相逆变器此位是关键。工作原理将此位置1会在下一个TBCLK上升沿让所有已使能的eHRPWM模块的时基计数器同时开始计数。前提条件所有需要同步的eHRPWM模块的TBCTL寄存器中的预分频器HSPCLKDIV和CLKDIV必须设置成相同的值否则即使同步启动频率也不同很快又会失步。AMUTESELx (Bits [11:8], [7:4], [3:0])选择McASP的AMUTEIN音频静音输入信号源。默认是拉低。可以将其配置为来自某个GPIO Bank的中断。应用场景在音频系统中你可以将一个硬件故障检测引脚如过流保护连接到某个GPIO。当故障发生时GPIO产生中断此中断信号通过SYSCFG直接路由到McASP的AMUTEIN硬件会立即静音音频输出响应速度远快于软件中断处理。清除机制与之配套的是CFGCHIP4寄存器的AMUTECLRx位。当GPIO中断触发AMUTE后该状态会被锁存。处理完故障后需要向AMUTECLRx位写1来清除这个锁存状态才能解除静音。3.4 CFGCHIP2USB 2.0 OTG PHY的“总闸”这是配置USB功能的首要和必查寄存器。很多USB无法识别的问题根源都在这里的配置错误。关键状态位只读USB0PHYCLKGD(Bit 17)PHY时钟状态。为1表示时钟稳定、电源良好且PLL已锁定。这是USB PHY正常工作的前提初始化后必须检查此位是否为1。USB0VBUSSENSE(Bit 16)VBUS电压检测状态。在Device模式下用于检测主机是否提供了VBUS电源。关键控制位RESET(Bit 15)USB PHY复位。上电后需要先置1复位再清0释放复位这是标准的PHY初始化流程。USB0OTGMODE(Bits [14:13])强制OTG模式。通常设置为0无覆盖让PHY根据ID引脚和VBUS比较器自动判断主机/设备模式。在调试时可以强制设为主机(1)或设备(2)模式以排除软件协议栈的问题。USB0PHYCLKMUX(Bit 11)时钟源选择。这是最容易出错的地方之一。0: USB PHY参考时钟来自外部引脚USB_REFCLKIN。这是最常见的方式需要板载一个精确的晶振通常19.2MHz, 20MHz, 24MHz, 26MHz或48MHz连接到该引脚。1: USB PHY参考时钟来自内部AUXCLK由PLL产生。这种方式可以减少一个外部晶振但必须确保PLL能产生一个非常稳定且符合USB规范频率容差的时钟。USB0REF_FREQ(Bits [3:0])必须与USB0PHYCLKMUX的选择和实际输入的时钟频率严格匹配如果你选择外部24MHz晶振那么此字段必须配置为2h24 MHz。如果配置错误PHY无法正常工作。USB0PHYPWDN(Bit 10) 和USB0OTGPWRDN(Bit 9)PHY和OTG子系统掉电控制。正常工作时必须为0使能。在低功耗模式下可以将其置1以关闭USB模块省电。USB0DATPOL(Bit 8)数据线极性。通常保持默认值1不反转。只有在PCB布线时将USB的D和D-线交叉了才需要将此位置0来软件纠正。正常情况下绝对不要动。3.5 CFGCHIP3与CFGCHIP4时钟与辅助功能CFGCHIP3主要控制EMIF外部存储器接口的时钟源。DIV4P5ENA(Bit 2)使能一个固定的4.5分频器可以从600MHz PLL产生133MHz时钟供给EMIF。EMA_CLKSRC/EMB_CLKSRC(Bits [1:0])选择EMIFA和EMIFB的时钟是来自PLLC的SYSCLK3/5还是来自上述的DIV4.5输出。这直接影响到你外接SDRAM或异步存储器的访问速度需要根据芯片数据手册推荐的时钟配置和你的实际硬件SDRAM型号来设置。CFGCHIP4功能单一就是清除CFGCHIP1中配置的McASP AMUTEIN锁存中断。向对应位写1产生一个清除脉冲。4. 实操流程从零开始配置SYSCFG的完整指南下面我将以一个典型的C6748 DSP项目为例展示如何系统性地初始化SYSCFG模块。假设我们需要1) 使能核间中断2) 配置EDMA3突发大小为32字节3) 配置USB为Device模式并使用外部24MHz晶振4) 将McASP0的TX DMA事件路由到eCAP1。4.1 准备工作与头文件包含首先确保你的工程包含了芯片的寄存器定义头文件。TI的编译器通常自带或者你可以从CSL库中找到。#include #include “c6748.h” // 假设这是你的芯片寄存器定义头文件 // 或者使用CSL方式 #include #include4.2 分步配置代码实现我们将在系统初始化早期在配置完PLL和基础时钟之后来设置SYSCFG。void SYSCFG_Init(void) { // 步骤1解锁PLL控制器如果需要。在配置PLL前确保CFGCHIP0的PLL锁未使能。 // 通常PLL配置由Bootloader或更早的初始化代码完成这里假设PLL已配好。 // 我们暂时保持PLL_MASTER_LOCK为0最后再锁。 // 步骤2配置EDMA3传输控制器的默认突发大小(DBS)为32字节。 // 假设我们使用TC0和TC1。0x1对应32字节。 uint32_t temp CSL_FEXT(SYSCFG-CFGCHIP0, SYSCFG_CFGCHIP0_TC0DBS); temp CSL_FMK(SYSCFG_CFGCHIP0_TC0DBS, 1) | CSL_FMK(SYSCFG_CFGCHIP0_TC1DBS, 1); // 注意修改寄存器时对于保留位(Reserved)必须写入其复位默认值通常是0。 // CSL库的FMK宏通常会处理但若直接操作寄存器需注意 // SYSCFG-CFGCHIP0 (SYSCFG-CFGCHIP0 ~0xF) | (1 0) | (1 2); // TC0DBS1, TC1DBS1 CSL_FINS(SYSCFG-CFGCHIP0, SYSCFG_CFGCHIP0_TC0DBS, 1); CSL_FINS(SYSCFG-CFGCHIP0, SYSCFG_CFGCHIP0_TC1DBS, 1); // 步骤3配置USB 2.0 PHY // 3.1 首先确保USB PHY处于复位状态 CSL_FINS(SYSCFG-CFGCHIP2, SYSCFG_CFGCHIP2_RESET, 1); // 3.2 配置时钟源和频率外部24MHz晶振 CSL_FINS(SYSCFG-CFGCHIP2, SYSCFG_CFGCHIP2_USB0PHYCLKMUX, 0); // 外部时钟 CSL_FINS(SYSCFG-CFGCHIP2, SYSCFG_CFGCHIP2_USB0REF_FREQ, 2); // 24 MHz (0x2) // 3.3 使能VBUS比较器和Session End比较器对于Device模式很重要 CSL_FINS(SYSCFG-CFGCHIP2, SYSCFG_CFGCHIP2_USB0VBDTCTEN, 1); CSL_FINS(SYSCFG-CFGCHIP2, SYSCFG_CFGCHIP2_USB0SESNDEN, 1); // 3.4 退出复位状态 CSL_FINS(SYSCFG-CFGCHIP2, SYSCFG_CFGCHIP2_RESET, 0); // 3.5 等待PHY时钟稳定可选但建议 // 这里简单延时实际产品中可能需要更可靠的检查 delay_us(100); // 可以添加检查while(!CSL_FEXT(SYSCFG-CFGCHIP2, SYSCFG_CFGCHIP2_USB0PHYCLKGD)); // 步骤4配置硬件事件路由 - 将McASP0 TX DMA事件作为eCAP1的输入源 // 先读取整个字段然后修改对应的位域避免影响其他配置。 uint32_t cfgchip1 SYSCFG-CFGCHIP1; // 清除CAP1SRC原来的值Bits 26-22然后设置为McASP0 TX DMA事件 (值 1) cfgchip1 ~(0x1F 22); // 清除5个bit cfgchip1 | (1 22); // 设置为1 (McASP0 TX DMA Event) SYSCFG-CFGCHIP1 cfgchip1; // 使用CSL库写法CSL_FINS(SYSCFG-CFGCHIP1, SYSCFG_CFGCHIP1_CAP1SRC, 1); // 步骤5锁住PLL配置防止意外修改系统稳定后执行 CSL_FINS(SYSCFG-CFGCHIP0, SYSCFG_CFGCHIP0_PLL_MASTER_LOCK, 1); // 步骤6可选配置EMIF时钟源。假设我们使用DIV4.5输出给EMIFA。 CSL_FINS(SYSCFG-CFGCHIP3, SYSCFG_CFGCHIP3_DIV4P5ENA, 1); // 使能4.5分频器 // 等待分频器稳定... CSL_FINS(SYSCFG-CFGCHIP3, SYSCFG_CFGCHIP3_EMA_CLKSRC, 1); // EMIFA时钟源选择DIV4.5输出 }4.3 核间中断使用示例假设DSP需要响应来自ARM的中断CHIPINT2。DSP端代码 (ISR准备)// 首先在DSP的中断服务表IST中将SYSCFG_CHIPINT2中断向量指向你的处理函数。 // 这通常在中断初始化函数中完成例如使用CSL的IRQ_plug函数或直接设置IST。 // SYSCFG_CHIPINT2的中断服务函数 interrupt void SYSCFG_CHIPINT2_ISR(void) { // 1. 读取共享内存或信号量获取ARM发送的消息或任务 // uint32_t message *((volatile uint32_t *)SHARED_MEMORY_ADDR); // 2. 处理任务... processInterruptTask(); // 3. 至关重要清除CHIPSIG中的中断标志位通知ARM处理完成。 SYSCFG-CHIPSIG_CLR (1 2); // 清除CHIPSIG2 // 4. 如果需要确认中断某些平台可能需要操作中断控制器 // IRQ_clear(...); }ARM端代码 (触发中断)// 在ARM端通过写DSP SYSCFG模块的CHIPSIG寄存器来触发中断。 // 需要确保ARM能访问DSP的SYSCFG地址空间通常通过配置MMU或共享内存区域实现。 volatile uint32_t *dsp_chipsig (volatile uint32_t *)(DSP_SYSCFG_BASE CHIPSIG_OFFSET); void send_signal_to_dsp(void) { // 1. 将数据或命令写入共享内存 // *((volatile uint32_t *)SHARED_MEMORY_ADDR) COMMAND; // 2. 触发DSP中断 *dsp_chipsig (1 2); // 置位CHIPSIG2 // 3. 等待DSP处理完成轮询方式 while (*dsp_chipsig (1 2)) { // 可以加入超时机制 } // 4. DSP已清除标志可以继续后续操作 }5. 常见问题排查与调试技巧实录SYSCFG配置问题往往表现为系统级的不稳定或外设完全无法工作。以下是我在实际项目中遇到的典型问题及排查思路。5.1 USB无法识别或枚举失败这是最常遇到的问题几乎都与CFGCHIP2配置有关。症状USB设备插入主机主机毫无反应或提示“无法识别的设备”。排查清单检查物理连接和电源确保VBUS5V供电正常D和D-数据线连接正确。确认时钟配置这是重中之重。使用示波器测量USB_REFCLKIN引脚是否有时钟信号频率是否准确如24.000MHz。频率偏差必须小于±0.25%普通的无源晶振可能达不到要求建议使用有源晶振或时钟发生器。核对CFGCHIP2寄存器USB0PHYCLKMUX和USB0REF_FREQ是否与硬件时钟源匹配USB0PHYPWDN和USB0OTGPWRDN是否为0使能RESET位是否先1后0完成了复位USB0PHYCLKGD位是否为1时钟/电源/PLL正常检查数据线极性除非PCB画反了否则USB0DATPOL保持为1默认。可以用示波器看D和D-在枚举时的差分信号如果完全没动静可能是PHY未工作如果有信号但主机不认可能是极性错误。软件栈问题如果以上硬件配置都正确问题可能出在USB设备协议栈的初始化或描述符上。5.2 eCAP无法捕获到预期的事件症状配置了eCAP从McASP事件捕获但eCAP的捕获寄存器始终为0或不变。排查清单确认事件源本身是否发生首先确保McASP的DMA传输确实已启动并产生了完成事件。可以通过读取McASP的DMA状态寄存器或使用GPIO翻转来验证。检查SYSCFG路由配置确认CFGCHIP1中对应的CAPxSRC字段已正确设置为目标事件如McASP0 TX DMA事件的值是1。检查eCAP模块自身配置eCAP是否工作在捕获模式ECCTL2.CAP/APWM 0捕获使能位ECCTL1.CAPLDEN是否置位事件分频ECCTL1.EVTPS是否设置得过大过滤掉了事件对应的捕获事件中断标志ECFLG.CEVTx是否被置位即使不使能中断标志位也会变化。信号同步问题确保事件产生和eCAP模块的时钟域是同步的。如果涉及跨时钟域可能需要检查是否有同步器。5.3 EDMA3传输性能不达预期症状理论计算DMA带宽很高但实测数据吞吐率很低。排查清单检查CFGCHIP0的DBS设置使用逻辑分析仪或芯片的性能计数器观察EDMA传输的突发长度。如果始终是单次传输非突发可能是DBS设置过小或者源/目标地址未对齐。优化传输参数DBS只是因素之一。同时检查传输数据量是否远大于DBS否则无法体现突发优势。源和目标地址递增模式是否设置为连续递增SUM/DUM INC如果是固定模式不会发生突发。FIFO深度查阅数据手册确认你使用的TC的FIFO深度。如果一次传输的数据量小于FIFO深度且地址对齐DMA控制器会尽量用突发填满FIFO。系统总线竞争使用性能分析工具如TI的System Analyzer查看在DMA传输期间是否有其他高优先级主设备如CPU、另一个DMA频繁占用总线导致DMA等待。5.4 核间中断CHIPSIG无法触发或无法清除症状一个核写了CHIPSIG另一个核没进中断或者进了中断但清除标志后对方仍然检测到标志位为1。排查清单内存映射与访问权限确保触发中断的核如ARM有权限写入DSP的SYSCFG寄存器空间。这通常需要在MMU或系统地址转换表中配置。中断使能与映射在接收中断的核如DSP上除了SYSCFG模块本身还需要在中断控制器INTC中使能SYSCFG_CHIPINTx这个系统中断并将其映射到可屏蔽中断线上。SYSCFG只产生中断信号INTC负责接收和分发。缓存一致性问题如果两个核通过共享内存传递数据务必注意缓存一致性。在写入共享数据后、触发中断前发送核应执行缓存写回并无操作如CacheWBInv。在接收核的ISR中读取共享数据前应执行缓存无效操作如CacheInv。否则可能读到旧数据。清除操作的正确性确保是在接收中断的核的ISR中向CHIPSIG_CLR写1而不是向CHIPSIG写0。向CHIPSIG写0是无效的。寄存器位宽与访问确认你访问的是32位的完整寄存器。有些总线访问可能被拆分成字节访问导致意外行为。使用volatile指针并确保32位对齐访问。5.5 调试方法论总结寄存器检查法在初始化后和出问题时通过调试器如CCS直接读取SYSCFG相关寄存器的值与预期配置逐位对比。这是最直接的方法。信号追踪法对于时钟、中断信号路由问题如果条件允许使用示波器或逻辑分析仪探测关键引脚如USB_REFCLKIN或内部信号某些芯片提供信号观察引脚。隔离测试法将复杂配置分解。例如先确保USB PHY的时钟和电源正常通过读状态位再使能数据通路先测试eCAP从引脚捕获再测试从内部事件源捕获。查阅勘误表TI的芯片勘误表Silicon Errata是宝藏。某些SYSCFG相关的问题如特定配置下USB不稳定可能已知并有解决方案或规避方法。SYSCFG模块是连接软件意图与硬件行为的枢纽。它的配置往往在系统启动的最早期完成但其影响贯穿整个应用的生命周期。花时间深入理解这些寄存器尤其是在项目初期进行充分的验证和测试能为系统的稳定性和性能打下坚实的基础。记住在嵌入式世界里魔鬼藏在细节中而SYSCFG正是这些细节的集散地。