Polling

该示例通过使用 SPI3W 的轮询方式读取鼠标 ID 信息。

通过 SPI3W 与鼠标进行通信,通过读取指定地址下的数据来读取指定信息。

环境需求

该示例支持以下开发套件:

开发套件

Hardware Platforms

Board Name

RTL8752H HDK

RTL8752H EVB

更多信息请参考 快速入门

硬件连线

EVB 外接 PWM3610DM-SUDU 鼠标,连接 P2_2 和 CLK,P2_3 和 SDIO,P2_4 和 CS#,同时连接 GND 和 VDD。

硬件介绍

PWM3610DM-SUDU 为激光鼠标传感器模块。PMW3610DM-SUDU 寄存器可通过串行端口访问。寄存器用于读取运动数据和状态,以及设置设备配置。在此示例中,用于演示与 SPI3W 的通信。

编译和下载

该示例的工程路径如下:

Project file: board\evb\io_sample\SPI3WIRE\Polling\mdk

Project file: board\evb\io_sample\SPI3WIRE\Polling\gcc

请按照以下步骤操作构建并运行该示例:

  1. 打开工程文件。

  2. 按照 快速入门编译 APP Image 给出的步骤构建目标文件。

  3. 编译成功后,在路径 mdk\bingcc\bin 下会生成 app bin app_MP_xxx.bin 文件。

  4. 按照 快速入门MP Tool 给出的步骤将 app bin 烧录至 EVB 内。

  5. 按下 reset 按键,开始运行。

测试验证

EVB 启动后,打印获取到的 ID 信息。若 ID 为 0x3e 和 0x01(仅代表 PWM3610DM-SUDU 鼠标),代表测试成功。

id[0] = 0x3e, id[1] = 0x01
SPI3W test pass!

代码介绍

该章节分为以下几个部分:

  1. 源码路径

  2. 初始化函数将在 初始化 章节介绍。

  3. 初始化后的功能实现将在 功能实现 章节介绍。

源码路径

  • 工程路径: sdk\board\evb\io_sample\SPI3WIRE\Polling

  • 源码路径: sdk\src\sample\io_sample\SPI3WIRE\Polling

该工程的工程文件代码结构如下:

└── Project: Polling
    └── secure_only_app
        └── include
            ├── app_define.h
            └── rom_uuid.h
        ├── cmsis                    includes CMSIS header files and startup files
            ├── overlay_mgr.c
            ├── system_rtl876x.c
            └── startup_rtl876x.s
        ├── lib                      includes all binary symbol files that user application is built on
            ├── rtl8752h_sdk.lib
            ├── gap_utils.lib
            └── ROM.lib
        ├── peripheral               includes all peripheral drivers and module code used by the application
            ├── rtl876x_rcc.c
            ├── rtl876x_pinmux.c
            ├── rtl876x_nvic.c
            └── rtl876x_3wire_spi.c
        ├── profile
        └── app                      includes the ble_peripheral user application implementation
            └── main_ns.c

初始化

当 EVB 复位启动时,调用 main() 函数,将执行以下流程:

int main(void)
{
    extern uint32_t random_seed_value;
    srand(random_seed_value);
    spi3wire_demo();

    while (1)
    {
    }
}

