This is the multi-page printable view of this section. Click here to print...

Return to the regular view of this page

As of 2025-07-24

SPI (Helper Class Version)

SPI (How to use with helper class)
    The helper class version is a more abstract implementation. By creating a read/write object transceiver, you start using the bus, and by destroying the object, you end the use of the bus.

    By creating the object inside the conditional expression of an if statement, the lifetime of the object is limited to the scope within the if block, and when exiting the if block, the object is destroyed and the bus release procedure is performed at that point.

    uint8_t c;
    if (auto&& trs = SPI.get_rwer()) { // Create object and check device communication
       // The scope (curly braces) here is the lifetime of trs.
       trs << 0x00; // Write 0x00 using mwx::stream interface
       trs >> c;    // Store the read data into c.
    }
    // When exiting the if block, trs is destroyed and the bus usage ends
    

    Also, since the read/write object implements the mwx::stream interface, operators like << can be used.

    • Matching the bus usage start and end with the object’s lifetime improves code readability and prevents omission of release procedures.
    • Unifies read/write procedures using the mwx::stream interface.

    Read/Write

    A reading method using a helper class that performs read operations and their termination procedures within the scope if() { ... }.

    inline uint8_t _spi_single_op(uint8_t cmd, uint8_t arg) {
        uint8_t d0, d1;
        if (auto&& x = SPI.get_rwer()) {
            d0 = x.transfer(cmd); (void)d0;
            d1 = x.transfer(arg);
            // (x << (cmd)) >> d0;
            // (x << (arg)) >> d1;
        }
    
        return d1;
    }

    Above, the x object created by the get_rwer() method is used to perform byte-wise read/write.

    1. The x object is created inside the if(...). At the same time, the SPI bus select pin is set. (The type is resolved by universal reference auto&& with type inference.)
    2. The created x object defines operator bool () which is used for evaluation in the conditional expression. For SPI bus, it always evaluates to true.
    3. The x object defines the method uint8_t transfer(uint8_t), which performs an 8-bit read/write transfer to SPI when called.
    4. At the end of the if() { ... } scope, the destructor of x is called, releasing the SPI bus select pin.

    get_rwer()

    periph_spi::transceiver get_rwer()

    Obtains a worker object used for SPI bus read/write.

    Worker Object

    transfer(), transfer16(), transfer32()

    uint8_t transfer(uint8_t val)
    uint16_t transfer16(uint16_t val)
    uint32_t transfer32(uint32_t val)

    Perform transfers of 8-bit, 16-bit, and 32-bit respectively, and return the read result with the same data width as the written data.

    << operator

    operator << (int c)
    operator << (uint8_t c)
    operator << (uint16_t c)
    operator << (uint32_t c)

    int and uint8_t types perform 8-bit transfers.

    uint16_t and uint32_t types perform 16-bit and 32-bit transfers respectively.

    Transfer results are stored in an internal FIFO queue of up to 16 bytes and read out by the >> operator. Since the buffer is not large, it is assumed to be read out each time after transfer.

    >> operator

    operator >> (uint8_t& c)
    operator >> (uint16_t& c)
    operator >> (uint32_t& c)
    
    null_stream(size_t i = 1)
    operator >> (null_stream&& p)

    Specify a variable with the same data width as the previous transfer.

    If the read result is not needed, use the null_stream() object. It skips the number of bytes specified by i.