Skip to content

Commit 7bdf349

Browse files
committed
Improve I2C and SPI register documentation
Signed-off-by: gatecat <gatecat@ds0.me>
1 parent cfd3591 commit 7bdf349

File tree

2 files changed

+154
-21
lines changed

2 files changed

+154
-21
lines changed

chipflow_digital_ip/io/i2c.py

Lines changed: 77 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,40 @@
1616

1717
class I2CPeripheral(wiring.Component):
1818
class Divider(csr.Register, access="rw"):
19-
"""I2C SCK clock divider, 1 = divide by 4"""
19+
"""Divider register.
20+
21+
This :class:`Register` is used to configure the clock frequency of the I2C peripheral.
22+
23+
The SCK frequency is the input clock frequency divided by 4 times the value in this register.
24+
For example, for a SCK of 1/12 the system clock, this register would be set to 3.
25+
"""
2026
val: csr.Field(csr.action.RW, unsigned(12))
2127

2228
class Action(csr.Register, access="w"):
23-
"""
24-
reset: reset the core, e.g. in case of a bus lockup
25-
start: write 1 to trigger I2C start
26-
stop: write 1 to trigger I2C stop
27-
read_ack: write 1 to trigger I2C read and ACK
28-
read_nack: write 1 to trigger I2C read and NACK
29+
"""Action register.
30+
31+
This :class:`Register` is written to in order to perform various actions on the I2C bus.
32+
Writing ``0b1`` to a field performs that action, it is only valid to set one field at a time.
33+
34+
It has the following fields:
35+
36+
.. bitfield::
37+
:bits: 8
38+
39+
[
40+
{ "name": "reset", "bits": 1, "attr": "W" },
41+
{ "name": "start", "bits": 1, "attr": "W" },
42+
{ "name": "stop", "bits": 1, "attr": "W" },
43+
{ "name": "read_ack", "bits": 1, "attr": "W" },
44+
{ "name": "read_nack", "bits": 1, "attr": "W" },
45+
{ "bits": 3, "attr": "ResR0W0" },
46+
]
47+
48+
- The ``reset`` field is used to reset the PHY in case of a lock-up (e.g. SCK stuck low)
49+
- The ``start`` field sends an I2C start
50+
- The ``stop`` field sends an I2C stop
51+
- The ``read_ack`` field begins an I2C read, followed by an ACK
52+
- The ``read_nack`` field begins an I2C read, followed by a NACK
2953
"""
3054
reset: csr.Field(csr.action.W, unsigned(1))
3155
start: csr.Field(csr.action.W, unsigned(1))
@@ -35,14 +59,58 @@ class Action(csr.Register, access="w"):
3559

3660

3761
class SendData(csr.Register, access="w"):
38-
"""writes the given data onto the I2C bus when written to"""
62+
"""SendData register.
63+
64+
Writing to this :class:`Register` sends a byte on the I2C bus.
65+
66+
It has the following fields:
67+
68+
.. bitfield::
69+
:bits: 8
70+
71+
[
72+
{ "name": "val", "bits": 8, "attr": "W" },
73+
]
74+
75+
"""
3976
val: csr.Field(csr.action.W, unsigned(8))
4077

4178
class ReceiveData(csr.Register, access="r"):
42-
"""data received from the last read"""
79+
"""ReceiveData register.
80+
81+
This :class:`Register` contains the result of the last read started using `read_ack` or `read_nack`.
82+
83+
It has the following fields:
84+
85+
.. bitfield::
86+
:bits: 8
87+
88+
[
89+
{ "name": "val", "bits": 8, "attr": "R" },
90+
]
91+
92+
"""
4393
val: csr.Field(csr.action.R, unsigned(8))
4494

4595
class Status(csr.Register, access="r"):
96+
"""Status register.
97+
98+
This :class:`Register` contains the status of the peripheral.
99+
100+
It has the following fields:
101+
102+
.. bitfield::
103+
:bits: 8
104+
105+
[
106+
{ "name": "busy", "bits": 1, "attr": "R" },
107+
{ "name": "ack", "bits": 1, "attr": "R" },
108+
{ "bits": 6, "attr": "ResR0" },
109+
]
110+
111+
- The ``busy`` field is set when the PHY is currently performing an action, and unable to accept any requests.
112+
- The ``ack`` field contains the ACK/NACK value of the last write.
113+
"""
46114
busy: csr.Field(csr.action.R, unsigned(1))
47115
ack: csr.Field(csr.action.R, unsigned(1))
48116

chipflow_digital_ip/io/spi.py

Lines changed: 77 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -112,35 +112,100 @@ def elaborate(self, platform):
112112

113113
class SPIPeripheral(wiring.Component):
114114
class Config(csr.Register, access="rw"):
115-
"""
116-
sck_idle: idle state of sck, '1' to invert sck
117-
sck_edge:
118-
1 to latch output on rising sck edge, read input on falling sck edge
119-
0 to read input on rising sck edge, latch output on falling sck edge
120-
chip_select: write '1' to assert (bring low) chip select output
121-
width: width of transfer, minus 1
115+
"""Config register.
116+
117+
This :class:`Register` is written to in order to configure the SPI mode and transaction.
118+
119+
It has the following fields:
120+
121+
.. bitfield::
122+
:bits: 8
123+
124+
[
125+
{ "name": "sck_idle", "bits": 1, "attr": "RW" },
126+
{ "name": "sck_edge", "bits": 1, "attr": "RW" },
127+
{ "name": "chip_select", "bits": 1, "attr": "RW" },
128+
{ "name": "width", "bits": 5, "attr": "RW" },
129+
]
130+
131+
- The ``sck_idle`` field is used to invert the SCK polarity, ``0b0`` for an idle low SCK, ``0b1`` for an idle high SCK
132+
- The ``sck_edge`` field selects which edge is used for input and output data.
133+
- ``0b0`` to read input on rising SCK edge, latch output on falling SCK edge
134+
- ``0b1`` to latch output on rising SCK edge, read input on falling SCK edge
135+
- The ``chip_select`` field controls the CS pin; setting it to ``0b1`` asserts (brings low) chip select.
136+
- The ``width`` field configures the width of the transfer. It is set to the width of the transfer minus 1,
137+
``31`` gives the maximum width of 32.
122138
"""
123139
sck_idle: csr.Field(csr.action.RW, unsigned(1))
124140
sck_edge: csr.Field(csr.action.RW, unsigned(1))
125141
chip_select: csr.Field(csr.action.RW, unsigned(1))
126142
width: csr.Field(csr.action.RW, unsigned(5))
127143

