SoC 内部的 PWM 模块驱动程序

若要提供对脉冲宽度调节(PWM)控制器的访问,该控制器是 SoC 的一部分,并且内存映射到 SoC 地址空间,需要编写内核模式驱动程序。 驱动程序必须注册 PWM 控制器的设备类接口,以便 UWP 应用可以通过 Windows.Devices.Pwm 命名空间中定义的 PWM WinRT API 访问系统公开的 PWM 设备。

注释

如果具有基于 I2C、SPI 或 UART 控制器的附加 PWM 模块,则可以使用 Windows.Devices.Pwm 和Windows.Devices.Pwm.Provider 命名空间中定义的 API 从 UWP 应用访问该模块。

PWM 设备抽象为单个控制器和一个或多个引脚。 通过 PWM 定义的 IOCTL 控制控制器或引脚。 例如,LCD 显示驱动程序将此类请求发送到 PWM 驱动程序以控制 LCD 反光级别。

多控制器和多通道 PWM 信号生成,具有可配置的周期、极性和负载周期,可实现以下任务:

  • 驱动伺服电机。
  • 驱动 LED 或直流有刷电机等负载。
  • 生成模拟信号。
  • 生成精确的时钟。

本主题介绍,

  • 如何启用对系统公开的 PWM 设备的 UWP 访问。

  • 如何处理 Win32 应用程序或第三方内核模式驱动程序发送的 PWM IOCTL 请求。

预期受众

  • OEM 和 IHV 开发具有 On-SoC PWM 控制器的系统。

上次更新时间

  • 2017 年 8 月

Windows 版本

  • Windows 10 版本

重要的应用程序接口(API)

关于 PWM

PWM 介绍了生成具有调节脉冲宽度的矩形脉冲波的基本技术,从而产生波形平均值的变化。

PWM 波形可以按 2 个参数进行分类:波形周期(T)和负载周期。 波形频率 (f) 是波形周期 f=1/T 的倒数。 值班周期描述“开”或“活动”时间相对于固定间隔或“时间段”的时间比例;低负载周期对应于低输出功率的平均值,因为大部分时间电源都已关闭。 职责周期以百分比表示,其中 100 个% 已完全打开,0% 完全关闭,50% 处于“活动”50%。

司机。

访问系统公开的 PWM 控制器和引脚

PWM 驱动程序必须注册
GUID_DEVINTERFACE_PWM_CONTROLLER作为用于公开和访问 PWM 设备的设备接口 GUID。

// {60824B4C-EED1-4C9C-B49C-1B961461A819} 

DEFINE_GUID(GUID_DEVINTERFACE_PWM_CONTROLLER, 0x60824b4c, 0xeed1, 0x4c9c, 0xb4, 0x9c, 0x1b, 0x96, 0x14, 0x61, 0xa8, 0x19); 

#define GUID_DEVINTERFACE_PWM_CONTROLLER_WSZ L"{60824B4C-EED1-4C9C-B49C-1B961461A819}" 

若要注册设备接口 GUID,驱动程序必须在驱动程序的 EVT_WDF_DRIVER_DEVICE_ADD 回调函数实现中调用 WdfDeviceCreateDeviceInterface。 注册后,系统会向控制器和引脚分配符号链接。

应用程序或其他驱动程序可以通过 PWM 定义的 IOCTL 控制控制器或引脚。 发送 IOCTL 之前,发送方应用程序或驱动程序必须通过指定其符号链接来打开控制器和引脚的文件句柄。 这要求驱动程序注册文件创建和关闭事件。 请参阅(链接)

下面是控制器的符号路径示例:

\??\ACPI#FSCL000E#1#{60824b4c-eed1-4c9c-b49c-1b961461a819}  

同样,引脚的格式如下所示:路径的格式如下所示:

<DeviceInterfaceSymbolicLinkName>\<PinNumber>

其中 <PinNumber> ,要打开的引脚的从 0 开始的索引。

下面是引脚的符号路径示例:

\??\ACPI#FSCL000E#1#{60824b4c-eed1-4c9c-b49c-1b961461a819}\0 ; Opens pin 0 

