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
请按照以下步骤操作构建并运行该示例:
打开工程文件。
按照 快速入门 中 编译 APP Image 给出的步骤构建目标文件。
编译成功后,在路径
mdk\bin
或gcc\bin
下会生成 app binapp_MP_xxx.bin
文件。按下 reset 按键,开始运行。
测试验证
EVB 启动后,打印获取到的 ID 信息。若 ID 为 0x3e 和 0x01(仅代表 PWM3610DM-SUDU 鼠标),代表测试成功。
id[0] = 0x3e, id[1] = 0x01
SPI3W test pass!
代码介绍
该章节分为以下几个部分:
源码路径
工程路径:
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 等流程。与外设有关的初始化流程如下:
board_3wire_spi_init
为 PAD/PINMUX 设置,包含如下流程:配置 PAD:设置引脚、PINMUX 模式、PowerOn、无内部上拉,输出高。
配置 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); }
driver_3wire_spi_init
为对 SPI3W 外设的初始化,包含如下流程:使能 RCC 时钟。
设置 SPI3W 输出时钟。
设置工作模式为三线模式。
设置读取数据的延时时间。
设置输出不产生延时。
设置三线 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); }
功能实现
初始化完毕后,进行三线 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); ... }
执行
SPI3W_Cmd
函数,使能三线 SPI 功能。执行
spi3wire_readbyte
函数,读取鼠标 ID。等待 busy 状态标志位消除。
清除 SPI3W 的接收 FIFO 中数据。
执行
SPI3WIRE_StartRead()
,读取该地址下的一个数据。执行
SPI3WIRE_ReadBuf()
,读取 SPI3W 接收 FIFO 中数据。返回读取的数据并打印。
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(®_value, 1); return reg_value; }