From 1627bdc6ac0fe8ebf2a681bccf867ad3bbf0d2e6 Mon Sep 17 00:00:00 2001 From: Wilfried Chauveau Date: Wed, 10 Oct 2018 10:48:04 +0100 Subject: [PATCH 1/5] add SPI migration guide --- docs/porting/target/spi.md | 133 +++++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 docs/porting/target/spi.md diff --git a/docs/porting/target/spi.md b/docs/porting/target/spi.md new file mode 100644 index 0000000000..eb16da4a32 --- /dev/null +++ b/docs/porting/target/spi.md @@ -0,0 +1,133 @@ +

Serial Peripheral Interface (SPI)

+ +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. + +**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. + 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. +- `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. + +#### 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: + +[![View code](https://www.mbed.com/embed/?type=library)](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 -m -n "tests-mbed_hal-spi*" +``` + +You can read more about the test cases: + +[![View code](https://www.mbed.com/embed/?type=library)](http://os-doc-builder.test.mbed.com/docs/development/feature-hal-spec-spi-doxy/group__hal__spi__tests.html) From 2ca2c8d0e259bbc7551435b0543537e3b9c4c56c Mon Sep 17 00:00:00 2001 From: Wilfried Chauveau Date: Thu, 18 Oct 2018 15:05:45 +0100 Subject: [PATCH 2/5] fix spi_modes rendering --- docs/porting/target/spi.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/porting/target/spi.md b/docs/porting/target/spi.md index eb16da4a32..38312278fb 100644 --- a/docs/porting/target/spi.md +++ b/docs/porting/target/spi.md @@ -37,11 +37,11 @@ This highly configurable interface has a wide range of elements you can adjust: - `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 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. From b832fead4483704a57c9af5ca3edf85b7f7c4ed4 Mon Sep 17 00:00:00 2001 From: Wilfried Chauveau Date: Tue, 6 Nov 2018 16:31:05 +0000 Subject: [PATCH 3/5] add a note for SPI_COUNT definition location. --- docs/porting/target/spi.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/porting/target/spi.md b/docs/porting/target/spi.md index 38312278fb..2a6d6f6956 100644 --- a/docs/porting/target/spi.md +++ b/docs/porting/target/spi.md @@ -101,7 +101,7 @@ This highly configurable interface has a wide range of elements you can adjust: A target must also define these elements: - `#define SPI_COUNT (xxxxxU)`. - The number of SPI peripheral available on the device. + The number of SPI peripheral available on the device. A good place for that macro is `PeripheralNames.h` next to the `SPIName` enumeration. #### Notes From 5c905c833dc1d6d8eef44b59d53e321448c77158 Mon Sep 17 00:00:00 2001 From: Amanda Butler Date: Wed, 2 Jan 2019 14:11:59 -0600 Subject: [PATCH 4/5] Edit spi.md Copy edit file, mostly for agreement, formatting and spelling. --- docs/porting/target/spi.md | 107 ++++++++++++++++++------------------- 1 file changed, 52 insertions(+), 55 deletions(-) diff --git a/docs/porting/target/spi.md b/docs/porting/target/spi.md index 2a6d6f6956..92b6a39327 100644 --- a/docs/porting/target/spi.md +++ b/docs/porting/target/spi.md @@ -2,14 +2,14 @@ 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. +- MISO: Master in, slave out. +- MOSI: Master out, slave in. - MCLK: Clock. -- SS: Slave Select. +- 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: +This highly configurable interface has elements you can adjust: - Frame length. - Clocks polarity and phase. @@ -18,82 +18,81 @@ This highly configurable interface has a wide range of elements you can adjust: ### Assumptions -#### Defined Behaviours +#### Defined behaviors - `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. - 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. +- `spi_get_capabilities()` fills the given `spi_capabilities_t` instance. +- `spi_get_capabilities()` should consider the `ssel` pin when evaluating the `support_slave_mode` capability. +- 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 8 bit 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. + - 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()` 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()` returns the actual frequency that is used. - `spi_frequency()` updates the baud rate generator leaving other configurations unchanged. - `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_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. For example: + - 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. +- Unless the transfer is aborted, the callback is invoked on completion. The completion may be when all symbols have been transmitted + or when, in slave mode, the master deasserts the chip select. +- The `spi_transfer_async()` function may use the `DMAUsage` hint to select the appropriate asynchronous algorithm. +- The `spi_async_event_t` must be filled with the number of symbols clocked on the bus during this transfer and a boolean value indicated if an error has occurred. +- `spi_transfer_async_abort()` aborts an ongoing asynchronous transfer. -#### Undefined Behaviours +#### Undefined behaviors - 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`. +- Calling any method other than `spi_init()` on an uninitialized 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. +- Giving an `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). +- Calling `spi_transfer_async_abort()` while no asynchronous 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 @@ -101,11 +100,9 @@ This highly configurable interface has a wide range of elements you can adjust: 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. +- The number of SPI peripherals 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). +**Note:**You can find more details about the design choices in the [SPI design document](https://github.com/ARMmbed/mbed-os/blob/feature-hal-spec-spi/docs/design-documents/hal/0000-spi-overhaul.md). ### Dependencies @@ -115,7 +112,7 @@ Hardware SPI capabilities. You can find the API and specification for the SPI API in the following class reference: -[![View code](https://www.mbed.com/embed/?type=library)](http://os-doc-builder.test.mbed.com/docs/development/feature-hal-spec-spi-doxy/classmbed_1_1_s_p_i.html) +[![View code](https://www.mbed.com/embed/?type=library)](http://os.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. @@ -130,4 +127,4 @@ mbed test -t -m -n "tests-mbed_hal-spi*" You can read more about the test cases: -[![View code](https://www.mbed.com/embed/?type=library)](http://os-doc-builder.test.mbed.com/docs/development/feature-hal-spec-spi-doxy/group__hal__spi__tests.html) +[![View code](https://www.mbed.com/embed/?type=library)](http://os.mbed.com/docs/development/feature-hal-spec-spi-doxy/group__hal__spi__tests.html) From c7180fd9a3d2d522b0d18e669f0a25dc2903d1b0 Mon Sep 17 00:00:00 2001 From: Amanda Butler Date: Wed, 2 Jan 2019 14:12:42 -0600 Subject: [PATCH 5/5] Add space in spi.md Add space to fix formatting. --- docs/porting/target/spi.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/porting/target/spi.md b/docs/porting/target/spi.md index 92b6a39327..67043f4ee8 100644 --- a/docs/porting/target/spi.md +++ b/docs/porting/target/spi.md @@ -102,7 +102,7 @@ A target must also define these elements: - `#define SPI_COUNT (xxxxxU)`. - The number of SPI peripherals available on the device. A good place for that macro is `PeripheralNames.h` next to the `SPIName` enumeration. -**Note:**You can find more details about the design choices in the [SPI design document](https://github.com/ARMmbed/mbed-os/blob/feature-hal-spec-spi/docs/design-documents/hal/0000-spi-overhaul.md). +**Note:** You can find more details about the design choices in the [SPI design document](https://github.com/ARMmbed/mbed-os/blob/feature-hal-spec-spi/docs/design-documents/hal/0000-spi-overhaul.md). ### Dependencies