\??\ACPI#FSCL000E#1#{60824b4c-eed1-4c9c-b49c-1b961461a819}\0001 ; Opens pin 1 with the leading 0s have no effect.

若要打开文件句柄,应用程序必须调用 Configuration Manager API(CM_Get_Device_Interface_*)。

打开文件句柄后,应用程序可以通过调用 DeviceIoControl 函数发送这些请求。 请参阅 PWM 部分。

驱动程序应使用提供的 PWM 支持例程 PwmParsePinPath 来分析和验证引脚路径并提取引脚编号。

设置设备接口属性

若要从 UWP 应用使用 PWM WinRT API,必须设置这些 设备接口属性

  • DEVPKEY_DeviceInterface_Restricted

    根据当前的 UWP 设备访问模型,需要将受限设备接口属性设置为 FALSE,以便 UWP 应用能够访问 PWM 设备接口。

  • DEVPKEY_DeviceInterface_SchematicName(链接?)

    必须为静态连接的 PWM 设备接口分配一个示例名称,以便使用 PwmController.GetDeviceSelector(FriendlyName) 工厂方法。 示意图名称是在系统设计示意图(PWM0、PWM_1等)中提供给 PWM 设备的名称。 假定示意图名称在整个系统中是唯一的,但未强制实施。 至少,不应有 2 个 PWM 设备具有相同的示意图名称,否则 WinRT PWM PwmController.GetDeviceSelector(FriendlyName) 行为将是不确定的。

可以通过以下两种方式之一设置属性:

  1. 使用 PWM 驱动程序的 INF 文件

    使用 AddProperty 指令设置设备属性。 INF 文件应允许为 PWM 设备实例的一个或多个子集上的相同属性设置不同的值。 下面是设置DEVPKEY_DeviceInterface_Restricted的示例。

    ;***************************************** 
    ; Device interface installation 
    ;***************************************** 
    
    [PWM_Device.NT.Interfaces] 
    AddInterface={60824B4C-EED1-4C9C-B49C-1B961461A819},,PWM_Interface 
    
    [PWM_Interface] 
    AddProperty=PWM_Interface_AddProperty 
    
    ; Set DEVPKEY_DeviceInterface_Restricted property to false to allow UWP access 
    ; to the device interface without the need to be bound with device metadata. 
    ; If Restricted property is set to true, then only applications which are bound 
    ; with device metadata would be allowed access to the device interface. 
    
    [PWM_Interface_AddProperty] 
    {026e516e-b814-414b-83cd-856d6fef4822},6,0x11,,0 
    

    并非所有设计都具有将 PWM 设备公开到 UWP 的相同策略。 例如,策略可能是允许 UWP 访问 PWM 设备实例的子集。 公开 PWM 设备的子集或为一个或多个 PWM 设备实例分配不同的属性值需要为每个 PWM 设备实例使用不同的硬件 ID,并根据策略选择性地匹配 INF 部分。

    请考虑一种基于 SoC 的设计,其中四个相同的 PWM 设备实例(IP 块)名为 PWM0,...,PWM3,其中 ACPI 分配的硬件 ID (_HID) FSCL00E0,其唯一 ID (_UID) 为 0,...,3。 将所有 PWM 设备向 UWP 公开,需要在 INF 部分中设置 DEVPKEY_DeviceInterface_Restricted 以匹配硬件 ID ACPI\FSCL00E0。

    这种设置属性的方式不需要在驱动程序代码中进行任何更改。 这是一个更简单的选项,因为为 INF 文件提供服务比驱动程序二进制文件更容易。 缺点是,这种方法需要为每个设计定制 INF 文件。

  2. 在 PWM 驱动程序中以编程方式进行操作

    PWM 驱动程序可以调用 IoSetDeviceInterfacePropertyData,以在创建和发布 PWM 设备接口后在其EVT_WDF_DRIVER_DEVICE_ADD实现中设置设备接口属性。 驱动程序负责决定要分配的值和设备属性。 此信息通常存储在基于 SoC 的设计的系统 ACPI 中。 可以在每个 ACPI 设备节点中指定每个设备接口属性的值,_DSD方法作为设备属性。 驱动程序必须从 ACPI 查询the_DSD,分析设备属性数据,提取每个属性的值,并为其分配设备接口。

    通过编程方式设置属性,使得驱动程序及其 INF 文件能够跨设计和因此跨 BSPs 移植,唯一需要更改的是在 ACPI DSDT 中定义每个 PWM 设备节点。 但是,读取和分析 ACPI 二进制块很繁琐,需要大量的代码,这些代码很容易出错和漏洞,从而导致更大的错误图面。

