Skip to content

Extending SPI by exposing zephyr SPI capabilities. (probably applies to many subsystems) #14

Closed
@KurtE

Description

@KurtE

Overview:
Suppose in a library (or sketch), I wish to use some of the more powerful capabilities of the Zephyr system. For example in SPI,
I may wish to output a whole display frame of pixel data: for example an ILI9341 with 320x240 pixels, or 153600 bytes.
Currently with the SPI library, I have the choices of calling simple SPI.transfer(), where for each pixel I have to do something like
SPI.transfer(color >> 8); SPI.transfer(color & 0xff);

Which is rather slow. That is there is a lot of wasted time on the SPI buss.
Image
Or assuming SPI.transfer16(color) works. #13
We can cut the time down more or less half.

The only fast alternative is to use: SPI.transfer(buf, cnt)
However, we have to use a secondary buffer, and reverse the bytes into that secondary buffer, but it does speed things up.
And the transfer overwrites the buffer, with the return data, which is unneeded in this case.

What I would like is the ability to do: SPI.transfer16(send_buf, recv_buf, cnt);
where the two buffers are optional. Can do send only or receive only or send and receive...
And in some case I might want to do this asynchronously, maybe using DMA.

It looks like Zephyr has a lot of these capabilities built into their SPI device. That is the spi_transceive function that our SPI library is calling allows most of the above.

Question, how much of the above can/should be included in the main Arduino SPI library? And if it is not implemented as part of the SPI library, how much should we facilitate, making it easier for developers to implement faster and more efficient SPI functionality?
There are several possibilities:

a) Add some additional methods to the SPI library, for this. Several of other SPI libraries have additional methods, including those for the Teensy and likewise ESP32.

b) Add methods to SPI, that exposes some of the internal data, like:

  // temporary 
  const struct device *getSPIDevice() {return spi_dev;}
  const struct spi_config *getSPIConfig() {return &config;}

Which allow one to gain access to the underlying zephyr SPI object and the config. Note: one could use their own config object without too much problem

c) change the SPI object, to use protected: instead of private: than one could create a new sub-class
like: class extended_SPI : public SPI { ...

d) Hack it, which I will likely do to experiment:

const struct device *spi_dev;
struct spi_config *config;
...
    uint32_t *p = (uint32_t *)&SPI;
    spi_dev = (const struct device *)p[1];
    config = (struct spi_config *)&p[2];

and then maybe in my display code, I might have something like updateScreen:
might change from something like:

      uint16_t *pfbtft_end =
          &_pfbtft[(ILI9341_TFTWIDTH * ILI9341_TFTHEIGHT) - 1]; // setup
      uint16_t *pftbft = _pfbtft;

      // Quick and dirty
      uint16_t c = 0;
      while (pftbft <= pfbtft_end) {
        uint16_t pixel_color = *pftbft++;
        s_row_buff[c++] = (pixel_color >> 8) | ((pixel_color & 0xff) << 8);  // swap the bytes...
        if (c == 320) {
          _pspi->transfer(s_row_buff, c * 2);
          c = 0;
        }
      }
      if (c != 0) _pspi->transfer(s_row_buff, c * 2);

maybe to something like:

  const struct spi_buf tx_buf = {.buf = _pfbtft, .len = TFT_WIDTH*TFT_HEIGHT*2};
  const struct spi_buf_set tx_buf_set = {
      .buffers = &tx_buf,
      .count = 1,
  };
  spi_operation_t operation_save = config->operation;
  config->operation = (operation_save & ~(SPI_WORD_SET(0x3f))) | SPI_WORD_SET(16) | BIT(4);
  ret = spi_transceive(spi_dev, config, &tx_buf_set, nullptr);
  config->operation = operation_save;

Which does not need secondary buffer, nor time to copy it into it and reverse the bytes

Thoughts?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions