forked from M-Labs/artiq
1
0
Fork 0

gateware.spi: cleanup doc

This commit is contained in:
Robert Jördens 2016-02-29 12:41:30 +01:00
parent aeae565d35
commit eb01b0bfee
1 changed files with 32 additions and 24 deletions

View File

@ -166,10 +166,6 @@ class SPIMaster(Module):
Notes: Notes:
* M = 32 is the data width (width of the data register, * M = 32 is the data width (width of the data register,
maximum write bits, maximum read bits) maximum write bits, maximum read bits)
* If there is a miso wire in pads, the input and output can be done
with two signals (a.k.a. 4-wire SPI), else mosi must be used for
both output and input (a.k.a. 3-wire SPI) and config.half_duplex
must to be set when reading data is desired.
* Every transfer consists of a write_length 0-M bit write followed * Every transfer consists of a write_length 0-M bit write followed
by a read_length 0-M bit read. by a read_length 0-M bit read.
* cs_n is asserted at the beginning and deasserted at the end of the * cs_n is asserted at the beginning and deasserted at the end of the
@ -184,29 +180,37 @@ class SPIMaster(Module):
"cs_n all deasserted" means "all cs_n bits high". "cs_n all deasserted" means "all cs_n bits high".
* cs is not mandatory in pads. Framing and chip selection can also * cs is not mandatory in pads. Framing and chip selection can also
be handled independently through other means. be handled independently through other means.
* If there is a miso wire in pads, the input and output can be done
with two signals (a.k.a. 4-wire SPI), else mosi must be used for
both output and input (a.k.a. 3-wire SPI) and config.half_duplex
must to be set when reading data is desired.
* For 4-wire SPI only the sum of read_length and write_length matters.
The behavior is the same no matter how the total transfer length is
divided between the two. For 3-wire SPI, the direction of mosi/miso
is switched from output to input after write_len cycles, at the
"shift_out" clk edge corresponding to bit write_length + 1 of the
transfer.
* The first bit output on mosi is always the MSB/LSB (depending on * The first bit output on mosi is always the MSB/LSB (depending on
config.lsb_first) of the data register, independent of config.lsb_first) of the data register, independent of
xfer.write_len. The last bit input from miso always ends up in xfer.write_len. The last bit input from miso always ends up in
the LSB/MSB (respectively) of the data register, independent of the LSB/MSB (respectively) of the data register, independent of
read_len. read_len.
* For 4-wire SPI only the sum of read_len and write_len matters. The
behavior is the same no matter how the total transfer length is
divided between the two. For 3-wire SPI, the direction of mosi/miso
is switched from output to input after write_len cycles, at the
"shift_out" clk edge corresponding to bit write_length + 1 of the
transfer.
* Data output on mosi in 4-wire SPI during the read cycles is what * Data output on mosi in 4-wire SPI during the read cycles is what
is found in the data register at the time. is found in the data register at the time.
Data in the data register outside the least/most (depending Data in the data register outside the least/most (depending
on config.lsb_first) significant read_length bits is what is on config.lsb_first) significant read_length bits is what is
seen on miso during the write cycles. seen on miso during the write cycles.
* The SPI data register is double-buffered: once a transfer completes, * The SPI data register is double-buffered: Once a transfer has
the previous transfer's read data is available in the data register started, new write data can be written, queuing a new transfer.
and new write data can be written, queuing a new transfer. Transfers Transfers submitted this way are chained and executed without
submitted this way are chained and executed without deasserting cs. deasserting cs. Once a transfer completes, the previous transfer's
read data is available in the data register.
* A wishbone transaction is ack-ed when the transfer has been written * A wishbone transaction is ack-ed when the transfer has been written
to the intermediate buffer. It will be started when there are no to the intermediate buffer. It will be started when there are no
other transactions being executed. other transactions being executed. Writes take one cycle when
there is either no transfer being executed, no data in the
intermediate buffer, or a transfer just completing. Reads always
finish in one cycle.
Transaction Sequence: Transaction Sequence:
* If desired, write the config register to set up the core. * If desired, write the config register to set up the core.
@ -215,28 +219,30 @@ class SPIMaster(Module):
writing triggers the transfer and when the transfer is accepted to writing triggers the transfer and when the transfer is accepted to
the inermediate buffer, the write is ack-ed. the inermediate buffer, the write is ack-ed.
* If desired, read the data register. * If desired, read the data register.
* If desired write xfer and data for the next, chained, transfer * If desired, write data for the next, chained, transfer.
Register address and bit map: Register address and bit map:
config (address 2): config (address 2):
1 offline: all pins high-z (reset=1) 1 offline: all pins high-z (reset=1)
1 active: cs/transfer active 1 active: cs/transfer active (read-only)
1 pending: transfer pending in intermediate buffer, bus writes will 1 pending: transfer pending in intermediate buffer, bus writes will
block block (read-only)
1 cs_polarity: active level of chip select (reset=0) 1 cs_polarity: active level of chip select (reset=0)
1 clk_polarity: idle level for clk (reset=0) 1 clk_polarity: idle level of clk (reset=0)
1 clk_phase: first edge after cs assertion to sample data on (reset=0) 1 clk_phase: first edge after cs assertion to sample data on (reset=0)
(clk_polarity, clk_phase) == (CPOL, CPHA) in Freescale language.
(0, 0): idle low, output on falling, input on rising (0, 0): idle low, output on falling, input on rising
(0, 1): idle low, output on rising, input on falling (0, 1): idle low, output on rising, input on falling
(1, 0): idle high, output on rising, input on falling (1, 0): idle high, output on rising, input on falling
(1, 1): idle high, output on falling, input on rising (1, 1): idle high, output on falling, input on rising
There is never a clk edge during a cs edge.
1 lsb_first: LSB is the first bit on the wire (reset=0) 1 lsb_first: LSB is the first bit on the wire (reset=0)
1 half_duplex: 3-wire SPI, in/out on mosi (reset=0) 1 half_duplex: 3-wire SPI, in/out on mosi (reset=0)
8 undefined 8 undefined
8 div_write: counter load value to divide this module's clock 8 div_write: counter load value to divide this module's clock
to the SPI write clk. to generate the SPI write clk (reset=0)
f_clk/f_spi_write == 2*(div_write + 1) (reset=0) f_clk/f_spi_write == div_write + 2
8 div_read: ditto for the read clock 8 div_read: ditto for the read clock
xfer (address 1): xfer (address 1):
@ -338,12 +344,14 @@ class SPIMaster(Module):
clk_t = TSTriple() clk_t = TSTriple()
self.specials += clk_t.get_tristate(pads.clk) self.specials += clk_t.get_tristate(pads.clk)
mosi_t = TSTriple()
self.specials += mosi_t.get_tristate(pads.mosi)
self.comb += [ self.comb += [
clk_t.oe.eq(~config.offline), clk_t.oe.eq(~config.offline),
clk_t.o.eq((spi.cg.clk & spi.cs) ^ config.clk_polarity), clk_t.o.eq((spi.cg.clk & spi.cs) ^ config.clk_polarity),
]
mosi_t = TSTriple()
self.specials += mosi_t.get_tristate(pads.mosi)
self.comb += [
mosi_t.oe.eq(~config.offline & spi.cs & mosi_t.oe.eq(~config.offline & spi.cs &
(spi.oe | ~config.half_duplex)), (spi.oe | ~config.half_duplex)),
mosi_t.o.eq(spi.reg.o), mosi_t.o.eq(spi.reg.o),