spi3wire_demo 中,包含了 PAD/PINMUX 设置,SPI3W 外设的初始化,以及读取 sensor id 等流程。与外设有关的初始化流程如下:

  1. board_3wire_spi_init 为 PAD/PINMUX 设置,包含如下流程:

    1. 配置 PAD:设置引脚、PINMUX 模式、PowerOn、无内部上拉,输出高。

    2. 配置 PINMUX:配置引脚 P2_2 为 SPI2W_CLK 功能、P2_3 为 SPI2W_DATA 功能、P2_4 为 SPI2W_CS 功能。

    void board_3wire_spi_init(void)
    {
        Pad_Config(SPI_3WIRE_CLK_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_ENABLE,
                PAD_OUT_HIGH);
        Pad_Config(SPI_3WIRE_DATA_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_ENABLE,
                PAD_OUT_HIGH);
        Pad_Config(SPI_3WIRE_CS_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_ENABLE,
                PAD_OUT_HIGH);
    
        Pinmux_Config(SPI_3WIRE_CLK_PIN, SPI2W_CLK);
        Pinmux_Config(SPI_3WIRE_DATA_PIN, SPI2W_DATA);
        Pinmux_Config(SPI_3WIRE_CS_PIN, SPI2W_CS);
    }
    
  2. driver_3wire_spi_init 为对 SPI3W 外设的初始化,包含如下流程:

    1. 使能 RCC 时钟。

    2. 设置 SPI3W 输出时钟。

    3. 设置工作模式为三线模式。

    4. 设置读取数据的延时时间。

    5. 设置输出不产生延时。

    6. 设置三线 SPI 为一般模式。

    void driver_3wire_spi_init(void)
    {
        /* Enable SPI3WIRE clock */
        RCC_PeriphClockCmd(APBPeriph_SPI2W, APBPeriph_SPI2W_CLOCK, ENABLE);
    
        /* Initialize SPI3WIRE */
        SPI3WIRE_InitTypeDef SPI3WIRE_InitStruct;
        SPI3WIRE_StructInit(&SPI3WIRE_InitStruct);
    
        SPI3WIRE_InitStruct.SPI3WIRE_SysClock       = 20000000;
        SPI3WIRE_InitStruct.SPI3WIRE_Speed          = 800000;
        SPI3WIRE_InitStruct.SPI3WIRE_Mode           = SPI3WIRE_3WIRE_MODE;
        /** The delay time from the end of address phase to the start of read data phase.
        * delay time = (SPI3WIRE_ReadDelay +1)/(2*SPI3WIRE_Speed).
        * delay time = (0x03 + 1)/(2 * speed) = 2.5us
        */
        SPI3WIRE_InitStruct.SPI3WIRE_ReadDelay      = 0x3;
        SPI3WIRE_InitStruct.SPI3WIRE_OutputDelay    = SPI3WIRE_OE_DELAY_NONE;
        SPI3WIRE_InitStruct.SPI3WIRE_ExtMode        = SPI3WIRE_NORMAL_MODE;
        SPI3WIRE_Init(&SPI3WIRE_InitStruct);
    }
    

功能实现

  1. 初始化完毕后,进行三线 SPI 的信号同步。设置 resync 时间,发送 resync 信号,等待 resync 信号输出完毕后失能 resync 信号。

    void spi3wire_demo(void)
    {
        ...
        /** Send resync time. Resync signal time = 2*1/(2*SPI3WIRE_Speed) = 1.25us
        * This parameter can be only be the following value: 0x0 to 0xf.
        */
        SPI3WIRE_SetResyncTime(2);
        SPI3WIRE_ResyncSignalCmd(ENABLE);
        while (SPI3WIRE_GetFlagStatus(SPI3WIRE_FLAG_RESYNC_BUSY) == SET);
        SPI3WIRE_ResyncSignalCmd(DISABLE);
        ...
    }
    
  2. 执行 SPI3W_Cmd 函数,使能三线 SPI 功能。

  3. 执行 spi3wire_readbyte 函数,读取鼠标 ID。

    1. 等待 busy 状态标志位消除。

    2. 清除 SPI3W 的接收 FIFO 中数据。

    3. 执行 SPI3WIRE_StartRead() ,读取该地址下的一个数据。

    4. 执行 SPI3WIRE_ReadBuf() ,读取 SPI3W 接收 FIFO 中数据。

    5. 返回读取的数据并打印。

    uint8_t spi3wire_readbyte(uint8_t address)
    {
        uint8_t reg_value = 0;
        uint32_t timeout = 0;
    
        /* Check spi busy or not */
        while (SPI3WIRE_GetFlagStatus(SPI3WIRE_FLAG_BUSY) == SET)
        {
            timeout++;
            if (timeout > 0x1ffff)
            {
                break;
            }
        }
    
        /* Clear Receive data length */
        SPI3WIRE_ClearRxDataLen();
    
        SPI3WIRE_StartRead(address, 1);
    
        timeout = 0;
        while (SPI3WIRE_GetFlagStatus(SPI3WIRE_FLAG_BUSY) == SET)
        {
            timeout++;
            if (timeout > 0x1ffff)
            {
                break;
            }
        }
    
        /* Get the length of received data */
        while (SPI3WIRE_GetRxDataLen() == 0);
        /* Read data */
        SPI3WIRE_ReadBuf(&reg_value, 1);
    
        return reg_value;
    }