处理文件打开/关闭事件

PWM 驱动程序需要通过实现EVT_WDF_DEVICE_FILE_CREATE和EVT_WDF_FILE_CLEANUP/EVT_WDF_FILE_CLOSE回调函数来注册文件创建和关闭事件。 在实现中,驱动程序必须执行以下任务:

  1. 确定创建请求是针对控制器还是引脚。

  2. 如果请求适用于引脚,驱动程序必须分析并验证用于创建引脚请求的引脚路径,并确保请求的引脚编号位于控制器边界内。

  3. 授予或拒绝对控制器和引脚创建请求的访问权限。

  4. 根据定义良好的状态机维护控制器和引脚状态的完整性。

在前面的一组任务中,可以在EVT_WDF_DEVICE_FILE_CREATE中执行第二个验证任务,如下所示:

  1. 如果与请求文件对象关联的文件名为 null,则使用 STATUS_INVALID_DEVICE_REQUEST 完成请求。

  2. 如果与请求文件对象关联的文件名是空字符串,则这是控制器创建请求,否则为 pin 创建请求。

  3. 如果这是创建固定的请求,则:

    1. 根据<DecimalName>格式解析管脚路径,并通过调用 PwmParsePinPath 提取引脚编号。

    2. 如果分析和验证PIN路径失败,请使用STATUS_NO_SUCH_FILE完成请求。

    3. 如果引脚数大于或等于控制器引脚计数,则使用STATUS_NO_SUCH_FILE完成请求。 请注意,引脚编号是从零开始的索引。

    4. 否则,请继续处理EVT_WDF_DEVICE_FILE_CREATE。

下面是实现前面提到的EVT_WDF_DEVICE_FILE_CREATE处理程序验证步骤的示例代码:

EVT_WDF_DEVICE_FILE_CREATE PwmEvtDeviceFileCreate;

VOID 

PwmEvtDeviceFileCreate ( 
    WDFDEVICE WdfDevice, 
    WDFREQUEST WdfRequest, 
    WDFFILEOBJECT WdfFileObject 
    ) 
{ 

    UNICODE_STRING* filenamePtr = WdfFileObjectGetFileName(WdfFileObject); 
    IMXPWM_DEVICE_CONTEXT* deviceContextPtr = PwmGetDeviceContext(WdfDevice); 
    NTSTATUS status; 
    ULONG pinNumber; 

    // 
    // Parse and validate the filename associated with the file object 
    // 

    bool isPinInterface; 

    if (filenamePtr == nullptr) { 

        WdfRequestComplete(WdfRequest, STATUS_INVALID_DEVICE_REQUEST); 

        return; 

    } else if (filenamePtr->Length > 0) { 

        // 
        // A non-empty filename means to open a pin under the controller namespace 
        // 

        status = PwmParsePinPath(filenamePtr, &pinNumber); 

        if (!NT_SUCCESS(status)) { 

            WdfRequestComplete(WdfRequest, status); 

            return; 

        } 


        if (pinNumber >= deviceContextPtr->ControllerInfo.PinCount) { 

            WdfRequestComplete(WdfRequest, STATUS_NO_SUCH_FILE); 

            return; 

        } 


        isPinInterface = true; 

    } else { 

        // 
        // An empty filename means that the create is against the root controller 
        // 

        isPinInterface = false; 
    } 

    // 
    // Continue request processing here 
    // 
} 

控制器和引脚共享

