Skip to content

Commit f5c4f1e

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

File tree

3 files changed

+168
-27
lines changed

3 files changed

+168
-27
lines changed

chipflow_digital_ip/io/i2c.py

Lines changed: 83 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,47 @@
1515

1616

1717
class I2CPeripheral(wiring.Component):
18+
"""
19+
A minimal I2C controller wrapping the Glasgow core
20+
21+
Support for customisable clock frequency and byte-wise transfers.
22+
"""
23+
1824
class Divider(csr.Register, access="rw"):
19-
"""I2C SCK clock divider, 1 = divide by 4"""
25+
"""Divider register.
26+
27+
This :class:`Register` is used to configure the clock frequency of the I2C peripheral.
28+
29+
The SCK frequency is the input clock frequency divided by 4 times the value in this register.
30+
For example, for a SCK of 1/12 the system clock, this register would be set to 3.
31+
"""
2032
val: csr.Field(csr.action.RW, unsigned(12))
2133

2234
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
35+
"""Action register.
36+
37+
This :class:`Register` is written to in order to perform various actions on the I2C bus.
38+
Writing ``0b1`` to a field performs that action, it is only valid to set one field at a time.
39+
40+
It has the following fields:
41+
42+
.. bitfield::
43+
:bits: 8
44+
45+
[
46+
{ "name": "reset", "bits": 1, "attr": "W" },
47+
{ "name": "start", "bits": 1, "attr": "W" },
48+
{ "name": "stop", "bits": 1, "attr": "W" },
49+
{ "name": "read_ack", "bits": 1, "attr": "W" },
50+
{ "name": "read_nack", "bits": 1, "attr": "W" },
51+
{ "bits": 3, "attr": "ResR0W0" },
52+
]
53+
54+
- The ``reset`` field is used to reset the PHY in case of a lock-up (e.g. SCK stuck low)
55+
- The ``start`` field sends an I2C start
56+
- The ``stop`` field sends an I2C stop
57+
- The ``read_ack`` field begins an I2C read, followed by an ACK
58+
- The ``read_nack`` field begins an I2C read, followed by a NACK
2959
"""
3060
reset: csr.Field(csr.action.W, unsigned(1))
3161
start: csr.Field(csr.action.W, unsigned(1))
@@ -35,20 +65,61 @@ class Action(csr.Register, access="w"):
3565

3666

3767
class SendData(csr.Register, access="w"):
38-
"""writes the given data onto the I2C bus when written to"""
68+
"""SendData register.
69+
70+
Writing to this :class:`Register` sends a byte on the I2C bus.
71+
72+
It has the following fields:
73+
74+
.. bitfield::
75+
:bits: 8
76+
77+
[
78+
{ "name": "val", "bits": 8, "attr": "W" },
79+
]
80+
81+
"""
3982
val: csr.Field(csr.action.W, unsigned(8))
4083

4184
class ReceiveData(csr.Register, access="r"):
42-
"""data received from the last read"""
85+
"""ReceiveData register.
86+
87+
This :class:`Register` contains the result of the last read started using `read_ack` or `read_nack`.
88+
89+
It has the following fields:
90+
91+
.. bitfield::
92+
:bits: 8
93+
94+
[
95+
{ "name": "val", "bits": 8, "attr": "R" },
96+
]
97+
98+
"""
4399
val: csr.Field(csr.action.R, unsigned(8))
44100

45101
class Status(csr.Register, access="r"):
102+
"""Status register.
103+
104+
This :class:`Register` contains the status of the peripheral.
105+
106+
It has the following fields:
107+
108+
.. bitfield::
109+
:bits: 8
110+
111+
[
112+
{ "name": "busy", "bits": 1, "attr": "R" },
113+
{ "name": "ack", "bits": 1, "attr": "R" },
114+
{ "bits": 6, "attr": "ResR0" },
115+
]
116+
117+
- The ``busy`` field is set when the PHY is currently performing an action, and unable to accept any requests.
118+
- The ``ack`` field contains the ACK/NACK value of the last write.
119+
"""
46120
busy: csr.Field(csr.action.R, unsigned(1))
47121
ack: csr.Field(csr.action.R, unsigned(1))
48122