128144
class Divider(csr.Register, access="rw"):
129-
"""SPI SCK clock divider, 1 = divide by 4"""
145+
"""Divider register.
146+
147+
This :class:`Register` is used to configure the clock frequency of the I2C peripheral.
148+
149+
The SCK frequency is the input clock frequency divided by 4 times the value in this register.
150+
For example, for a SCK of 1/12 the system clock, this register would be set to 3.
151+
"""
130152
val: csr.Field(csr.action.RW, unsigned(8))
131153

132154
class SendData(csr.Register, access="w"):
133-
"""data to transmit, must be left justified (bits [31..32-N] used)"""
155+
"""SendData register.
156+
157+
Writing to this :class:`Register` starts a read/write transfer on the SPI bus, the width of which is configured in `Config`.
158+
159+
It has the following fields:
160+
161+
.. bitfield::
162+
:bits: 32
163+
164+
[
165+
{ "name": "val", "bits": 32, "attr": "W" },
166+
]
167+
168+
- The `val` field must be left-justified, so for a transfer of ``N`` bits, bits ``[31..32-N]`` are used.
169+
"""
170+
134171
val: csr.Field(csr.action.W, unsigned(32))
135172

136173
class ReceiveData(csr.Register, access="r"):
137-
"""data received, is right justified (bits [N-1..0] used)"""
174+
"""ReceiveData register.
175+
176+
This :class:`Register` contains the read data of the last transfer started with a write to ``SendData``.
177+
178+
It has the following fields:
179+
180+
.. bitfield::
181+
:bits: 8
182+
183+
[
184+
{ "name": "val", "bits": 32, "attr": "R" },
185+
]
186+
187+
- The `val` field is right-justified, so for a transfer of ``N`` bits, bits ``[N-1..0]`` are used.
188+
"""
138189
val: csr.Field(csr.action.R, unsigned(32))
139190

140191
class Status(csr.Register, access="r"):
141-
"""recv_full is 1 when transfer has been completed. reset to zero by reading receive_data"""
142-
recv_full: csr.Field(csr.action.R, unsigned(1))
192+
"""Status register.
193+
194+
This :class:`Register` contains the status of the peripheral.
195+
196+
It has the following fields:
197+
198+
.. bitfield::
199+
:bits: 8
143200
201+
[
202+
{ "name": "recv_full", "bits": 1, "attr": "R" },
203+
{ "bits": 7, "attr": "ResR0" },
204+
]
205+
206+
- The ``recv_full`` field is set to ``0b1`` when a transfer is completed. It is reset to zero by reading ``ReceiveData``.
207+
"""
208+
recv_full: csr.Field(csr.action.R, unsigned(1))
144209

145210
"""
146211
A custom, minimal SPI controller

0 commit comments

Comments
 (0)