控制器和引脚的共享模型遵循多个读取器单编写器模式。 可以打开控制器/引脚供多个调用方读取,但一次只有一个调用方可以打开该控制器/引脚进行写入。

打开文件句柄时,可以使用 Desired Access 和共享访问标志的组合来实现该模型。 DDI 共享模型选择更简单的共享语义,其中仅使用 Desired Access 规范来控制访问。 共享访问规范在共享模型中没有任何作用,即使在打开控制器或引脚时指定,也不会被遵循。

在EVT_WDF_DEVICE_FILE_CREATE中,应该提取和验证创建请求的期望访问权限和共享访问权限。这一过程应基于控制器/引脚状态或者如下所示:

  1. 如果共享访问不是 0,则拒绝访问,并使用 STATUS_SHARING_VIOLATION完成请求。

  2. 如果 Desired Access 用于只读,则授予访问权限并继续处理EVT_WDF_DEVICE_FILE_CREATE。

  3. 如果 Desired Access 用于写入,则:

如果控制器/引脚已打开进行写入,则拒绝访问,并使用STATUS_SHARING_VIOLATION完成请求,否则授予访问权限,将控制器或引脚标记为已打开进行写入并继续处理EVT_WDF_DEVICE_FILE_CREATE。

以下示例演示如何从创建请求中提取所需访问权限和共享权限:

void 
PwmCreateRequestGetAccess( 
    _In_ WDFREQUEST WdfRequest, 
    _Out_ ACCESS_MASK* DesiredAccessPtr, 
    _Out_ ULONG* ShareAccessPtr 
    ) 
{ 

    NT_ASSERT(ARGUMENT_PRESENT(DesiredAccessPtr)); 

    NT_ASSERT(ARGUMENT_PRESENT(ShareAccessPtr)); 


    WDF_REQUEST_PARAMETERS wdfRequestParameters; 

    WDF_REQUEST_PARAMETERS_INIT(&wdfRequestParameters); 

    WdfRequestGetParameters(WdfRequest, &wdfRequestParameters); 


    NT_ASSERTMSG( 

        "Expected create request", 
        wdfRequestParameters.Type == WdfRequestTypeCreate); 


    *DesiredAccessPtr = 
        wdfRequestParameters.Parameters.Create.SecurityContext->DesiredAccess; 

    *ShareAccessPtr = wdfRequestParameters.Parameters.Create.ShareAccess; 
} 

控制器与引脚的独立性

控制器和引脚具有父子关系。 若要打开引脚,必须先打开其父控制器。 另一种方法是查看引脚是独立实体,其中其父控制器仅向引脚提供一个服务,该服务为该控制器中包含的所有引脚设置全局 PWM 周期。

以下是一些示例场景:

  • 单进程访问:

    • 进程 A 可以打开引脚,设置其工作周期,使用控制器默认周期启动它,稍后打开控制器并按需设置其周期。 如果应用程序的默认时间段正常,则它可能永远不需要打开控制器。

    • 进程可以有多个线程,其中每个线程控制同一控制器下的不同引脚。

  • 多进程访问:

    • 命令行实用工具可以打开具有只读访问权限的控制器,以便向控制台显示信息。 同时,后台 UWP 任务可以打开控制器进行写入,并且使用单个引脚控制某些 LED。

    • 内核模式显示驱动程序,通过 Pin0 控制 LCD 反光,同时按住控制器进行写入和锁定 PWM 期间。 同时,Win32 服务使用显示驱动程序设置的 PWM 周期,并使用 Pin1 使某些 LED 变暗,以向用户传达一些状态。

请注意,独立于引脚打开和关闭控制器有一些重要的影响。 有关详细信息,请参阅关于状态机的章节。

控制器和引脚状态机

控制器状态定义

状态特征 默认值 DESCRIPTION
Is-Opened-For-Write False 表示控制器已关闭或已打开进行读取;True 表示它已打开进行写入。
Desired-Period 最小周期

控制器状态机。

下面的控制器状态机仅以 Is-Opened-For-Write 状态为中心。 所需的时间段值也会被省略,因为它不会影响在控制器上可以执行的操作类型。 请注意,每当打开写入的控制器被打开以供写入的调用方关闭时,控制器将重置为其默认值(默认所需时间段)。

