《利用与硬件无关的方法简化嵌入式系统设计:基本知识》

  • 来源专题:智能制造
  • 编译者: icad
  • 发布时间:2025-02-24
  • 摘要

    本文将演示一种加速嵌入式系统设计原型阶段的方法,说明如何将与硬件无关的驱动程序和传感器结合使用,简化整个嵌入式系统的器件选择。同时还将介绍嵌入式系统的器件、典型软件结构以及驱动程序的实现。后续文章“利用与硬件无关的方法简化嵌入式系统设计:驱动程序实现”将进一步探讨执行过程。

    简介

    通过使用与硬件无关的驱动程序,设计人员可以自由选择微控制器或处理器的类型来管理传感器,而不受硬件的限制。这种方法的优势在于,除了供应商提供的基本软件层外,还可以添加额外的软件层,同时简化传感器的集成。本文将以惯性测量单元(IMU)传感器为例,说明如何实现与硬件无关的驱动程序,不过,这种方法同样适用于其他类型的传感器和器件。驱动程序采用C语言编写,并在一款通用微控制器上进行了测试。

    器件选择

    IMU传感器主要用于运动检测,以及通过加速度和角速度来测量运动强度。本示例选择使用ADIS16500  IMU传感器(图1),因为与复杂且昂贵的分立设计方案相比,该传感器能够为精确的多轴惯性检测与工业系统的集成提供简单且经济高效的方法。

    图1.ADIS16500评估板。

    主要应用包括:

    ▲导航、稳定性和仪器仪表

    ▲无人机和自动驾驶车辆

    ▲智能农业和施工机械设备

    ▲工厂/工业自动化、机器人

    ▲虚拟/增强现实

    ▲运动物联网

    图2.ADIS16500框图。

    ADIS16500是一款精密微型机电系统(MEMS) IMU,内置一个三轴陀螺仪、一个三轴加速度计和一个温度传感器。参见图2。该IMU的灵敏度、偏置、对准、线性加速度(陀螺仪偏置)和坐标轴原点(加速度计位置)已在工厂校准。这意味着在各种条件下都能提供精确的传感器测量。

    通过该接口,微控制器可以写入和读取用户控制寄存器,并读取输出数据寄存器,从而获得加速度计、陀螺仪或温度传感器数据。为此,管理该接口所需的全部软件和固件均已完成开发。图2所示为数据就绪(DR)引脚。该引脚是一个数字信号,指示何时可从传感器读取新数据。DR引脚可被视为通过通用输入/输出(GPIO)端口的输入,因此可通过微控制器轻松管理。

    从硬件的角度来看,IMU传感器和微控制器将使用SPI接口连接,该接口是由nCS、SCLK、DIN和DOUT引脚组成的4线接口。DR引脚应连接到微控制器的其中一个GPIO。此外,IMU传感器需要3 V至3.6 V的电源电压,因此3.3 V就足够了。

    了解嵌入式系统的典型软件结构

    图3.嵌入式系统的软件/固件结构。

    了解嵌入式系统的通用软件和固件结构对于与传感器驱动程序连接至关重要。这将帮助设计人员构建一个灵活且易于集成到任何项目的软件模块。此外,驱动程序必须以模块化的方式实现,以使设计人员能够依赖于现有函数添加更高级的函数。

    嵌入式系统的软件结构如图3所示。在图3中,层次结构从应用层开始,应用代码就是在这一层编写的。应用层包括main文件、依赖于传感器的应用模块,以及依赖于管理处理器配置的外设驱动程序的模块。此外,在应用层中,还有与微控制器必须处理的任务相关的所有模块。例如,通过中断或轮询、状态机等管理任务的所有软件。应用层级别根据项目的类型而有所不同,因此不同项目中实现的代码也不同。在应用层,系统的所有传感器根据其数据手册进行初始化和配置。传感器驱动程序提供的所有公共函数均可调用。例如,读取负责输出数据的寄存器,或者写入一个寄存器以更改设置/校准的程序。

    应用层下面是传感器的驱动层,这一层有两种类型的接口。可从应用层调用的所有函数都在这一层实现。此外,函数的原型插入到驱动程序标头文件(。h)中。因此,通过查看传感器驱动程序的标头文件,您可以了解驱动程序的接口以及可从较高层级调用的函数。较低级别的层将与特定外设驱动程序连接,这些外设驱动程序依赖于管理传感器的微控制器。外设驱动程序包括管理微控制器外设的所有模块,例如SPI、I2C、UART、USB、CAN、SPORT等,或管理处理器内部模块的模块,例如定时器、内存、ADC等。由于它们与硬件紧密相关,因此称为低级函数。例如,由于微控制器不同,因此每个SPI驱动程序都是不同的。我们以ADIS16500为例。接口是SPI,因此其驱动程序将与微控制器的SPI驱动程序封装在一起。对于不同的传感器和不同的接口也是如此。例如,如果另一个传感器具有I2C接口,那么同样地,将在传感器的初始化过程中与微控制器的I2C驱动程序封装一起。

    传感器驱动程序的下层是外设驱动程序,各类微控制器的外设驱动程序各不相同。如图3所示,外设驱动程序和低级驱动程序是分开的。本质上,外设驱动程序通过可用的通信协议提供读写函数。由于低级驱动程序将管理信号的物理层,因此它非常依赖于设计人员所使用的硬件。外设和低级驱动层往往通过可视化工具从微控制器的集成开发环境(IDE)生成,具体取决于安装微控制器的评估板。

    驱动程序实现

    与硬件无关的方法支持在不同应用、不同微控制器或不同处理器中使用相同的驱动程序。这种方法取决于驱动程序的实现方式。要了解驱动程序的实现方式,首先要看接口,或图4中的传感器标头文件(adis16500.h)。

    标头文件包含有用的公共宏。其中包括寄存器的地址、SPI最大速度、默认输出数据速率(ODR)、位掩码,以及加速度计、陀螺仪和温度传感器的输出灵敏度,这些宏与用于表示数据的位数(16或32)有关。图4显示了这些宏,其中仅显示了几个寄存器的地址作为示例。本文引用的代码可参见附录。

    图4.ADIS16500标头文件(adis16500.h)中显示的宏。

    附录中的图3显示了包括adis16500.h在内的每个模块均可使用的所有公共变量和公共类型声明,其中定义了新的类型,以便更有效地管理数据。例如,ADIS16500_XL_OUT类型被定义为包含三个浮点的结构,每个轴(x、y和z)一个浮点。此外,还通过枚举来支持不同的传感器配置,使设计人员能够灵活地选择符合自身需求的配置。最值得关注的是使驱动程序与硬件无关的部分。在公共变量部分的开头(附录中的图3),有三个关键的类型定义:指向三个基本函数的指针,或者SPI发送和接收函数,以及为生成正确的停转时间,两次SPI访问之间所需的延迟函数。这些代码还显示了可指向的函数的原型。SPI发送函数将指向待发送值的指针作为输入,然后返回可供检查的内容,以确定发送是否成功。SPI接收函数也是如此,该函数将指向变量的指针作为输入,这个指针将存储接收时读取的值。延迟函数以浮点数作为输入,表示设计人员想要等待的微秒数,不返回任何内容(void)。通过这种方式,设计人员可以在应用层(例如在main文件中)利用这些特定的原型来声明这三个函数。声明后,他们可以将这三个函数赋值给ADIS16500_INIT私有结构的字段。附录中的图2列举了一个示例,以帮助更好地理解最后一步。

    SPI发送器、接收器函数和延迟函数在main文件中声明为静态函数,因此属于应用层。这些函数依赖于外设驱动程序函数,因此传感器驱动程序本身与硬件无关。这三个函数被分配给一个变量的字段,而这些字段是指向函数的指针。这样一来,设计人员可以封装传感器和微控制器,而无需修改传感器驱动程序代码。如果设计人员更换微控制器,他们只需将三个静态函数内的低级函数替换为新微控制器的相应函数,从而调整main文件。通过这种方法,驱动程序变得与硬件无关,因为设计人员不需要更改传感器的驱动程序代码。微控制器的IDE中通常包含spiSelect、spiReceive、spiUnselect、chThdSleepMicroseconds等低级函数。在本例中,所用的微控制器评估板是SDP-K1,它嵌入了STM32F469NIH6 Cortex?-M4微控制器。该IDE是ChibiOS,这是一个免费的Arm?开发环境。

    附录中的图4显示了应用级别的可调用函数原型。这些原型以及附录中图2和图3讨论的所有其他软件和固件都可在传感器驱动程序的标头文件(adis16500.h)中找到。首先,初始化函数(adis16500_init)将指向ADIS16500_INIT结构的指针作为输入,并返回状态代码,以指示初始化是否成功。初始化函数的实现在传感器驱动程序的源文件(adis16500.c)中完成。附录中的图5所示为adis16500_init函数的代码。首先,定义名为ADIS16500_PRIV的类型,其中至少包含ADIS16500_INIT结构的所有字段,然后声明一个属于该类型的私有变量_adis16500_priv。在初始化函数中,应用层传递的ADIS16500_INIT结构的所有字段将赋值给私有变量_adis16500_priv的字段。这意味着,对传感器驱动程序的任何后续调用都将使用由应用层传入的SPI读写函数和处理器延迟函数。这一点很关键,正因如此,传感器驱动程序才能与硬件无关。如果设计人员想要更改微控制器,只需更改传递给adis16500_init函数的函数即可,不需要修改传感器驱动程序代码本身。在初始化函数开头,_adis16500_priv变量的已初始化字段设置为false,因为初始化过程尚未完成。在该函数结束时,该字段将设置为true,然后返回。设计人员每次调用另一个公共函数(附录中的图4)时,都会执行以下检查:如果_adis16500_priv.initialized为true,可以继续;如果为false,将立即返回ADIS16500_RET_VALERROR错误。这是为了防止用户在没有先初始化传感器驱动程序的情况下调用函数。继续讨论初始化函数,执行以下步骤:

    1.通过读取ADIS16500_REG_ PROD_ID寄存器,检查预先已知的产品ID。

    2.将应用层(main.c)传递的值写入ADIS16500_REG_MSC_CTRL寄存器的相应位字段,设置数据就绪(DR)引脚极性。

    3.将应用层(main.c)传递的值写入ADIS16500_REG_MSC_CTRL寄存器的相应位字段,设置同步模式。

    4.将应用层(main.c)传递的值写入ADIS16500_REG_DEC_RATE寄存器,设置抽取率。

    初始化函数取决于读写寄存器函数(附录中的图6)。因此,为_adis16500_priv变量赋值之后,需要完成上述四个例程。否则,在调用读取或写入寄存器函数时,它们不知道该使用哪个SPI发送器、接收器和处理器延迟函数。

    参考附录中的图4,在初始化函数之后,还可以调用其他公共函数。下面是已实现例程的功能描述,所示为低级别例程。本文的第二部分将详细介绍驱动程序的其他已实现函数。以下所有函数只能在初始化函数之后调用。为此,将在每个函数开头仔细检查,以确定传感器是否已初始化。如果未初始化,程序会立即返回错误。

    ▲adis16500_rd_reg_16

    该函数用于读取16位寄存器。该函数实现可参见附录中的图6。输入包括ad,这是一个uint8_t变量,表示要读取的寄存器的地址,以及*p_reg_val,这是指向uint16_t类型变量的指针,表示读取值将赋值的目标。要通过SPI协议读取寄存器,需要访问两次SPI;第一次访问是为了发送地址,第二次是为了读回被寻址寄存器的值。两次访问之间需要有停转时间,因此需要延迟函数。在第一次访问过程中,我们发送读/写位,在本例中为1(R = 1,W = 0),寄存器地址移位8位,再补充8位0,因此序列如下:

    R/W | AD6 | AD5 | AD4 | AD3 | AD2 | AD1 | AD0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |

    其中AD代表地址,R/W代表读/写位。

    经过延迟后,函数通过SPI读取值,并将该值传递给输入指针。ADIS16500的寄存器具有一个包含高位值(8个最高有效位)的高地址和一个包含低位值(8个低有效位)的低地址。为了获得16位的完整值(低位和高位),使用低地址作为ad已经足够,因为低地址和高地址是连续的。

    ▲adis16500_wr_reg_16

    该函数用于写入16位寄存器。该函数实现可参见附录中的图6。输入包括ad,这是一个uint8_t类型变量,表示要写入的寄存器的地址,以及reg_val,这是uint16_t类型变量,表示要写入寄存器的值。对于读取函数,需要考虑低地址和高地址以及低位值和高位值。因此,根据数据手册,要想写入ADIS16500的寄存器,需要在发送时访问两次SPI。第一次访问将发送等于0的R/W位,接着是低寄存器地址,然后是低位值,因此序列如下:

    R/W | AD6 | AD5 | AD4 | AD3 | AD2 | AD1 | AD0 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |,其中D代表数据。

    第二次SPI发送器访问将发送等于0的R/W位,接着是高寄存器地址,然后是高位值,因此序列如下:

    R/W | AD14 | AD13 | AD12 | AD11 | AD10 | AD9 | AD8 | D15 | D14 | D13 | D12 | D11 | D10 | D9 | D8 |。

    写入和读取寄存器函数实际上也可以定义为私有,因此从驱动程序软件模块外部不可见,也不可调用。将它们定义为公共是为了能够调试。这样一来,设计人员能够快速访问传感器中的任何寄存器以进行读取或写入,从而帮助解决问题。

    ▲adis16500_rd_acc

    该函数从输出数据寄存器读取x、y、z加速度数据,并返回它们的值,单位为[m/sec2]。该函数实现可参见附录中的图7。输入是指向ADIS16500_XL_OUT结构的指针,它只嵌入三个字段:以浮点类型表示的x、y、z加速度。在这三个轴上,读取加速度的方式是相同的,唯一的区别在于要读取的寄存器。每个轴有其各自要读取的寄存器:x轴必须在x加速度输出数据寄存器上读取,y和z轴也在相应寄存器上读取。加速度值将用32位值来表示,因此要读取的寄存器有两个。一个读取高16位,一个读取低16位。因此,通过查看代码可知,将进行两次寄存器读取访问,再加上适当的移位和OR位运算,得到整个二进制值并存储在名为_temp的私有int32_t变量中。然后,数据将经过二进制转二进制补码的转换。转换后,用二进制补码值除以灵敏度(单位为[LSB/(m/sec2)]),这样最终将获得以[m/sec2]为单位的加速度值。此值将记录到指针的x、y或z字段,该指针指向已作为输入传递的结构。

    ▲adis16500_rd_gyro

    陀螺仪读取函数与加速度读取函数的实现方法完全相同。毫无疑问,该函数将读取x、y、z陀螺仪数据,单位为[°/sec]。其实现方法可参见附录中的图8。与加速度函数类似,函数的输入是指向ADIS16500_GYRO_OUT结构的指针,该结构嵌入以浮点类型表示的x、y和z陀螺仪数据。读取的寄存器是陀螺仪输出数据寄存器。二进制值将用32位表示,要获得二进制补码值,需要完成与加速度函数相同的步骤。完成二进制到二进制补码转换后,用得到的值除以灵敏度(单位为[LSB/(°/sec)]),最终得到以[°/sec]为单位的值,然后该值将记录到指针的x、y或z字段,该指针指向已作为输入传递的结构。

    结论

    本文阐述了嵌入式系统的典型软件/固件堆栈,介绍了IMU传感器的驱动程序实现。与硬件无关的方法为各种传感器或器件提供了可重复使用的方法,即使接口(SPI、I2C、UART等)不同也没关系。后续文章“利用与硬件无关的方法简化嵌入式系统设计:驱动程序实现”进一步详细解释了传感器驱动程序的实现方法。

  • 原文来源:http://www.chinaaet.com/article/3000170330
