Files
BSI-901-fpga-software/docs/csi040_ctrl_datasheet.md

438 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CSI040 控制模块 Datasheet
## 1. 概述
`csi040_ctrl` 是用于控制 CSI040 ASIC 的 PL 侧控制模块。模块对上层软件暴露一组 32 bit BRAM 风格寄存器,并把软件写寄存器的动作转换为 CSI040 SPI 总线访问。
该模块主要完成:
- CSI040 ASIC 控制寄存器写入
- 16 通道 enable 配置
- 单通道参数寄存器写入
- DCS/Test 模式 key 序列写入
- Direct SPI 读写
- ASIC reset/trigger 引脚直接控制
- SPI busy/done/error 状态反馈
相关 RTL 文件:
- `c64_pro.srcs/sources_1/rtl/csi040/csi040_ctrl.v`
- `c64_pro.srcs/sources_1/rtl/csi040/csi040_spi_master.v`
- `c64_pro.srcs/sources_1/rtl/csi040/csi040_ctrl_tb.v`
## 2. 模块框图
```text
+------------------------------+
BRAM register | | SPI command
access -------->| csi040_ctrl |----------------+
| | |
| register map / shadow regs | v
| sequence engine | +--------------------+
| busy/done/error status | | csi040_spi_master |
+------------------------------+ +---------+----------+
| | |
| | direct pins | SPI pins
v v v
asic_rst_n asic_trig asic_csn/asic_sck/asic_si/asic_so
```
## 3. 主要特性
| 项目 | 规格 |
| --- | --- |
| 软件接口 | 32 bit BRAM 风格寄存器接口 |
| BRAM 地址宽度 | 13 bit |
| 支持写类型 | 仅支持 `bram_we == 4'hF` 的整字写 |
| 支持读类型 | `bram_en == 1``bram_we == 4'h0` |
| ASIC 地址宽度 | 默认 16 bit |
| SPI 地址字节数 | 默认 2 byte |
| Direct SPI 最大 payload | 默认 4 byte,由 `MAX_BURST_BYTES` 决定 |
| SPI SCK 极性 | idle low |
| SPI CSN 极性 | active low |
| SPI 输出位序 | opcode/address/data 均 MSB first 按帧发送;payload byte0 来自低 8 bit |
| 忙保护 | 忙时写命令寄存器不会启动新命令,并置位 `error_busy` |
| 复位 | `rst_n` 异步低有效 |
## 4. 参数
### 4.1 `csi040_ctrl` 参数
| 参数 | 默认值 | 说明 |
| --- | ---: | --- |
| `VERSION` | `32'h04040001` | 模块版本号,读 `0x0000` 返回 |
| `SPI_CLK_DIV` | `50` | SPI SCK 半周期分频,`f_sck = f_clk / (2 * SPI_CLK_DIV)` |
| `REG_ADDR_WIDTH` | `16` | ASIC 寄存器地址宽度 |
| `SPI_ADDR_BYTES` | `2` | SPI 帧中地址字段字节数 |
| `MAX_BURST_BYTES` | `4` | Direct SPI 最大 payload 字节数 |
| `SPI_OPCODE_WRITE` | `8'h00` | SPI 写 opcode |
| `SPI_OPCODE_READ` | `8'h80` | SPI 读 opcode |
| `CSI_REG_CONTROL` | `16'h0002` | CSI040 control register 地址 |
| `CSI_REG_CH_ENABLE1` | `16'h0007` | channel 0-7 enable 地址 |
| `CSI_REG_CH_ENABLE2` | `16'h0008` | channel 8-15 enable 地址 |
| `CSI_REG_TEST_DCS_KEY` | `16'h0009` | DCS/Test key register 地址 |
| `CSI_CH_BASE` | `16'h0010` | 通道寄存器基地址 |
| `CSI_CH_STRIDE` | `16'h0010` | 通道寄存器地址步进 |
| `CSI_REG_STIM_TRIGGER` | `16'h0110` | stimulation trigger register 地址 |
| `CSI_REG_PART_ID` | `16'h011D` | part ID register 地址 |
| `CSI_REG_REVISION` | `16'h011E` | revision register 地址 |
### 4.2 `MAX_BURST_BYTES` 说明
`MAX_BURST_BYTES` 同时影响以下信号宽度和行为:
| 位置 | 影响 |
| --- | --- |
| `spi_cmd_wdata` | 宽度为 `8 * MAX_BURST_BYTES` |
| `spi_cmd_rdata` | 宽度为 `8 * MAX_BURST_BYTES` |
| SPI master 内部 frame | 最大帧长为 `8 * (1 + SPI_ADDR_BYTES + MAX_BURST_BYTES)` |
| Direct SPI 长度 | `SPI_CTRL[15:8]` 超过 `MAX_BURST_BYTES` 时会被截断 |
高层命令序列目前都只发 1 byte payload`MAX_BURST_BYTES` 主要服务于 Direct SPI burst 访问。
## 5. 端口说明
### 5.1 时钟复位
| 信号 | 方向 | 位宽 | 说明 |
| --- | --- | ---: | --- |
| `clk` | input | 1 | 主时钟,模块内部逻辑均使用此时钟 |
| `rst_n` | input | 1 | 异步低有效复位 |
| `bram_clk` | input | 1 | 当前 RTL 未使用,保留接口 |
| `bram_rst` | input | 1 | 当前 RTL 未使用,保留接口 |
注意:当前实现中 `bram_clk/bram_rst` 未参与逻辑,BRAM 访问必须与 `clk` 同步。
### 5.2 BRAM 寄存器接口
| 信号 | 方向 | 位宽 | 说明 |
| --- | --- | ---: | --- |
| `bram_addr` | input | 13 | BRAM 字节地址 |
| `bram_din` | input | 32 | 写数据 |
| `bram_dout` | output reg | 32 | 读数据 |
| `bram_en` | input | 1 | BRAM 访问使能 |
| `bram_we` | input | 4 | 写 strobe;仅 `4'hF` 识别为写,`4'h0` 识别为读 |
### 5.3 状态输出
| 信号 | 方向 | 位宽 | 说明 |
| --- | --- | ---: | --- |
| `busy` | output | 1 | 模块忙。为 1 时不要写命令寄存器 |
| `spi_done` | output | 1 | SPI master 完成脉冲,持续 1 个 `clk` |
| `error_busy` | output reg | 1 | 忙时启动命令产生的粘滞错误标志 |
### 5.4 ASIC 引脚
| 信号 | 方向 | 位宽 | 说明 |
| --- | --- | ---: | --- |
| `asic_rst_n` | output reg | 1 | ASIC reset 引脚,软件通过 `PIN_CTRL[0]` 控制 |
| `asic_trig` | output reg | 1 | ASIC trig 引脚,软件通过 `PIN_CTRL[1]` 控制 |
| `asic_csn` | output | 1 | SPI CSN,低有效 |
| `asic_sck` | output | 1 | SPI SCK,空闲低 |
| `asic_si` | output | 1 | SPI master 输出到 ASIC |
| `asic_so` | input | 1 | ASIC 输出到 SPI master |
## 6. BRAM 寄存器映射
| 地址 | 名称 | 访问 | 说明 |
| ---: | --- | --- | --- |
| `13'h0000` | `VERSION` | R | 返回 `VERSION` |
| `13'h0004` | `STATUS` | R/W1C | 状态寄存器;写 bit0 清 done,写 bit1 清 error |
| `13'h0008` | `SPI_ADDR` | R/W | Direct SPI 目标 ASIC 地址 |
| `13'h000C` | `SPI_WDATA` | R/W | Direct SPI 写数据 |
| `13'h0010` | `SPI_CTRL` | W | Direct SPI 启动控制 |
| `13'h0014` | `SPI_RDATA` | R | 最近一次 SPI 读回数据 |
| `13'h0018` | `PIN_CTRL` | R/W | 直接控制 `asic_rst_n/asic_trig` |
| `13'h001C` | `LAST_ADDR` | R | 最近一次完成 SPI 操作的 ASIC 地址 |
| `13'h0020` | `CONTROL` | R/W | 写 CSI040 control register |
| `13'h0024` | `CH_ENABLE` | R/W | 写 channel enable1/2 |
| `13'h0028` | `TRIGGER` | W | 向 ASIC trigger register 写 `8'hAA` |
| `13'h002C` | `SEQ_CMD` | W | 特殊序列命令 |
| `13'h0040` | `CH_INDEX` | R/W | 选择通道编号 |
| `13'h0044` | `CH_MISC` | W | 当前通道 offset `0x0` |
| `13'h0048` | `CH_CUR_A` | W | 当前通道 offset `0x1` |
| `13'h004C` | `CH_CUR_B` | W | 当前通道 offset `0x2` |
| `13'h0050` | `CH_CUR_C` | W | 当前通道 offset `0x3` |
| `13'h0054` | `CH_CUR_D` | W | 当前通道 offset `0x4` |
| `13'h0058` | `CH_STIM_PW` | W | 当前通道 offset `0x5` |
| `13'h005C` | `CH_DZ0` | W | 当前通道 offset `0x6` |
| `13'h0060` | `CH_DZ1` | W | 当前通道 offset `0x7` |
| `13'h0064` | `CH_SKIP_AB` | W | 当前通道 offset `0x8` |
| `13'h0068` | `CH_SKIP_CD` | W | 当前通道 offset `0x9` |
| `13'h006C` | `CH_STIM_NUM` | W | 当前通道 offset `0xA` |
| `13'h0070` | `CH_DZ2` | W | 当前通道 offset `0xB` |
| `13'h0074` | `CH_THERAPY_DELAY` | W | 当前通道 offset `0xC` |
| `13'h0078` | `CH_THERAPY_NUM` | W | 当前通道 offset `0xD` |
| `13'h007C` | `CH_DZ3` | W | 当前通道 offset `0xE` |
| `13'h0080` | `CH_MASTER_NUM` | W | 当前通道 offset `0xF` |
## 7. 寄存器位定义
### 7.1 `STATUS` 寄存器
`STATUS` 读回值由 RTL 拼接得到:
```verilog
{16'd0, seq_id, seq_step, error_busy, done_latched, spi_cmd_ready, ctrl_busy}
```
赋值给 32 bit `bram_dout` 时左侧补 0。软件可按以下位使用:
| 位 | 名称 | 说明 |
| ---: | --- | --- |
| `[5]` | `ctrl_busy` | 当前模块忙 |
| `[6]` | `spi_cmd_ready` | SPI master 空闲可接收命令 |
| `[7]` | `done_latched` | 至少完成过一次 SPI 操作 |
| `[8]` | `error_busy` | 忙时写命令错误 |
| `[11:9]` | `seq_step` | 当前序列步骤 |
| `[15:12]` | `seq_id` | 当前序列编号 |
`STATUS` 清除粘滞位:
| 写 bit | 行为 |
| ---: | --- |
| `[0] = 1` | 清除 `done_latched` |
| `[1] = 1` | 清除 `error_busy` |
### 7.2 `SPI_CTRL` 寄存器
| 位 | 名称 | 说明 |
| ---: | --- | --- |
| `[0]` | `direct_write` | 1Direct SPI 写;0Direct SPI 读 |
| `[15:8]` | `direct_len` | payload 字节数;0 会被转换为 1 |
| 其他 | 保留 | 当前未使用 |
`direct_len` 最终会在 SPI master 内限制到 `1..MAX_BURST_BYTES`
### 7.3 `PIN_CTRL` 寄存器
| 位 | 名称 | 说明 |
| ---: | --- | --- |
| `[0]` | `asic_rst_n` | 直接驱动 ASIC reset_n |
| `[1]` | `asic_trig` | 直接驱动 ASIC trig |
| 其他 | 保留 | 当前读回为 0 |
### 7.4 `SEQ_CMD` 寄存器
| 位 | 命令 | SPI 行为 |
| ---: | --- | --- |
| `[0]` | DCS unlock | 向 `0x0009` 依次写 `55h, B3h, 0Ah` |
| `[1]` | Test unlock | 向 `0x0009` 依次写 `AAh, 4Ch, F5h` |
| `[2]` | Mode exit | 向 `0x0009``F9h` |
| `[3]` | Control quick write | 设置 `control_shadow = 8'h10` 并写 `0x0002` |
| `[4]` | Control quick write | 设置 `control_shadow = 8'h08` 并写 `0x0002` |
若多个 bit 同时为 1,优先级从 bit0 到 bit4。
## 8. 命令行为
### 8.1 `CONTROL`
`BRAM_ADDR_CONTROL`
```text
control_shadow <= bram_din[7:0]
SPI write addr 0x0002, data control_shadow, len 1
```
### 8.2 `CH_ENABLE`
`BRAM_ADDR_CH_ENABLE`
```text
ch_enable_shadow <= bram_din[15:0]
step0: SPI write addr 0x0007, data ch_enable_shadow[7:0]
step1: SPI write addr 0x0008, data ch_enable_shadow[15:8]
```
### 8.3 通道参数写
通道参数地址计算:
```text
asic_addr = CSI_CH_BASE + CH_INDEX * CSI_CH_STRIDE + channel_offset
```
默认:
```text
asic_addr = 0x0010 + CH_INDEX * 0x0010 + channel_offset
```
示例:
```text
CH_INDEX = 3
写 CH_CUR_A = 0x7F
channel_offset = 0x1
asic_addr = 0x0041
```
### 8.4 Direct SPI
Direct SPI 使用 `SPI_ADDR/SPI_WDATA/SPI_CTRL`
```text
1. 写 SPI_ADDR 设置 ASIC 地址
2. 写 SPI_WDATA 设置写数据
3. 写 SPI_CTRL 启动 direct transfer
4. 读操作完成后,从 SPI_RDATA 取数据
```
## 9. SPI 时序规格
### 9.1 SCK 频率
```text
f_sck = f_clk / (2 * SPI_CLK_DIV)
```
示例:
| `f_clk` | `SPI_CLK_DIV` | `f_sck` |
| ---: | ---: | ---: |
| 100 MHz | 50 | 1 MHz |
| 100 MHz | 25 | 2 MHz |
| 100 MHz | 10 | 5 MHz |
| 100 MHz | 5 | 10 MHz |
### 9.2 SPI 帧格式
默认 `SPI_ADDR_BYTES = 2`
```text
byte0 opcode
byte1 address high byte
byte2 address low byte
byte3.. payload byte0..N
```
写 1 byte 示例:
```text
opcode = 0x02
addr = 0x0002
data = 0x10
frame = 0x02_0002_10
```
### 9.3 SPI bit 数
```text
frame_bits = 8 * (1 + SPI_ADDR_BYTES + payload_len)
```
默认地址 2 byte 时:
| payload_len | frame_bits |
| ---: | ---: |
| 1 | 32 |
| 2 | 40 |
| 3 | 48 |
| 4 | 56 |
### 9.4 传输时间估算
不计状态机少量额外周期时:
```text
transfer_time ≈ frame_bits * 2 * SPI_CLK_DIV * clk_period
```
100 MHz、`SPI_CLK_DIV = 50`、1 byte payload
```text
frame_bits = 32
transfer_time ≈ 32 * 2 * 50 * 10 ns = 32 us
```
## 10. 软件推荐流程
### 10.1 写普通命令
```text
1. 轮询 STATUS[5] == 0,确认不忙
2. 写目标命令寄存器
3. 轮询 STATUS[7] == 1,确认完成
4. 写 STATUS[0] = 1,清除 done_latched
5. 若 STATUS[8] == 1,记录错误并写 STATUS[1] = 1 清除
```
### 10.2 Direct read 示例
读取 CSI040 Part ID
```text
write SPI_ADDR = 0x0000011D
write SPI_CTRL = 0x00000100 // bit0=0 read, len=1
wait done
read SPI_RDATA[7:0]
```
testbench 中 ASIC 模型返回 `8'h28`
### 10.3 Direct write 示例
向 ASIC `0x0002``0x10`
```text
write SPI_ADDR = 0x00000002
write SPI_WDATA = 0x00000010
write SPI_CTRL = 0x00000101 // bit0=1 write, len=1
wait done
```
## 11. 复位默认值
| 项目 | 复位值 |
| --- | ---: |
| `direct_addr` | `0` |
| `direct_wdata` | `0` |
| `direct_len` | `1` |
| `direct_write` | `1` |
| `control_shadow` | `0` |
| `ch_enable_shadow` | `0` |
| `ch_index` | `0` |
| `seq_id` | `SEQ_IDLE` |
| `seq_step` | `0` |
| `seq_active` | `0` |
| `error_busy` | `0` |
| `done_latched` | `0` |
| `last_rdata` | `0` |
| `last_addr` | `0` |
| `asic_rst_n` | `1` |
| `asic_trig` | `0` |
| `asic_csn` | `1` |
| `asic_sck` | `0` |
| `asic_si` | `0` |
## 12. 集成注意事项
- `bram_clk``bram_rst` 当前未使用,BRAM 访问必须同步到 `clk`
- 只支持整字写,软件侧需要保证 `bram_we == 4'hF`
- `busy = 1` 时不要写命令寄存器,否则命令被丢弃并置位 `error_busy`
- `TRIGGER` 寄存器是通过 SPI 写 ASIC trigger register`PIN_CTRL[1]` 是直接驱动 `asic_trig` 引脚,两者不是同一个功能。
- `SPI_OPCODE_WRITE/READ` 需要与最终 CSI040 SPI 协议匹配。当前 testbench 使用 `8'h02/8'h03`
- 若系统时钟不是 100 MHz,需要重新计算 `SPI_CLK_DIV`,保证 CSI040 SPI 时序满足要求。
- Direct SPI 多字节读写最大长度由 `MAX_BURST_BYTES` 控制,默认最多 4 byte。
## 13. 验证状态
当前 testbench 覆盖:
| 测试项 | 期望 |
| --- | --- |
| CONTROL 写 | SPI frame `0x02000210` |
| CH_ENABLE 写 | SPI frame `0x0200075A``0x020008A5` |
| CH3 CUR_A 写 | SPI frame `0x0200417F` |
| DCS unlock | SPI frame `0x02000955/0x020009B3/0x0200090A` |
| Direct read Part ID | SPI frame `0x03011D00`,读回 `0x28` |
已运行:
```text
xvlog: pass
xelab: pass
xsim : $finish at 10940 ns
```