Hi! I'm back to trying to get SPI to work between a Bela mini and a xiao esp32s3. The Bela is the master/host and the esp32s3 is set to slave/peripheral. It seems like the slave does not detect that the SPI transfer is completed except for when the Bela program is started and the SpiDevice is created, even if no new SPI transfer is started. In its current state, there is one successful transfer on both devices when I start/restart the Bela, and then a series of unsuccessful transfers (i.e. static values) on the bela with no completed transfers reported on the esp32s3. When I restart the esp32s3, the Bela receives one correct transfer, but the esp32s3 is still waiting for its first completed one.

If I move the SpiDevice into the AuxiliaryTask to recreate it for every transfer, the transfers do all finish on the esp32s3, but the content is mostly (but not entirely) rubbish in both directions.

Hookup: 4 6cm wires between SPI pins, bridged ground,

Tried among other things:

  • testing and combining different SPI modes
  • different clock speeds
  • different transfer lengths and offsets between the transfer lengths on the 2 devices
  • powering the esp32s3 separately of from the Bela

Bela code:

ESP-IDF code:

Grateful for any thoughts or ideas!

    ErikNatanael It seems like the slave does not detect that the SPI transfer is completed except for when the Bela program is started and the SpiDevice is created, even if no new SPI transfer is started

    This sounds like the chip select line is not properly asserted/deasserted. Do you have a scope that you could use to look at the signals and verify that?

    Using pin P2.31 aka SPI1 CS. Thanks, I'm thinking something along those lines too, but I unfortunately don't have a scope and my multimeter is extremely slow. Just confirmed that the esp32s3 code works fine with a different master. I'll experiment around the CS line and see what happens.

    Yes, tried all sorts of values there.
    Current state: manually setting a CS pin with digitalWrite works insofar as the data mostly comes through and the transfers are closed on the esp32s3 side! But of course the timing is off so there's a bunch of noise coming through as well.
    Doing only PinmuxUtils::set("P2_8", "spi_cs"); gives the warning File /sys/devices/platform/ocp/ocp:P2_8_pinmux/state could not be opened and the transfers are closed, but no data is transferred (noise-ish on the master side, default initialised value on the slave side). Are there any other pins that are suitable as CS?

      ErikNatanael File /sys/devices/platform/ocp/ocp😛2_8_pinmux/state could not be opened and the transfers are closed

      That should be P2_08, not P2_8. If it fails it means its pinmux hasn't changed. Also, it doesn't look like P2.08 contains any SPI1 CS signals. When using a GPIO as a chip select line, you should set it to gpio instead (which is the default anyhow). If using a GPIO, it becomes complicated to use one of Bela's 16 digital I/O as they are handled in the audio thread and cannot be used in the same thread as the SPI transaction. For that you'd need to use "synchronous" GPIOs (probably a bad name, see here and here. I was going to suggest something like this:. Do config-pin P2.31 gpio - instead of spi_cs; now you can address the corresponding GPIO (19) via the Gpio class.
      At the top of the file:

      #include <Gpio.h>
      Gpio cs;

      in setup()":

      cs.open(19);

      Then readSpi() could have:

      {
          ...
          cs.clear();
          usleep(1000); // wait between start of chip select and start of transmission.
          int ret = spiDevice.transfer(tx_buf, rx_buf, transmissionLength);
          usleep(1000); // wait between end of transmission and end of chip select
          if(ret)
          {...} else {...}
      }

      Then you can tweak the sleep values as needed. Note that you won't have a lot of accuracy on the sleep times, as that's governed by the kernel scheduler and note that usleep(0) is different from (longer than) no call to usleep() at all. Also, a compliant SPI implementation on the device side should not care about long chip select times.

      Oh, another way you'd be able to monitor if this (or the original) chip select code is behaving as expected you could wire that pin back to one of the Bela digital inputs and visualise it on the Bela scope.

      Thanks a million, that actually works flawlessly! I'll see what throughput I can get, it should be sufficient. For documentation, I used the P2.31 pin, driving it manually with cs.write(LOW); before transfer and cs.write(HIGH); after with the usleeps in between.

      I did as you said and connected the P2.31 pin as spi_cs to the scope (and also just printed the value) and what it does is go HIGH when the program starts and then LOW after almost exactly 1.5 seconds (2068 audio blocks at 32 frames per block). Then it never goes HIGH again until restart. Let me know if you think of something to help troubleshoot this more, but I will go with your solution for now.

      Full code if it helps someone else (or future me):