1. 项目概述:为何选择LPC3141/3143这颗“老将”?
在嵌入式项目选型时,我们常常面临一个经典困境:是追求极致性能的Cortex-M7/A系列新贵,还是选择那些久经沙场、生态成熟、性价比突出的经典架构?对于许多工业控制、消费电子和需要复杂外设集成的应用来说,NXP的LPC3141/3143系列至今仍是一个被低估的宝藏。它集成了一个运行在270MHz的ARM926EJ-S内核,这听起来可能不如动辄几百兆赫兹的Cortex-M4/M7“新潮”,但其真正的价值在于极其均衡和丰富的片上系统(SoC)集成度。
这颗芯片最吸引我的地方,是它在一个单芯片内几乎打包了一个完整嵌入式系统所需的所有关键模块:高速USB 2.0 OTG(带片上PHY,省去外部芯片)、专用的NAND闪存控制器(支持硬件ECC和AES解密)、灵活的外部存储器接口、LCD控制器、以及多个串行接口。对于需要连接大容量存储(如NAND Flash)、显示界面(LCD)、并与PC或其他USB设备进行高速数据交换的项目,LPC3141/3143能大幅简化你的硬件设计,减少BOM成本和PCB面积。特别是LPC3143型号集成的AES硬件解密引擎和一次性可编程(OTP)存储器,为需要安全启动或数据加密的应用提供了开箱即用的解决方案,这在同期的许多MCU中并不常见。
我最初接触它是在一个旧项目的升级中,客户要求保留原有的架构和大部分代码,但需要增加USB海量存储设备(U盘)读写和液晶屏显示功能。重新画板换用新平台成本太高,而LPC3141恰好完美匹配了这些新增的外设需求,让升级变得平滑。它的低功耗特性,尤其是动态时钟门控和多个独立电源域,对于电池供电或能源敏感的设备来说,是实打实的续航保障。接下来,我将结合自己的实战经验,深入拆解这颗芯片的核心特性、设计要点和那些数据手册里不会明说的“坑”。
2. 核心架构与设计思路解析
2.1 ARM926EJ-S内核:性能与效率的平衡点
LPC3141/3143的核心是ARM926EJ-S,这是一个经典的ARM9家族处理器。与现在流行的Cortex-M系列不同,ARM9是冯·诺依曼架构的处理器,拥有内存管理单元(MMU)。这意味着它可以运行像Linux这样的完整操作系统,而不仅仅是RTOS。270MHz的主频,配合16KB的指令缓存(I-Cache)和16KB的数据缓存(D-Cache),在处理复杂协议栈(如USB协议、文件系统)和图形界面时,能提供比无缓存MCU流畅得多的体验。
在实际项目中,MMU的存在是一把双刃剑。好处是你可以方便地实现虚拟内存管理,隔离用户空间和内核空间,提升系统的稳定性和安全性,非常适合运行Linux。但这也带来了复杂性,你需要正确配置页表,理解虚拟地址到物理地址的映射。对于从Cortex-M系列转过来的开发者,这是一个需要重新学习的概念。我的经验是,如果项目不需要运行大型操作系统,只是使用RTOS(如FreeRTOS)或裸机编程,你可以将MMU配置为最简单的“平坦映射”(即虚拟地址等于物理地址),从而简化初始开发。芯片支持动态调整CPU时钟与AHB总线时钟的比例,这在优化功耗时非常有用。当处理负载较轻时,可以降低CPU频率,而保持外设总线时钟不变,确保USB、LCD等接口的时序不受影响。
2.2 存储子系统:速度、容量与安全的三角博弈
芯片的存储架构是其设计的亮点之一。内部集成了192KB的SRAM,分为两个96KB的块(ISRAM0和ISRAM1)。在规划内存使用时,我的建议是将ISRAM0用于存放最需要快速访问的数据和栈,例如USB批量传输的缓冲区、LCD的帧缓冲区。ISRAM1则可以用于运行核心代码或作为系统堆空间。这种布局可以利用ARM内核的缓存优势,减少访问延迟。
外部存储器接口(MPMC)支持连接SDRAM和SRAM,这对于需要大内存的应用(如图形界面、数据缓存)至关重要。但这里有一个关键细节:当使用SDRAM时,NAND闪存接口、SDRAM和LCD接口的供电电压(SUP4和SUP8域)必须连接到同一电源轨上。这意味着你的板级电源设计必须仔细考虑,不能将它们分开供电。我曾在一个早期版本中忽略了这一点,将LCD单独用3.3V供电,而SDRAM用1.8V,结果导致SDRAM读写极不稳定,排查了整整两天才找到这个电源约束条件。
NAND闪存控制器是另一个核心模块,尤其是对于LPC3143。它不仅仅是一个简单的接口,而是集成了硬件ECC(纠错码)引擎和AES解密引擎。对于使用MLC NAND Flash的项目来说,硬件ECC是必需品,因为MLC颗粒的位错误率比SLC高得多。芯片的ECC模块使用里德-所罗门编码,能纠正每512字节页中的多个符号错误,大大提升了数据存储的可靠性。AES引擎则支持从加密的NAND、SPI Flash或SD卡安全启动,保护你的知识产权和固件安全。在配置时,需要注意NAND控制器的时序参数需要根据你选用的具体Flash型号进行编程,包括tCS、tWP、tWH等时间参数,这些在Flash的数据手册中都能找到。
2.3 电源与时钟管理:低功耗设计的基石
LPC3141/3143的低功耗特性并非空谈,它通过多电源域和灵活的时钟生成单元(CGU)来实现。芯片内部有多个独立的电源域:
- SUP1 (1.0V-1.3V):数字核心电压(VDDI),为ARM内核和部分模拟电路(如PLL)供电。
- SUP3 (2.7V-3.6V):主要外设I/O电压(VDDE_IOC),以及ADC、USB PHY的模拟供电。
- SUP4/SUP8 (1.65V-1.95V或2.5V-3.6V):分别为NAND接口和SDRAM/LCD接口供电,两者电压必须一致。
这种设计允许你独立关闭或调节不同模块的电源。例如,在系统休眠时,可以关闭SDRAM和LCD的电源(SUP8域),而仅保持RTC和唤醒逻辑在SUP3域下运行。CGU支持动态时钟门控和缩放。时钟门控是指当某个模块(如闲置的SPI或I2C)不工作时,完全关闭其时钟源,消除动态功耗。时钟缩放则允许你动态调整CPU、AHB、APB总线的运行频率。一个实用的策略是:在处理器密集型任务时全速运行(270MHz),在等待外部事件或处理简单任务时,将CPU频率降至90MHz甚至更低,同时保持USB等需要特定时钟的外设不受影响。
注意:VPP引脚(用于OTP编程)的上电顺序有严格要求。必须确保在VDDI(核心电压)达到正常工作电压之前,VPP的电压不能超过2.3V。否则,可能会意外烧写OTP中的安全熔丝,导致芯片被锁定或AES密钥损坏,芯片将彻底报废。稳妥的做法是,在初始上电时,将VPP连接到SUP1(即VDDI)域,待系统稳定后再由软件控制切换到更高的编程电压(如果需要编程OTP的话)。
3. 关键外设接口的实战配置与驱动开发
3.1 高速USB 2.0 OTG:从PHY到协议栈
集成高速USB OTG PHY是LPC3141/3143的一大卖点,它省去了昂贵且占空间的外部PHY芯片。USB模块支持设备(Device)、主机(Host)和OTG角色,通过USB_ID引脚的电平自动或由软件控制切换。在硬件设计上,需要注意USB_DP和USB_DM线上已经集成了45欧姆的终端电阻,因此PCB布线时无需再外接匹配电阻,但应确保走线差分对等长,阻抗控制在90欧姆。
在软件层面,USB驱动的开发是整个项目中最复杂的部分之一。你需要处理多个层次:
- PHY和控制器初始化:配置USB时钟源(通常来自主PLL)、使能PHY、设置工作模式(设备/主机)。
- 端点配置:芯片支持多个双向端点。你需要根据USB设备描述符(如海量存储设备类MSC、人机接口设备类HID)来分配端点。例如,对于MSC设备,通常需要分配一个批量输入(Bulk IN)端点和一个批量输出(Bulk OUT)端点。
- DMA配置:为了高效传输数据,务必使用USB模块的DMA功能。你需要设置DMA描述符,将USB端点的数据缓冲区与片内SRAM或外部SDRAM关联起来。当USB有数据到达或需要发送数据时,DMA控制器会自动搬运,大大减轻CPU负担。
一个常见的坑是USB枚举失败。除了检查硬件连接和电源,软件上要确保描述符(设备描述符、配置描述符、接口描述符、端点描述符)完全正确,并且对主机请求的响应速度足够快。建议在初始调试时,使用一个简单的HID设备(如USB键盘)作为模板,因为其协议相对简单,成功后再迁移到更复杂的MSC或CDC(串口)设备。
3.2 NAND Flash控制器与文件系统集成
NAND Flash控制器的配置是数据可靠性的关键。首先,你需要根据连接的NAND Flash芯片数据手册,正确设置控制器时序寄存器(如TCEA、TWH、TWP等)。然后,需要初始化ECC引擎。对于LPC3143,你还可以选择使能AES解密,用于读取加密的启动镜像。
在实际操作中,与NAND Flash交互通常有两种模式:
- 软件控制模式:CPU直接通过寄存器发送命令、地址和数据到Flash。这种方式灵活,但效率低,适合初始化、读取ID等操作。
- 硬件控制模式(带DMA):设置好起始地址、传输长度和ECC/AES选项后,启动控制器,由它自动完成整个页的读取或写入,并通过DMA将数据搬运到系统内存。这是执行大量数据读写(如加载操作系统镜像、读写文件)的标准方式。
将NAND Flash用于文件系统(如YAFFS2, UBIFS)时,需要提供底层的读写、擦除和坏块管理函数。LPC3141/3143的硬件ECC能透明地处理读写过程中的纠错,但坏块管理仍需软件实现。通常的做法是在驱动层维护一个坏块表,在初始化时扫描所有块,将坏块标记并排除在可用空间之外。
3.3 外部存储器接口(MPMC)与SDRAM初始化
MPMC的配置相对直接,但时序参数至关重要。你需要根据SDRAM芯片的数据手册,正确配置:
- 存储器类型和位宽:例如,16位数据总线,4个Bank,行地址位数,列地址位数。
- 时序参数:包括行预充电时间(tRP)、行有效到列有效延迟(tRCD)、行周期时间(tRC)以及刷新间隔(Refresh Period)。这些参数通常以时钟周期数设置。
- 初始化序列:SDRAM上电后必须执行一个严格的初始化序列,包括预充电所有Bank、执行多个自动刷新(Auto Refresh)命令、最后设置模式寄存器(MRS)。这个序列通常由MPMC的控制器在配置后自动执行,但你需要在代码中确保供电稳定并等待足够的上电延时(通常几百微秒)后再启动配置。
一个调试技巧是,先使用最简单的时序参数(较大的延迟),确保能进行基本的读写测试。然后逐步收紧时序,直到找到芯片稳定工作的极限。可以使用一个内存测试算法(如 walking 1/0, checkerboard pattern)来验证SDRAM的稳定性。
3.4 丰富的通信与显示接口
芯片还集成了大量其他外设,极大地扩展了应用可能性:
- LCD控制器:支持4/8/16位6800或8080并行接口,可以直接驱动常见的TFT液晶模块。你需要配置显示时序参数(如水平/垂直同步脉冲宽度、前沿、后沿)、帧缓冲区地址(通常放在SDRAM中)和像素格式(如RGB565)。通过双缓冲技术可以避免屏幕撕裂。
- MCI(SD/MMC/SDIO):用于连接SD卡或Wi-Fi模块(SDIO)。驱动开发需要注意SD协议的状态机,特别是卡识别和初始化的过程。使用DMA进行块传输可以提升读写速度。
- I2S音频接口:两个独立的I2S通道,可用于连接音频编解码器,实现音频播放或录制。需要正确配置时钟分频器,以生成标准的采样率(如44.1kHz, 48kHz)和位时钟。
- 多路I2C、SPI、UART:这些标准接口的驱动开发相对成熟。需要注意的是引脚复用,许多I/O引脚(前缀为
m的,如mGPIO5)功能是可配置的,需要通过IOCONFIG模块寄存器来设置其具体功能(GPIO、UART CTS等)。
4. 系统启动流程与安全机制深度剖析
4.1 灵活的启动选择与Bootloader设计
LPC3141/3143提供了极其灵活的启动方式,这是系统设计的基础。芯片上电后,会采样GPIO0、GPIO1、GPIO2这三个模式引脚的状态,根据其组合来决定从哪个设备加载初始引导程序(Bootloader)。支持的启动源包括:
- SPI Flash
- NAND Flash
- SD/MMC卡
- UART
- USB(作为设备,从主机下载代码)
启动模式选择表
| GPIO2 | GPIO1 | GPIO0 | 启动设备 |
|---|---|---|---|
| 0 | 0 | 0 | SPI Flash (CS0) |
| 0 | 0 | 1 | NAND Flash (CE0) |
| 0 | 1 | 0 | SD/MMC卡 (通道0) |
| 0 | 1 | 1 | UART0 |
| 1 | 0 | 0 | USB (从主机下载) |
| 1 | 0 | 1 | 保留 |
| 1 | 1 | 0 | 保留 |
| 1 | 1 | 1 | 内部测试模式 |
重要提示:为了确保
GPIO0/1/2在上电复位时被正确识别为输入模式(而非被内部JTAG逻辑干扰),必须保证TRST_N和JTAGSEL这两个引脚在电源稳定期间保持低电平。我建议在PCB设计时,用下拉电阻(如10kΩ)将这两个引脚连接到地。
Bootloader的设计是关键。一个典型的二级Bootloader流程是:
- 一级ROM代码:芯片内部有128KB的ROM,其中固化了一段初始代码。它会根据启动模式引脚,从相应外设读取最前面的少量代码(通常为4KB)到内部SRAM中执行。这部分代码通常由NXP提供或需要用户编写,功能极其精简。
- 二级用户Bootloader:被加载到SRAM的这第一段代码,就是你的用户Bootloader。它的职责是初始化更复杂的外设(如SDRAM控制器、时钟),然后将位于外部存储器(如NAND Flash)中的完整应用程序或操作系统镜像,搬运到SDRAM或内部SRAM的指定地址,最后跳转执行。
对于LPC3143,还可以利用其AES引擎实现安全启动。即,存储在外部Flash中的应用程序镜像是经过AES加密的。Bootloader在将其加载到内存后,先通过硬件AES引擎解密,再执行。这样即使有人物理上读取了Flash内容,得到的也是密文,无法直接分析或篡改你的固件。
4.2 基于AES与OTP的安全启动实现(LPC3143)
LPC3143的安全特性是其区别于LPC3141的核心。它包含一个AES-128解密引擎和一个一次可编程(OTP)存储器。OTP中有一个128位的区域专门用于存储AES密钥,这个区域在编程后无法被任何方式(包括JTAG)读取,提供了极高的密钥安全性。
实现安全启动的步骤大致如下:
- 密钥烧写:在芯片生产或初次配置时,通过特定的编程流程(通常需要配合NXP提供的工具和较高的VPP电压),将你的128位AES密钥安全地烧写到OTP的密钥区域。这个过程是不可逆的,务必确保密钥备份无误。
- 固件加密:在开发主机上,使用相同的AES密钥(例如使用OpenSSL工具)对你的应用程序二进制文件进行加密。加密模式需要与硬件引擎匹配(通常是ECB或CBC模式)。
- Bootloader准备:你的二级Bootloader需要配置NAND控制器,在读取Flash数据时使能AES解密功能,并指向OTP中的密钥。控制器会在数据从Flash读出到内部缓冲区的过程中自动完成解密。
- 启动验证:Bootloader将解密后的镜像搬运到执行地址并跳转。如果密钥错误或镜像被篡改,解密出的将是乱码,CPU会执行无效指令而崩溃,从而阻止了非授权代码的运行。
这种机制非常适合保护产品的核心算法和防止固件被抄袭。但需要注意的是,AES引擎仅用于解密,不支持加密。因此加密过程必须在安全的开发环境中离线完成。
5. 硬件设计要点与PCB布局实战指南
5.1 电源树设计与去耦电容布局
为LPC3141/3143设计一个干净、稳定的电源是项目成功的先决条件。芯片有多个电源引脚,必须根据数据手册的要求仔细处理:
电源分离与连接:
- VDDI (SUP1):数字核心1.2V。需要非常干净的电源。建议使用一个专用的LDO或DC-DC转换器。去耦电容要足够,通常在芯片每个VDDI引脚附近放置一个0.1uF的陶瓷电容,并在电源入口处放置一个10uF的钽电容或大容量陶瓷电容。
- VDDE_IOC (SUP3):3.3V I/O电源。这是大多数外设(如UART, I2C, SPI, 部分USB)的电源。可以与板上其他3.3V器件共用电源,但需注意电流需求。
- VDDE_IOA (SUP4) & VDDE_IOB (SUP8):分别为NAND接口和SDRAM/LCD接口供电。如前所述,当使用SDRAM时,这两组电源必须短接并连接到同一电压轨。电压可以是1.8V或3.3V,取决于你使用的存储器芯片电压。
- 模拟电源 (VDDA12, VDDA33):为内部PLL、ADC、USB PHY等模拟电路供电。这些电源的噪声会直接影响时钟稳定性和模拟性能。务必使用磁珠(Ferrite Bead)或0Ω电阻从数字电源隔离出来,并搭配LC滤波电路。每个模拟电源引脚到模拟地(VSSA)之间都应放置0.1uF和1uF的电容。
接地策略:芯片有多个地引脚(VSSI, VSSE_IOx, VSSA)。理想情况下,应该使用一个完整的接地层。所有地引脚都应通过过孔直接连接到内部接地层。模拟地(VSSA)和数字地(VSSI)在芯片内部已经分离,在PCB上,建议在靠近芯片的位置用磁珠或0Ω电阻单点连接,以防止数字噪声串扰到敏感的模拟电路。
5.2 关键信号布线规则与阻抗控制
- USB差分对 (USB_DP/USB_DM):这是板上最高速的信号线(480 Mbps)。必须作为差分对布线,严格控制等长(长度差建议小于5mil),并保持连续的参考平面(通常是地平面)。差分阻抗应控制在90欧姆±10%。走线应尽量短,避免过孔,远离时钟和其他噪声源。
- SDRAM信号:包括时钟(SDCLK)、数据(DQ)、地址(ADDR)、控制(RAS, CAS, WE, CS)线。时钟线是关键,应优先布线,并与其他信号线保持3W(三倍线宽)以上的间距,必要时进行包地处理。数据线应分组(如高8位、低8位)并保持组内等长,地址和控制线也应尽量等长。所有SDRAM信号线的长度应尽可能匹配,偏差控制在几十皮秒以内(例如,对应1英寸的走线长度差)。
- 时钟信号 (FFAST_IN/OUT):外部12MHz晶振的连接线应尽可能短,并用地线包围。晶振外壳要接地。负载电容要尽可能靠近晶振引脚放置,其容值需根据晶振的负载电容要求精确计算。
- NAND Flash信号:虽然速度不如SDRAM,但为了信号完整性,控制线(CLE, ALE, CE, WE, RE)和数据线也应尽量短。
NAND_RYBN(就绪/忙)信号是开漏输出,需要上拉电阻。
5.3 散热与封装考虑
芯片采用TFBGA180封装,尺寸为12x12mm,球间距0.8mm。这意味着PCB需要至少4层板才能有足够的布线通道,并且需要激光打孔(微孔)工艺。在芯片底部中心区域,有一个裸露的散热焊盘(Thermal Pad),这个焊盘必须连接到地平面,并通过多个过孔阵列连接到PCB底层的地平面,以提供良好的散热和机械固定。在焊接时,需要使用精确的钢网和回流焊曲线,确保所有焊球都能良好焊接,避免虚焊。
6. 软件开发环境搭建与调试技巧
6.1 工具链选择与工程配置
对于ARM926EJ-S,主流的开发工具链有:
- ARM官方工具 (Arm Development Studio, DS-5):功能强大,调试体验好,但商业许可昂贵。
- GNU工具链 (arm-none-eabi-gcc):开源免费,社区支持好,是个人和小团队的首选。你可以通过Yocto Project或自己编译获取,也可以使用预编译的版本(如来自ARM或Linaro)。
- Keil MDK:对于从Cortex-M转过来的开发者可能更熟悉,但需要购买许可证。
我个人的选择是arm-none-eabi-gcc配合CMake或Makefile进行项目管理。启动文件(Startup Code)需要正确初始化:
- 设置异常向量表。
- 关闭看门狗。
- 初始化时钟系统(CGU),配置PLL将外部12MHz晶振倍频到所需的270MHz CPU时钟和90MHz AHB总线时钟。
- 初始化内存控制器(MPMC),配置SDRAM时序。
- 设置栈指针,将.data段从加载地址(如Flash)复制到运行地址(如SRAM/SDRAM),并将.bss段清零。
- 跳转到main函数。
链接脚本(Linker Script)至关重要,它定义了内存布局。你需要根据芯片的内存映射,合理分配代码段(.text)、数据段(.data, .bss)、堆(heap)和栈(stack)的位置。通常,中断向量表和启动代码放在内部SRAM(如0x00000000开始的区域)以获得最快速度,而主应用程序、只读数据等可以放在容量更大的SDRAM中。
6.2 调试接口使用与常见问题排查
芯片支持标准的JTAG接口进行调试和编程。你需要一个JTAG调试器,如J-Link、ULINK2或开源的OpenOCD配合FT2232H模块。
连接时需注意的引脚:
TCK,TMS,TDI,TDO:标准JTAG信号。TRST_N:JTAG复位,低电平有效。必须通过下拉电阻接地,以确保上电后JTAG接口处于确定状态。JTAGSEL:这个引脚控制SCAN_TDO和ARM_TDO信号的输出功能。同样建议下拉接地,除非你有特殊的扫描链需求。
调试中常见的棘手问题及排查思路:
芯片无法连接或识别(IDCODE错误):
- 检查电源:用万用表测量所有电源引脚电压是否稳定且在规定范围内,特别是核心电压1.2V。
- 检查复位电路:
RSTIN_N引脚在正常工作时应为高电平。确保复位电路没有误触发。 - 检查JTAG连线:确认
TCK、TMS、TDI、TDO、TRST_N连接正确且牢固。TRST_N和JTAGSEL是否已下拉。 - 检查启动模式:确保
GPIO0/1/2的上拉/下拉电阻配置正确,没有意外进入USB下载或其他非预期模式。
程序在SDRAM中运行不稳定(随机崩溃):
- 首要怀疑对象是时序:回到MPMC配置,增加
tRP、tRCD、tRC等时序参数的值,看问题是否消失。如果消失,说明原时序太紧。 - 检查电源完整性:用示波器探头(最好用接地弹簧)测量SDRAM电源引脚(VDDE_IOB)和芯片的SDRAM接口电源,观察在大量内存访问时是否有明显的电压跌落或毛刺。增加去耦电容。
- 检查PCB布线:审视SDRAM时钟线和数据线的布线,是否有过长的走线、锐角、或者参考平面不完整的情况。
- 运行内存测试:编写一个严格的内存测试程序(如反复写入并读取特定的数据模式),在启动初期运行,以确认SDRAM硬件和配置是否可靠。
- 首要怀疑对象是时序:回到MPMC配置,增加
USB枚举失败或不稳定:
- 检查USB差分线:使用示波器观察
USB_DP和USB_DM的波形。高速信号应是一对干净、幅值对称的差分信号。检查阻抗是否连续,有无stub(短线头)。 - 检查USB_VBUS:确保主机提供了正确的5V VBUS电压。
- 软件排查:在USB中断服务例程中设置断点,查看设备是否收到了主机发送的复位信号、获取描述符请求等。逐步跟踪枚举过程。确保描述符大小和内容完全符合USB规范。
- 检查USB差分线:使用示波器观察
NAND Flash读写错误或ECC纠错频繁:
- 确认Flash型号和支持:检查你使用的NAND Flash是否在控制器的支持列表内(主要是时序兼容)。MLC Flash比SLC需要更强的ECC。
- 检查硬件连接:确认所有控制线和数据线连接正确,
NAND_RYBN信号有上拉。 - 调整时序:和SDRAM类似,尝试放宽NAND控制器的读写时序参数。
- 分析ECC统计:读取ECC模块的纠错统计寄存器,如果发现每页纠错符号数持续很高,可能意味着Flash质量不佳、即将损坏,或者硬件连接(如焊接)有问题。
开发这类高度集成的微控制器,一半是软件功夫,一半是硬件功底。耐心、细致的调试,以及对数据手册的深入理解,是成功驾驭LPC3141/3143这类芯片的不二法门。它可能不是最新最快的芯片,但其高度的集成度和经过验证的稳定性,在成本敏感且功能要求全面的嵌入式项目中,依然是一个极具竞争力的选择。