引脚状态定义

状态特性 默认值 DESCRIPTION
Is-Opened-For-Write False 表示引脚已关闭或已打开以进行读操作;True 表示引脚已打开以进行写操作。
Active-Duty-Cycle 0
Is-Started False 指示已停止;True 表示已启动。

引脚状态机。

引脚状态机以 2 种状态 Is-Opened-For-Write 和 Is-Started 的组合为中心。 其他引脚状态(如极性和主动值周期)被排除在外,因为它们的值不会影响可在引脚上执行的作类型。 请注意,每当用于写入的引脚被打开写入的调用方关闭时,引脚将恢复为默认值状态(停止、默认极性和默认工作周期)。 请注意,Set-Polarity 在 Is-Started 为 true 的状态中的转换被排除在外,因为在该状态下无效。

对于给定状态未提及的任何转换都意味着此类转换无效或不可行,相应的请求应以适当的错误状态完成。

状态转换的实现注意事项

  • 在EVT_WDF_DEVICE_FILE_CREATE中,驱动程序应根据创建请求所需的访问权限以及控制器或引脚 Is-Opened-For-Write 状态授予或拒绝访问权限,如下所示:

    如果请求具有所需的写入权限并且控制器/引脚已经为写入打开,则使用STATUS_SHARING_VIOLATION完成请求,否则将控制器/引脚标记为已为写入打开(Is-Opened-For-Write = true),授予访问权限并继续处理。

    此示例为EVT_WDF_DEVICE_FILE_CREATE处理程序实现前面提到的访问验证步骤,其中省略处理并发文件创建请求所需的锁定逻辑:

    //
    // Verify request desired access
    //
    
    const bool hasWriteAccess = desiredAccess & FILE_WRITE_DATA;
    
    if (isPinInterface) {
        PWM_PIN_STATE* pinPtr = deviceContextPtr->Pins + pinNumber;
        if (hasWriteAccess) {
            if (pinPtr->IsOpenForReadWrite) {
                PWM_LOG_TRACE("Pin%lu access denied.", pinNumber);
                WdfRequestComplete(WdfRequest, STATUS_SHARING_VIOLATION);
                return;
            }
            pinPtr->IsOpenForReadWrite = true;
        }
        PWM_LOG_TRACE(
            "Pin%lu Opened. (IsOpenForReadWrite = %lu)",
            pinNumber,
            (pinPtr->IsOpenForReadWrite ? 1 : 0));
    
    } else {
        if (hasWriteAccess) {
            if (deviceContextPtr->IsControllerOpenForReadWrite) {
                PWM_LOG_TRACE("Controller access denied.");
                WdfRequestComplete(WdfRequest, STATUS_SHARING_VIOLATION);
                return;
            }
            deviceContextPtr->IsControllerOpenForReadWrite = true;
        }
        PWM_LOG_TRACE(
            "Controller Opened. (IsControllerOpenForReadWrite = %lu)",
            (deviceContextPtr->IsControllerOpenForReadWrite ? 1 : 0));
    }
    
    //
    // Allocate and fill a file object context
    //
    IMXPWM_FILE_OBJECT_CONTEXT* fileObjectContextPtr;
    {
        WDF_OBJECT_ATTRIBUTES wdfObjectAttributes;
        WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(
            &wdfObjectAttributes,
            IMXPWM_FILE_OBJECT_CONTEXT);
    
        void* contextPtr;
        NTSTATUS status = WdfObjectAllocateContext(
                WdfFileObject,
                &wdfObjectAttributes,
                &contextPtr);
        if (!NT_SUCCESS(status)) {
            IMXPWM_LOG_ERROR(
                "WdfObjectAllocateContext(...) failed. (status = %!STATUS!)",
                status);
            WdfRequestComplete(WdfRequest, status);
            return;
        }
    
        fileObjectContextPtr =
            static_cast<IMXPWM_FILE_OBJECT_CONTEXT*>(contextPtr);
    
        NT_ASSERT(fileObjectContextPtr != nullptr);
        fileObjectContextPtr->IsPinInterface = isPinInterface;
        fileObjectContextPtr->IsOpenForWrite = hasWriteAccess;
        fileObjectContextPtr->PinNumber = pinNumber;
    }
    
  • 在EVT_WDF_FILE_CLOSE/EVT_WDF_FILE_CLEANUP中,驱动程序应保持控制器/引脚状态完整性。

    如果文件对象属于为写入而打开的控制器/引脚,则将该控制器/引脚重置为默认状态,并取消对其进行写入的标记(Is-Opened-For-Write = false)。

    此示例为EVT_WDF_DEVICE_FILE_CLOSE处理程序实现前面提到的访问验证步骤,其中省略处理并发文件关闭请求所需的锁定逻辑。

    EVT_WDF_DEVICE_FILE_CLOSE PwmEvtFileClose;
    
    VOID
    PwmEvtFileClose (
        WDFFILEOBJECT WdfFileObject
        )
    {
        WDFDEVICE wdfDevice = WdfFileObjectGetDevice(WdfFileObject);
        PWM_DEVICE_CONTEXT* deviceContextPtr = PwmGetDeviceContext(wdfDevice);
        PWM_FILE_OBJECT_CONTEXT* fileObjectContextPtr = PwmGetFileObjectContext(WdfFileObject);
    
        if (fileObjectContextPtr->IsPinInterface) {
            if (fileObjectContextPtr->IsOpenForReadWrite) {
                const ULONG pinNumber = fileObjectContextPtr->PinNumber;
    
                NTSTATUS status = PwmResetPinDefaults(deviceContextPtr, pinNumber);
                if (!NT_SUCCESS(status)) {
                    PWM_LOG_ERROR(
                        "PwmResetPinDefaults(...) failed. "
                        "(pinNumber = %lu, status = %!STATUS!)",
                        pinNumber,
                        status);
                    //
                    // HW Error Recovery
                    //
                }
    
                NT_ASSERT(deviceContextPtr->Pins[pinNumber].IsOpenForReadWrite);
                deviceContextPtr->Pins[pinNumber].IsOpenForReadWrite = false;
            }
    
            PWM_LOG_TRACE("Pin%lu Closed.", fileObjectContextPtr->PinNumber);
    
        } else {
            if (fileObjectContextPtr->IsOpenForReadWrite) {
                NTSTATUS status = PwmResetControllerDefaults(deviceContextPtr);
                if (!NT_SUCCESS(status)) {
                    IMXPWM_LOG_ERROR(
                        "PwmResetControllerDefaults(...) failed. (status = %!STATUS!)",
                        status);
                    //
                    // HW Error Recovery
                    //  
                }
    
                NT_ASSERT(deviceContextPtr->IsControllerOpenForReadWrite);
                deviceContextPtr->IsControllerOpenForReadWrite = false;
            }
    
            PWM_LOG_TRACE("Controller Closed.");
        }
    }
    

