-
Notifications
You must be signed in to change notification settings - Fork 176
add SPI migration guide #766
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
<h2 id="spi-port">Serial Peripheral Interface (SPI)</h2> | ||
|
||
The **Serial Peripheral Interface** allows you to send or receive a data stream over a synchronous serial interface made of 3 to 4 lines. | ||
|
||
- MISO: Master In Slave Out. | ||
- MOSI: Master Out Slave In. | ||
- MCLK: Clock. | ||
- SS: Slave Select. | ||
|
||
A typical use case of this interface is with SDCard, memory blocks and DACs or ADCs. | ||
|
||
This highly configurable interface has a wide range of elements you can adjust: | ||
|
||
- Frame length. | ||
- Clocks polarity and phase. | ||
|
||
<span class="warnings">**Warning:** We are introducing the SPI API in an upcoming release of Mbed OS. This page documents code that exists on a feature branch of Mbed OS. You can find details on how it may affect you in the [implementing the SPI API](#implementing-the-spi-api) section. | ||
|
||
### Assumptions | ||
|
||
#### Defined Behaviours | ||
|
||
- `spi_get_module()` returns the `SPIName` unique identifier to the peripheral associated to this SPI channel. | ||
- `spi_get_capabilities()` fills the given `spi_capabilities_t` instance | ||
- `spi_get_capabilities()` should consider the `ssel` pin when evaluation the `support_slave_mode` capability. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. SSEL pin may have different names for each target (SSEL, NCS etc).. how will this be handled? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The actual name of the value does not matter much as what's considered by the |
||
If the given `ssel` pin cannot be managed by hardware in slave mode, `support_slave_mode` should be false. | ||
- At least a symbol width of 8bit must be supported. | ||
- The supported frequency range must include the range [0.2..2] MHz. | ||
- The shortest part of the duty cycle must not be shorter than 50% of the expected period. | ||
- `spi_init()` initializes the pins leaving the configuration registers unchanged. | ||
- `spi_init()` if `is_slave` is false: | ||
- if `ssel` is `NC` the hal implementation ignores this pin. | ||
- if `ssel` is not `NC` then the hal implementation owns the pin and its management. | ||
- When managed by the hal implementation, `ssel` is always considered active low. | ||
- When the hardware supports the half-duplex (3-wire) mode, if `miso` (exclusive) or `mosi` is missing in any function that expects pins, the bus is assumed to be half-duplex. | ||
- `spi_free()` resets the pins to their default state. | ||
- `spi_free()` disables the peripheral clock. | ||
- `spi_format()` sets : | ||
- the number of bits per symbol | ||
- the mode : | ||
.0 Clock idle state is *low*, data are sampled when the clock becomes *active* (polarity = 0, phase = 0) | ||
.1 Clock idle state is *low*, data are sampled when the clock becomes *inactive* (polarity = 0, phase = 1) | ||
.2 Clock idle state is *high*, data are sampled when the clock becomes *active* (polarity = 1, phase = 0) | ||
.3 Clock idle state is *high*, data are sampled when the clock becomes *inactive* (polarity = 1, phase = 1) | ||
- the bit ordering (lsb/msb first). | ||
- `spi_format()` updates the configuration of the peripheral except the baud rate generator. | ||
- `spi_frequency()` sets the frequency to use during the transfer. | ||
- `spi_frequency()` returns the actual frequency that will be used. | ||
- `spi_frequency()` updates the baud rate generator leaving other configurations unchanged. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why format() should leave baud rate generator un-touched? And the frequency() should only configure the baud rate generator? Can we have format() setting everything and frequency() change "only" the baud rate gen along with the other 2 functions above? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because the responsibility of The choice of having two functions was made during the RFC process because the format is very unlikely to change during the lifetime of a spi instance while the frequency is likely to be raised after the first few exchanges with the slave peripheral. |
||
- `spi_init()`, `spi_frequency()` and `spi_format()` must be called at least once each before initiating any transfer. | ||
- `spi_transfer()` : | ||
- writes `tx_len` symbols to the bus. | ||
- reads `rx_len` symbols from the bus. | ||
- if `rx` is NULL then inputs are discarded. | ||
- if `tx` is NULL then `fill_symbol` is used instead. | ||
- returns the number of symbol clocked on the bus during this transfer. | ||
- expects symbols types to be the closest stdint type bigger or equal to its size following the platform's endianness. | ||
e.g.: | ||
- 7bits => uint8_t | ||
- 15bits => uint16_t | ||
- 16bits => uint16_t | ||
- 17bits => uint32_t | ||
- In Full-duplex mode : | ||
- if `rx_len` > `tx_len` then it sends `(rx_len-tx_len)` additional `fill_symbol` to the bus. | ||
- In Half-duplex mode : | ||
- as master, `spi_transfer()` sends `tx_len` symbols and then reads `rx_len` symbols. | ||
- as slave, `spi_transfer()` receives `rx_len` symbols and then sends `tx_len` symbols. | ||
- `spi_transter_async()` schedules a transfer to be process the same way `spi_transfer()` would have but asynchronously. | ||
- `spi_transter_async()` returns immediately with a boolean indicating whether the transfer was successfully scheduled or not. | ||
- The callback given to `spi_transfer_async()` is invoked when the transfer completes (with a success or an error). | ||
- `spi_transfer_async()` saves the handler and the `ctx` pointer. | ||
- The `ctx` is passed to the callback on transfer completion. | ||
- Unless if the transfer is aborted, the callback is invoked on completion. The completion maybe when all symbols have been transmitted | ||
or when in slave mode the master de-asserts the chip select. | ||
- The `spi_transfer_async()` function may use the `DMAUsage` hint to select the appropriate async algorithm. | ||
- The `spi_async_event_t` must be filled with the number of symbol clocked on the bus during this transfer and a boolean value indicated if an error has occurred. | ||
- `spi_transfer_async_abort()` aborts an on-going async transfer. | ||
|
||
#### Undefined Behaviours | ||
|
||
- Calling `spi_init()` multiple times on the same `spi_t` without `spi_free()`'ing it first. | ||
- Calling any method other than `spi_init()` on a non-initialized or freed `spi_t`. | ||
- Passing both `miso` and `mosi` as `NC` to `spi_get_module` or `spi_init`. | ||
- Passing `miso` or `mosi` as `NC` on target that does not support half-duplex mode. | ||
- Passing `mclk` as `NC` to `spi_get_module` or `spi_init`. | ||
- Passing an invalid pointer as `cap` to `spi_get_capabilities`. | ||
- Passing pins that cannot be on the same peripheral. | ||
- Passing an invalid pointer as `obj` to any method. | ||
- Giving a `ssel` pin to `spi_init()` when using in master mode. | ||
SS must be managed by hardware in slave mode and must **NOT** be managed by hardware in master mode. | ||
- Setting a frequency outside of the range given by `spi_get_capabilities()`. | ||
- Setting a frequency in slave mode. | ||
- Setting `bits` in `spi_format` to a value out of the range given by `spi_get_capabilities()`. | ||
- Passing an invalid pointer as `fill_symbol` to `spi_transfer` and `spi_transfer_async` while they would be required by the transfer (`rx_len != tx_len` or `tx==NULL`). | ||
- Passing an invalid pointer as `handler` to `spi_transfer_async`. | ||
- Calling `spi_transfer_async_abort()` while no async transfer is being processed (no transfer or a synchronous transfer). | ||
- In half-duplex mode, any mechanism (if any is present) to detect or prevent collision is implementation defined. | ||
|
||
#### Other requirements | ||
|
||
A target must also define these elements: | ||
|
||
- `#define SPI_COUNT (xxxxxU)`. | ||
The number of SPI peripheral available on the device. A good place for that macro is `PeripheralNames.h` next to the `SPIName` enumeration. | ||
|
||
#### Notes | ||
|
||
You can find more details about the design choices on the [HAL RFC #0](https://github.com/ARMmbed/mbed-os/blob/feature-hal-spec-spi/docs/design-documents/hal/0000-spi-overhaul.md). | ||
|
||
### Dependencies | ||
|
||
Hardware SPI capabilities. | ||
|
||
### Implementing the SPI API | ||
|
||
You can find the API and specification for the SPI API in the following class reference: | ||
|
||
[](http://os-doc-builder.test.mbed.com/docs/development/feature-hal-spec-spi-doxy/classmbed_1_1_s_p_i.html) | ||
|
||
To enable SPI support in Mbed OS, add the `SPI` label in the `device_has` option of the target's section in the `targets.json` file. | ||
You can also add the `SPI_ASYNCH` label in the `device_has` option to enable the asynchronous API. | ||
|
||
### Testing | ||
|
||
The Mbed OS HAL provides a set of conformance tests for SPI. You can use these tests to validate the correctness of your implementation. To run the SPI HAL tests, use the following command: | ||
|
||
``` | ||
mbed test -t <toolchain> -m <target> -n "tests-mbed_hal-spi*" | ||
``` | ||
|
||
You can read more about the test cases: | ||
|
||
[](http://os-doc-builder.test.mbed.com/docs/development/feature-hal-spec-spi-doxy/group__hal__spi__tests.html) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ithinuel : This is a HAL API doc & not a user facing API doc, correct? If so, could you please add a line in the introduction that this is only for the HAL..thanks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is in the target porting guide. All chapter that live here relate to the hal layer.
The other guides don't have any warning about that.
Should this be added to all other guides too ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @ithinuel . In that case, the warning is not required. Thank you.