相关报告
  • 《嵌入式世界2024:人工智能仍是一大主题》

    • 来源专题:新一代信息技术
    • 编译者:isticzz2022
    • 发布时间:2024-04-23
    •        人工智能加速和tinyML仍然是2024年嵌入式世界的主要主题,许多供应商在硬件和软件方面展示了新的人工智能能力。 Ambiq Apollo 510        Ambiq推出了适用于可穿戴设备和物联网设备的最新一代超低功耗微控制器。与Ambiq的上一代Apollo4相比,Apollo510可以实现10倍的延迟和一半的功耗。Apollo510基于Arm Cortex-M55内核,带有氦矢量单元,可以通过Ambiq的NeuralSpot人工智能工具链运行人工智能模型。Ambiq首席技术官Scott Hanson告诉《EE时报》,一项对客户用例的调查显示,几乎所有的用例都可以由带有额外内存的M55处理,因此Apollo 510配备了4 MB的片上NVM和3.75 MB的SRAM,但在大多数情况下,不需要NPU。Hanson说:“我的观点是在你应该担心NPU之前,模型和软件至少需要进行时间倍的优化。这个特殊的芯片没有NPU,这是我们与客户讨论后做出的决定,”他补充道。“坦率地说,你看到的很多NPU都有寻找问题解决方案。如果你与客户交谈,真正了解他们的需求,他们就不需要NPU。”Hanson表示,由于硬件问题,如窄内存总线与大而宽的MAC单元相比,当今许多NPU实现的利用率都很低。他补充道,NPU将出现在未来的Ambiq产品中,但与此同时,大多数Ambiq客户不想处理多核的复杂性。        NeuralSpot是Ambiq的人工智能工具链,配有优化的模型动物园和Ambiq自己的内核库,用于在其基于Cortex-M的产品上进行高效的人工智能推理。 Efinix Titanium Ti375        FPGA供应商Efinix展示了其第二代中低端FPGA家族Titanium。Efinix营销和业务发展副总裁Mark Oliver告诉《EE时报》,与上一代相比,钛已迁移到16纳米,以实现更低的功率和更小的占地面积,其技术可从35千个逻辑元件扩展到100万个逻辑元件,目前该家族中最大的部分为37.5千个。        Oliver说:“Titanium将我们带到了令人兴奋的地方,因为它将我们带进了一个占地面积,在功率、价格和性能方面都可以从实验室带到大批量开发。得益于人工智能,汽车等行业的边缘计算需求激增。人工智能应用的定制硅将需要3-5年的时间,耗资3000万美元,两个月后你的人工智能模型就会过时。”        在FPGA上开发定制设计可以最大限度地减少NRE和风险。人工智能处理器需要快速总线和实例化人工智能加速器的能力。对于自动驾驶,它们也需要具有确定性,因为你需要快速上市,并具有迭代模型的灵活性。“检查,检查,检查”,他说。Titanium Ti375具有PCIe接口、万兆以太网和双LPDDR4接口,可优化芯片上和芯片下的数据获取。现有的Titanium家族成员,如Titanium 180,可以进行tinyML加速,Efinix的软件堆栈能够从tinyML框架中获取原语,并为FPGA结构创建基于RISC-V的加速器设计。Oliver表示,375的加速器设计和模型可在Github上获得,但人工智能的完整软件工具链仍在建设中,并补充说,Efinix打算在适当的时候使Ti375有资格用于汽车应用。 NXP eIQ Toolchain        恩智浦人工智能总监Ali Ors告诉《EE时报》,虽然英伟达的Tao培训工具包现在可以为来自多个不同供应商的tinyML硬件优化模型,但恩智浦与Tao的集成更进一步。        模型与Tao一起在云中进行训练,然后针对微控制器等边缘设备进行优化。Ors说:“我们确实比单独运行两个工具并在它们之间传递数据更进一步。”。“我们在API级别进行了集成,因此我们的eIQ工具包的用户可以从我们的工具内部启动Tao工具包,查看库,选择模型,重新培训,进行所需的任何迁移学习,然后对其进行配置并将其从eIQ工具包直接部署到NXP设备。”Ors补充道,“这将允许单一环境的用户体验,这将使整个体验更容易。如今,实现是一个赌注,所以它关乎你能为用户带来多容易。这并没有真正简化流程,因为这不是一个简单的流程,但你要尽可能地简化它,并为用户提供尽可能多的分析输入,这是关键部分。”       恩智浦正在构建eIQ的分析功能,以向用户提供有价值的见解,包括他们的模型在边缘运行的情况,他们可以做些什么来提高效率并更好地利用硬件资源,包括恩智浦自己的中子NPU。这可能涉及量化、修剪和稀疏技术,以及建议替换任何不受支持的运算符,以避免回退到CPU。      下一代恩智浦中子NPU将包括更大的加速器以及相应的内存和数据移动优化。Ors表示,与此同时,该公司正在大力投资微控制器和实时交叉处理器的人工智能工具链。 Infineon PSoC Edge E8x        微控制器巨头英飞凌最近推出了其首款带有NPU的微控制器PSoC Edge E8x,该微控制器基于Arm Cortex-M55与Arm Ethos-U55 NPU相结合。英飞凌连接安全系统部门总裁Thomas Rosteck表示,PSoC Edge E8x是即将推出的NPU微控制器系列中的第一款。这将包括为音频等应用程序优化的设备。该公司还收购了tinyML工具链公司Imagimob。       Rosteck说,Arm的Ethos-U55仍然允许Infineon增加价值和差异化。他说:“像Arm这样的生态系统的好处是,它周围有一个由开发者组成的生态系统。我们正在从Arm那里获得核心和加速器,并围绕它构建一个芯片,一个解决方案。这不仅仅是两者之间的总线,你还可以做很多其他事情来提高效率。”       PSoC高性能和低功耗的结合证明了英飞凌对Arm IP的实施。       英飞凌的产品到系统战略意味着该公司在具体决策时同时考虑应用程序和系统的角度,例如工作负载的哪些部分在硬件中完成,哪些部分在软件中完成,以及安全等其他技术。英飞凌也在考虑在未来的设备上运行变压器,但仍处于研究阶段。 Devices and demos       在采用国产NPU IP的xG24无线微控制器取得成功的基础上,Silicon Labs推出了一款新版本xG26,具有双倍的闪存和双倍的RAM。Silicon实验室高级产品营销经理Matt Maupin表示,双倍的RAM对运行ML特别有用,尤其是在语音应用中。       STMicro去年为所有Cortex-M设备开放了NanoEdgeAI Studio autoML工具,但最新版本增加了对所有基于Cortex-M的Arduino板的支持。       瑞萨展示了在其RZ/V2H上运行的各种神经网络,这是其家族中拥有最大NPU实例DRP的部分。演示包括Yolox在一块小板上运行物体检测,无需风扇或任何冷却。在Hailo展台,客户iRider展示了其先进的电动自行车驾驶员辅助系统(ADAS),该系统使用Hailo-8在三个摄像头流上同时运行人工智能。这可以帮助骑自行车的人在交通中看到身后的安全,但也可以实现额外的安全功能,如当用户在人行道上骑自行车或不戴头盔时限制使用。       AMD在其带有NPU的Ryzen Embedded 8000工业处理器上启动了Llama2-7B,并以每秒2.5个代币的速度运行。
  • 《Moortec为Arm的Neoverse N1系统开发平台提供嵌入式监控解决方案》

    • 来源专题:集成电路
    • 编译者:Lightfeng
    • 发布时间:2019-05-04
    • Moortec宣布将其TSMC 7nm FinFET制程上的芯片内监控解决方案提供给新的Arm®(安谋)Neoverse™ N1系统开发平台(SDP)。 作为市场领导者的Moortec乐意将其工艺、电压和温度(PVT)传感子系统技术集成和利用到该平台,从而实现由Arm Neoverse解决方案提供动力支持的新一代云端到边缘基础架构。Neoverse N1 SDP是业界首个7nm基础架构专用系统开发平台,可以通过CCIX互连架构实现非对称计算加速。Moortec和Arm之间的合作创造了一个能够动态感知芯片内状况的解决方案,如此可帮助减少功耗,最大程度优化系统速度并提高设备可靠性。Neoverse N1 SDP能够被硬件和软件开发商用来进行硬件原型设计、软件开发、系统验证、性能分析/调整。 Arm基础设施业务营销副总裁Mohamed Awad表示:“Arm Neoverse解决方案旨在为世界提供云端到边缘基础设施所需的性能和效率。我们与Moortec在N1 SDP测试芯片上的合作展示了IP在Neoverse平台中的应用,加速了基础设施中基于Arm的解决方案的开发和采用。” Moortec首席执行官Stephen Crosher说:“我们正在合作提高Arm在7nm上的下一代计算技术的性能和效率。通过将我们的高精度嵌入式传感结构用于Neoverse N1 SDP的开发,我们使客户能够从机器学习,人工智能和数据分析应用将拥有更高的性能和可靠性。” 关于Moortec Moortec于2005年成立,能够为监控提供引人注目的嵌入式子系统IP解决方案,主要是针对40纳米直至7纳米的高级节点CMOS(互补金属氧化物半导体)技术。Moortec的芯片内传感解决方案支持满足半导体设计领域对提升设备可靠性,以及加强性能优化与改进电源管理控制系统的需求。