PWM IOCTL 请求

PWM IOCTL 请求由应用程序或其他驱动程序发送,面向控制器或特定引脚。

控制器 IOCTL

锁定 IOCTL

对于每个 IOCTL 请求,PWM 驱动程序必须验证以下内容:

  1. 请求的操作代码 (IOCTL) 对关联的文件对象有效。

  2. 请求输入和输出缓冲区,并确保它们至少是预期的最小大小。

  3. 当前控制器/引脚状态中请求操作的有效性。

  4. 单个输入参数的有效性。 例如:所需的零期是IOCTL_PWM_CONTROLLER_SET_DESIRED_PERIOD的无效参数。

IOCTL 完成状态代码

PWM 驱动程序必须使用适当的状态代码完成 IOCTL 请求。 下面是常见的完成状态代码。 通常,设置一个已经设定值的 IOCTL 操作应始终成功。 例如,设置已设定好的完全相同的时间段、停止已停止的引脚、设置已设定好的极性等。

STATUS_NOT_SUPPORTED

请求的 IOCTL 操作未实现或不受支持。 例如,某些控制器可能不支持设置输出信号的极性。在这种情况下,应该实现IOCTL_PWM_PIN_SET_POLARITY,但对于非默认极性,应返回STATUS_NOT_SUPPORTED。

