Crates.io | neotron-bmc-protocol |
lib.rs | neotron-bmc-protocol |
version | 0.1.0 |
source | src |
created_at | 2023-07-15 10:40:58.214687 |
updated_at | 2023-07-15 10:40:58.214687 |
description | The SPI protocol supported by the Neotron BMC |
homepage | https://github.com/neotron-compute |
repository | https://github.com/neotron-compute/neotron-bmc |
max_upload_size | |
id | 917171 |
size | 32,093 |
The SPI protocol for communication with the Neotron Board Management Controller (NBMC).
The NBMC is an always-on microcontroller used on Neotron systems. It has very
low idle power consumption, allowing it to remain powered up at all times. This
lets it listen to button events from the Power and Reset buttons, and control
the system LEDs, main ~RESET
signal and turn the main 5V Power Rail on and
off. This lets your Neotron system have smart 'ATX PC' style features like a
soft power button, and it also ensures that all power rails come up before the
system is taken out of reset.
The NBMC sits on the SPI bus, receives Requests and sends Responses in reply. It can also activate an IRQ line.
This crate describes the protocol run over the SPI bus and provides some basic helper code for implementing the protocol in Rust.
To communicate with the NBMC, the Host Processor must first take the Chip Select
line (nCS
) low, then send a Header. SPI is a full-duplex system, but in
this system only one side is actually transferring useful data at any time, so
whilst the Header is being sent the Host will receive Padding Bytes of 0xFF
in
return (which can be discarded).
A transfer is comprised of three stages.
>
Request-
Turn-Around<
ReponseA Request is a sequence of bytes sent from the Host to the NBMC.
Turn-Around is a period of time of interdeterminate length during which
the Host clocks out dummy bytes and the NBMC responds with 0xFF
bytes,
which indicate that it has not yet formulated the Response. This period ends,
with the transmission of the Response from the NBMC to the Host.
There are different kinds of Request that can be made. Each has a corresponding Response.
Request Type | Contains | Length | Response Type |
---|---|---|---|
Read | Type, Register#, Length, CRC | 4 | Read |
Short Write | Type, Register#, Data Byte, CRC | 4 | Short |
Long Write Start | Type, Register#, Length, CRC | 4 | Short |
Long Write Payload | Length Bytes, CRC |
Length + 1 |
Short |
Response Type | Contains | Length |
---|---|---|
Short | Result, CRC | 2 |
Read | Result, Length Bytes, CRC |
Length + 2 |
To allow the NBMC to be efficient at receiving data over SPI, it is important
that the first Request received after the nCS
pin goes active-low is of a
fixed length. Here, all of the initial Requests have a fixed size of four
bytes. A Long Write Start Request tells the NBMC to expect a Request of a
different length to follow immediately after, which allows the NBMC to
re-configure the DMA to expect the longer length Request. The Long Write
Payload MUST only be sent following a Long Write Start, and without resetting
the nCS
signal in-between.
0xC0
: Read0xC1
: Read (alternate)0xC2
: Short Write0xC3
: Long Write0xA0
: OK0xA1
: CRC Failure0xA2
: Bad Request Type0xA3
: Bad Register#0xA4
: Bad LengthA Read Request consists of four 8-bit values:
0xC0
or 0xC1
marking this as a Read Request.The Type byte should alternate between 0xC0
and 0xC1
so that the NBMC
can tell if the Read Request is a repeat of the previous request. This may
occur, for example, if the Read Response fails its CRC check on arrival at the
Host. Because a Read Request can have side-effects (like removing bytes from
a FIFO), a repeated Read Request should return preceisely the same values as
before, rather than, say, fetching more new bytes from the FIFO. This allows the
FIFO to be read in a lossless fashion, even when there is occasional corruption
on the SPI bus.
A Read Response consists of a variable number of 8-bit values:
sequenceDiagram
Host->>NBMC: ReadRequest(25, 5)
Note over Host, NBMC: Read 5 bytes from Register 25
NBMC->>NBMC: Reads from register
NBMC->>Host: Response(OK, [0, 1, 2, 3, 4])
Note over Host, NBMC: Host get the five bytes
sequenceDiagram
Host->>NBMC: ReadRequest(25, 200)
Note over Host, NBMC: Read 200 bytes from Register 25
NBMC->>Host: Response(BadLength)
Note over Host, NBMC: NBMC says no.
A Short Write Request consists of four 8-bit values:
0xC2
or 0xC3
marking this as a Short Write Request.A Short Response is sent in returning, containing two bytes:
You could equally consider a Short Response as a single 16-bit big-endian
value, being one of 0xA069
, 0xA16E
, 0xA267
, 0xA360
or 0xA475
.
sequenceDiagram
Host->>NBMC: ShortWriteRequest(10, 0xAA)
Note over Host, NBMC: Write 0xAA to Register 10
NBMC->>NBMC: Writes to register
NBMC->>Host: Response(OK)
Note over Host, NBMC: NBMC is happy.
A Long Write Request consists of four 8-bit values:
0xC4
or 0xC5
marking this as a Long Write Request.A Short Response is sent, as per Short Write Request
If a Short Response is received containing a Response Result of OK
(0xA0
), the NBMC is ready to receive a Long Write Payload. If any other
Response Result is received, the Long Write Payload must not be sent and
nCS
must be raised to indicate the end of the transaction.
A Long Write Payload consists of a variable number of 8-bit values:
This message must always contain exactly the number of bytes stated in the Length field of the Long Write Request, plus one additional CRC byte.
A second Short Response is then sent, as per Short Write
Request. The nCS
signal must be
raised at this point to restart the write sequence, regardless of the specific
Response Result sent.
sequenceDiagram
Host->>NBMC: LongWriteRequest(16, 5)
Note over Host, NBMC: Prepare to write 5 bytes to Register 16
NBMC->>NBMC: Thinks for while
NBMC->>Host: Response(OK)
Note over Host, NBMC: NBMC is ready to take 5 bytes.
Host->>NBMC: LongWritePayload([0, 1, 2, 3, 4])
Note over Host, NBMC: Five bytes are sent
NBMC->>NBMC: Checks CRC
NBMC->>Host: Response(OK)
Note over Host, NBMC: NBMC is happy.
sequenceDiagram
Host->>NBMC: LongWriteRequest(16, 5)
Note over Host, NBMC: Prepare to write 5 bytes to Register 16
NBMC->>NBMC: Thinks for while
NBMC->>Host: Response(OK)
Note over Host, NBMC: NBMC is ready to take 5 bytes.
Host->>NBMC: LongWritePayload([0, 1, 2, 3, 4])
Note over Host, NBMC: Five bytes are sent
NBMC->>NBMC: Checks CRC
NBMC->>Host: Response(CrcFailure)
Note over Host, NBMC: NBMC is sad. The five bytes<br/>must have been corrupted as their CRC didn't<br/>match. Host must raise `nCS` and try again.
Any Request can be cancelled by the Host lifting nCS
high before the
Request has finished sending. This allows the NBMC to accomodate unexpected
Host reboots (as during a reboot it is expected that the nCS
line will be
raised).
This code is licenced under the Blue Oak Model License 1.0.0. See:
Our intent behind picking this licence is to allow this code to be freely reused, both in open-source and commercially licensed products.