SSI
SSI 驱动 | 无 sample
学习目标
- 理解 SSI(Synchronous Serial Interface)与 SPI 的关系——简化版 SPI,专为寄存器级外设通信设计
- 掌握 4 种地址/数据组合模式:addr16_data16、addr32_data16、addr32_data32
- 理解 SSI 的典型应用场景——RF 前端、电源管理芯片等寄存器级外设
基本概念
SSI 做什么
SSI 是简化版同步串行接口。标准 SPI 需要配置 CPOL、CPHA、帧格式、位宽等诸多参数,而 SSI 省略这些——直接按"地址 + 数据"模式与外部寄存器级外设通信。每次操作分为两段:先发地址,再读/写数据。适合 RF CMOS 前端、PMIC 等只需寄存器读写的芯片。
flowchart LR
M[WS63 MCU] -->|SSI 主机| S[SSI 控制器]
S -->|SCLK + SDIO + SEN| D[外设芯片]
D -->|寄存器数据| S
S -->|data 指针| M
SSI vs SPI
| 对比项 | SSI | SPI |
|---|---|---|
| 帧格式 | 固定:地址段 + 数据段 | 可配置 CPOL/CPHA |
| 配置复杂度 | 极低——只需 init | 高——多项参数 |
| 适用场景 | 寄存器级外设(RF/PMIC) | 通用——Flash/LCD/Sensor |
| 地址宽度 | 16-bit / 32-bit | 由协议决定 |
| 数据宽度 | 16-bit / 32-bit | 8~32 bit 任意 |
4 种读写模式
| 模式 | 地址宽度 | 数据宽度 | 典型外设 |
|---|---|---|---|
addr16_data16 |
16-bit | 16-bit | 常见 RF 前端寄存器 |
addr32_data16 |
32-bit | 16-bit | 大地址空间 16-bit 寄存器 |
addr32_data32 |
32-bit | 32-bit | 大地址空间 32-bit 寄存器 |
涉及 API
| API | 用途 | 头文件 |
|---|---|---|
uapi_ssi_init(void) |
初始化 SSI 控制器 | ssi.h |
uapi_ssi_deinit(void) |
去初始化 | ssi.h |
uapi_ssi_read_addr16_data16(uint16_t addr, uint16_t *data) |
16b 地址读 16b 数据 | ssi.h |
uapi_ssi_write_addr16_data16(uint16_t addr, uint16_t value) |
16b 地址写 16b 数据 | ssi.h |
uapi_ssi_read_addr32_data16(uint32_t addr, uint16_t *data) |
32b 地址读 16b 数据 | ssi.h |
uapi_ssi_write_addr32_data16(uint32_t addr, uint16_t value) |
32b 地址写 16b 数据 | ssi.h |
uapi_ssi_read_addr32_data32(uint32_t addr, uint32_t *data) |
32b 地址读 32b 数据 | ssi.h |
uapi_ssi_write_addr32_data32(uint32_t addr, uint32_t value) |
32b 地址写 32b 数据 | ssi.h |
所有读写接口返回
errcode_t——调用后应检查返回值,ERRCODE_SUCC表示操作成功。
案例说明
做什么
通过 SSI 以 addr16_data16 模式读写外部芯片的寄存器:读取 ID 寄存器验证通信正常,修改配置寄存器,回读确认写入成功。
规格与功能
| 规格项 | 说明 |
|---|---|
| 模式 | addr16_data16(16-bit 地址 + 16-bit 数据) |
| 外设地址 | 0x00(ID 寄存器)、0x10(配置寄存器) |
| 验证方法 | 读 → 修改 → 写 → 回读 → 比对 |
程序运行流程:init → read ID 寄存器 → 修改配置 → write 配置 → 回读确认 → deinit。
案例流程
sequenceDiagram
participant M as WS63 MCU
participant S as SSI 控制器
participant D as 外设芯片
M->>S: uapi_ssi_init
M->>S: read_addr16_data16 addr=0x00
S->>D: 发送地址0x00
D->>S: 返回ID值
S->>M: data = 0x1234
M->>M: 验证ID正确
M->>S: read_addr16_data16 addr=0x10
S->>D: 发送地址0x10
D->>S: 返回当前配置
S->>M: data = 0x0001
M->>M: 修改bit3=1
M->>S: write_addr16_data16 addr=0x10 val=0x0009
S->>D: 写入配置
M->>S: read_addr16_data16 addr=0x10
S->>D: 回读
D->>S: 返回0x0009
S->>M: 确认写入成功
M->>S: uapi_ssi_deinit
案例操作指导
第一步:编译
第二步:烧录和验证
WS63 通过 SSI 引脚连接到目标外设(SCLK、SDIO、SEN)。烧录后串口输出读取的寄存器值,验证 ID 寄存器匹配预期后继续。
第三步:预期输出
SSI: read ID reg[0x00] = 0x1234
SSI: read CFG reg[0x10] = 0x0001
SSI: write CFG reg[0x10] = 0x0009
SSI: verify CFG reg[0x10] = 0x0009 OK
关键配置
| 参数 | 值 | 说明 |
|---|---|---|
| 地址宽度 | 16-bit / 32-bit | 选错则外设不响应 |
| 数据宽度 | 16-bit / 32-bit | 需与外设寄存器宽度匹配 |
| 返回值检查 | 必须 | 总线错误时 data 无效 |
| 适用范围 | 协议栈内部 | 应用层通常通过 BSP 调用,不直接调 SSI |
地址宽度选择
| 外设寄存器数量 | 推荐模式 |
|---|---|
| <= 65536 个 16-bit 寄存器 | addr16_data16 |
| > 65536 个 16-bit 寄存器 | addr32_data16 |
| 32-bit 寄存器 | addr32_data32 |
代码详解
概念性代码,基于 SDK 头文件
ssi.h中的 API 签名。
#include "ssi.h"
#include "errcode.h"
#include "osal_printk.h"
#include "app_init.h"
#define RF_ID_REG 0x00 /* ID 寄存器 */
#define RF_CFG_REG 0x10 /* 配置寄存器 */
#define RF_ID_EXPECTED 0x1234 /* 期望的 ID 值 */
#define RF_CFG_BIT3 0x0008 /* 配置 bit3 掩码 */
static void ssi_entry(void)
{
errcode_t ret;
uint16_t id_val = 0;
uint16_t cfg_val = 0;
/* 初始化 SSI 控制器 */
uapi_ssi_init();
/* ---- 1. 读 ID 寄存器验证通信 ---- */
ret = uapi_ssi_read_addr16_data16(RF_ID_REG, &id_val);
if (ret != ERRCODE_SUCC) {
osal_printk("SSI: read ID failed, ret=%d\n", ret);
goto deinit;
}
osal_printk("SSI: read ID reg[0x%02X] = 0x%04X\n", RF_ID_REG, id_val);
if (id_val != RF_ID_EXPECTED) {
osal_printk("SSI: ID mismatch, expected 0x%04X\n", RF_ID_EXPECTED);
goto deinit;
}
/* ---- 2. 读配置寄存器 ---- */
ret = uapi_ssi_read_addr16_data16(RF_CFG_REG, &cfg_val);
if (ret != ERRCODE_SUCC) {
osal_printk("SSI: read CFG failed, ret=%d\n", ret);
goto deinit;
}
osal_printk("SSI: read CFG reg[0x%02X] = 0x%04X\n", RF_CFG_REG, cfg_val);
/* ---- 3. 修改 bit3 并写入 ---- */
cfg_val |= RF_CFG_BIT3;
ret = uapi_ssi_write_addr16_data16(RF_CFG_REG, cfg_val);
if (ret != ERRCODE_SUCC) {
osal_printk("SSI: write CFG failed, ret=%d\n", ret);
goto deinit;
}
osal_printk("SSI: write CFG reg[0x%02X] = 0x%04X\n", RF_CFG_REG, cfg_val);
/* ---- 4. 回读确认 ---- */
uint16_t verify_val = 0;
ret = uapi_ssi_read_addr16_data16(RF_CFG_REG, &verify_val);
if (ret == ERRCODE_SUCC && verify_val == cfg_val) {
osal_printk("SSI: verify OK\n");
} else {
osal_printk("SSI: verify FAIL, read=0x%04X expected=0x%04X\n",
verify_val, cfg_val);
}
deinit:
uapi_ssi_deinit();
}
app_run(ssi_entry);
SSI 的 4 种读写模式互斥——硬件上同一时刻只能使用一种模式。如需切换,先
deinit再init后重新选择模式。应用层通常不直接调用 SSI 接口——协议栈通过 BSP 封装使用。