STATUS_INVALID_DEVICE_REQUEST

IOCTL 请求已发送到错误的目标。 例如,控制器 IOCTL 请求是使用 pin 文件句柄发送的。

STATUS_BUFFER_TOO_SMALL

输入或输出缓冲区大小小于处理请求所需的最小缓冲区大小。 使用 WdfRequestRetrieveInputBuffer 或 WdfRequestRetrieveOutputBuffer 来检索和验证输入输出缓冲区的 WDF 驱动程序可以直接返回其相应的错误状态。 为其定义的输入和/或输出缓冲区的所有 IOCTL 都具有相应的结构,用于描述该缓冲区,其中输入和输出结构名称 分别具有 INPUT 和_OUTPUT后缀。输入缓冲区最小大小为 sizeof(PWMINPUT),而输出缓冲区最小大小为 sizeof(PWM_OUTPUT)。

IOCTL 代码 DESCRIPTION
IOCTL_PWM_CONTROLLER_GET_ACTUAL_PERIOD 检索脉冲宽度调节(PWM)控制器的有效输出信号周期,因为它将在输出通道上测量。 返回PWM_CONTROLLER_GET_ACTUAL_PERIOD_OUTPUT值。 Irp-IoStatus.Status> 设置为以下列表中的值之一。
  • 状态_成功
  • STATUS_NOT_SUPPORTED
  • STATUS_INVALID_DEVICE_REQUEST
  • STATUS_BUFFER_TOO_SMALL
IOCTL_PWM_CONTROLLER_GET_INFO (获取PWM控制器信息) 检索有关脉冲宽度调节(PWM)控制器的信息。 初始化控制器后,此信息不会更改。

调用方应传递一个输出缓冲区,该缓冲区的大小正好是PWM_CONTROLLER_INFO结构的大小。 驱动程序从请求输出缓冲区大小推断结构的版本。

如果缓冲区大小小于最低结构版本的大小,则使用STATUS_BUFFER_TOO_SMALL的 IOCTL 完成状态完成请求。 否则,驱动程序假定可以容纳到提供的输出缓冲区中的最高结构版本,并成功完成请求。

较新的PWM_CONTROLLER_INFO版本具有大于以前版本的字节大小

Irp-IoStatus.Status> 设置为以下列表中的值之一。
  • 状态_成功
  • STATUS_NOT_SUPPORTED
  • STATUS_INVALID_DEVICE_REQUEST
  • STATUS_BUFFER_TOO_SMALL
IOCTL_PWM_CONTROLLER_SET_DESIRED_PERIOD 将脉冲宽度调节(PWM)控制器的输出信号周期设置为建议的值。

PWM 控制器尝试根据其能力设置一个尽可能接近所请求值的周期。 有效期以 IOCTL 输出的形式返回。 稍后可以使用IOCTL_PWM_CONTROLLER_GET_ACTUAL_PERIOD来检索它。

所需的时间段必须大于零(0),并且在控制器支持的时间段范围内。 也就是说,它必须位于 MinimumPeriod 和 MaximumPeriod(包含)的范围内,可以使用 IOCTL_PWM_CONTROLLER_GET_INFO进行检索。

Irp-IoStatus.Status> 设置为以下列表中的值之一。
  • 状态_成功
  • STATUS_NOT_SUPPORTED
  • STATUS_INVALID_DEVICE_REQUEST
  • 状态_参数无效
  • STATUS_BUFFER_TOO_SMALL
IOCTL_PWM_PIN_GET_ACTIVE_DUTY_CYCLE_PERCENTAGE 检索引脚或通道的当前工作周期百分比。 控件代码将百分比作为PWM_PIN_GET_ACTIVE_DUTY_CYCLE_PERCENTAGE_OUTPUT结构返回。

Irp-IoStatus.Status> 设置为以下列表中的值之一。

  • 状态_成功
  • STATUS_NOT_SUPPORTED
  • STATUS_INVALID_DEVICE_REQUEST
  • STATUS_BUFFER_TOO_SMALL