49-
"""
50-
A minimal I2C controller wrapping the Glasgow core
51-
"""
52123
def __init__(self):
53124
regs = csr.Builder(addr_width=5, data_width=8)
54125

chipflow_digital_ip/io/spi.py

Lines changed: 83 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -111,40 +111,108 @@ def elaborate(self, platform):
111111

112112

113113
class SPIPeripheral(wiring.Component):
114+
"""
115+
A custom, minimal SPI controller
116+
117+
Transfers up to a width of 32 bits are supported, as are all SPI modes.
118+
"""
119+
114120
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
121+
"""Config register.
122+
123+
This :class:`Register` is written to in order to configure the SPI mode and transaction.
124+
125+
It has the following fields:
126+
127+
.. bitfield::
128+
:bits: 8
129+
130+
[
131+
{ "name": "sck_idle", "bits": 1, "attr": "RW" },
132+
{ "name": "sck_edge", "bits": 1, "attr": "RW" },
133+
{ "name": "chip_select", "bits": 1, "attr": "RW" },
134+
{ "name": "width", "bits": 5, "attr": "RW" },
135+
]
136+
137+
- The ``sck_idle`` field is used to invert the SCK polarity, ``0b0`` for an idle low SCK, ``0b1`` for an idle high SCK
138+
- The ``sck_edge`` field selects which edge is used for input and output data.
139+
- ``0b0`` to read input on rising SCK edge, latch output on falling SCK edge
140+
- ``0b1`` to latch output on rising SCK edge, read input on falling SCK edge
141+
- The ``chip_select`` field controls the CS pin; setting it to ``0b1`` asserts (brings low) chip select.
142+
- The ``width`` field configures the width of the transfer. It is set to the width of the transfer minus 1,
143+
``31`` gives the maximum width of 32.
122144
"""
123145
sck_idle: csr.Field(csr.action.RW, unsigned(1))
124146
sck_edge: csr.Field(csr.action.RW, unsigned(1))
125147
chip_select: csr.Field(csr.action.RW, unsigned(1))
126148
width: csr.Field(csr.action.RW, unsigned(5))
127149

128150
class Divider(csr.Register, access="rw"):
129-
"""SPI SCK clock divider, 1 = divide by 4"""
151+
"""Divider register.
152+
153+
This :class:`Register` is used to configure the clock frequency of the I2C peripheral.
154+
155+
The SCK frequency is the input clock frequency divided by 4 times the value in this register.
156+
For example, for a SCK of 1/12 the system clock, this register would be set to 3.
157+
"""
130158
val: csr.Field(csr.action.RW, unsigned(8))
131159

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

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

140197
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))
198+
"""Status register.
143199
200+
This :class:`Register` contains the status of the peripheral.
201+
202+
It has the following fields:
203+
204+
.. bitfield::
205+
:bits: 8
206+
207+
[
208+
{ "name": "recv_full", "bits": 1, "attr": "R" },
209+
{ "bits": 7, "attr": "ResR0" },
210+
]
211+
212+
- The ``recv_full`` field is set to ``0b1`` when a transfer is completed. It is reset to zero by reading ``ReceiveData``.
213+
"""
214+
recv_full: csr.Field(csr.action.R, unsigned(1))
144215

145-
"""
146-
A custom, minimal SPI controller
147-
"""
148216
def __init__(self):
149217
regs = csr.Builder(addr_width=5, data_width=8)
150218

chipflow_digital_ip/io/uart.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ def __init__(self):
130130

131131
"""Wrapper for amaranth_soc RFC UART with PHY and chipflow_lib.IOSignature support
132132
133+
See rfc_uart.py for detailed register documentation.
134+
133135
Parameters
134136
----------
135137
addr_width : :class:`int`

0 commit comments

Comments
 (0)