IOCTL_PWM_PIN_SET_ACTIVE_DUTY_CYCLE_PERCENTAGE(设置PWM引脚的活动占空比百分比) 为控制器引脚或通道设置所需的工作周期百分比值。 控件代码将百分比指定为PWM_PIN_SET_ACTIVE_DUTY_CYCLE_PERCENTAGE_INPUT结构。

Irp-IoStatus.Status> 设置为以下列表中的值之一。

  • 状态_成功
  • STATUS_NOT_SUPPORTED
  • STATUS_INVALID_DEVICE_REQUEST
  • STATUS_BUFFER_TOO_SMALL
IOCTL_PWM_PIN_GET_POLARITY 检索引脚或通道的当前信号极性。 控制代码将信号极性作为PWM_PIN_GET_POLARITY_OUTPUT结构获取。 信号极性为“活动高”或“活动低”,如PWM_POLARITY枚举中定义。

Irp-IoStatus.Status> 设置为以下列表中的值之一。

  • 状态_成功
  • STATUS_NOT_SUPPORTED
  • STATUS_INVALID_DEVICE_REQUEST
  • STATUS_BUFFER_TOO_SMALL
IOCTL_PWM_PIN_SET_POLARITY 设置引脚或通道的信号极性。 控制代码基于PWM_PIN_SET_POLARITY_INPUT结构设置信号极性。 信号极性为“活动高”或“活动低”,如PWM_POLARITY枚举中定义。

仅当引脚停止时,才允许更改极性。 可以使用控制代码 IOCTL_PWM_PIN_IS_STARTED 判断引脚是否停止。 如果引脚已停止,并且请求的极性与当前引脚极性不同,则请求使用STATUS_INVALID_DEVICE_STATE值完成。

在启动引脚时更改极性可能会导致某些脉冲宽度调节(PWM)控制器出现故障。 如果要更改极性,请先停止引脚,更改极性,然后启动引脚。

Irp-IoStatus.Status> 设置为以下列表中的值之一。

  • 状态_成功
  • STATUS_NOT_SUPPORTED
  • STATUS_INVALID_DEVICE_REQUEST
  • 状态_参数无效
  • STATUS_BUFFER_TOO_SMALL
IOCTL_PWM_PIN_START 开始在引脚或通道上生成脉冲宽度调节(PWM)信号。 若要检查引脚是否已启动,请使用IOCTL_PWM_PIN_IS_STARTED。

在已启动的引脚或通道上发出此 IOCTL 不起作用,但成功。

Irp-IoStatus.Status> 设置为以下列表中的值之一。

>
  • 状态_成功
  • STATUS_NOT_SUPPORTED
  • STATUS_INVALID_DEVICE_REQUEST
  • STATUS_BUFFER_TOO_SMALL
IOCTL_PWM_PIN_STOP 停止在引脚或通道上生成脉冲宽度调节(PWM)信号。 若要检查引脚是否已启动,请使用IOCTL_PWM_PIN_IS_STARTED。

在已停止的引脚或通道上发出此 IOCTL 不会产生任何效果,但操作仍然成功。

Irp-IoStatus.Status> 设置为以下列表中的值之一。

  • 状态_成功
  • STATUS_NOT_SUPPORTED
  • STATUS_INVALID_DEVICE_REQUEST
  • STATUS_BUFFER_TOO_SMALL
IOCTL_PWM_PIN_IS_STARTED (查询PWM引脚是否已启动) 检索引脚或通道的信号生成状态。 每个引脚的状态都作为PWM_PIN_IS_STARTED_OUTPUT结构启动或停止。 起始状态的布尔值为 true。 停止状态为 false。

默认情况下,针脚在打开时会暂停,并在关闭或释放时回到暂停状态。

Irp-IoStatus.Status> 设置为以下列表中的值之一。

  • 状态_成功
  • STATUS_NOT_SUPPORTED
  • STATUS_INVALID_DEVICE_REQUEST
  • STATUS_BUFFER_TOO_SMALL