ESP32 multiple slaves - same SPI bus

Hi guys,
I've been trying for several days to use different slaves on the same SPI bus.
I'm using ESP32 devKit V2 (wrover kit) with 16MB memory.

If I use slaves one by one, they work very well,
but when I try to integrate them to work in the same sketch, they no longer work correctly.

I assumed it was necessary to reconfigure the SPI at each slave change, but unfortunately this was not enough.

At the bus I have:

  • SD card
  • MAX3421
  • w5500

What I observe is that I can get MAX3421 and SD to work, but as soon as I introduce Ethernet module (w5500), the other two peripherals stop working.

Could you please advise me the best way to deal with this problem?
Examples or advice on the correct way to handle this situation?

Detail:
I'm using freertos and I have a mutex, named: mutex_SPI
which allows me to avoid simultaneous access of the peripherals to the bus.

At the moment I don't have particular efficiency and speed constraints,
I'm interested in starting by finding a way to make everything work.

SPI used: VSPI: SCK=18, MISO=19, MOSI=23
CS_SD=5
CS_MAX3421=27
CS_ETH=25

SD:
I'm using "SPClass" (SPI.h): SPIClass SPI_SD
and class SDFS: SDFS SD = SDFS(FSImplPtr(new VFSImpl()))
This is the initialization:

SPI_SD.begin(SPI_SCK, SPI_MISO, SPI_MOSI, CS_SD);
if(!SD.begin(CS_SD, SPI_SD, 4000000, "", 5, false))
{
      ESP_LOGE(TAG, "ERROR SD NOT INIT");
}

MAX3421:
I'm using "SPClass" (SPI.h): SPIClass SPI_USB
This is the initialization:

SPI_USB.begin(SPI_SCK, SPI_MISO, SPI_MOSI, CS_MAX3421);
if (Usb.Init() == -1)
{
    ESP_LOGE(TAG, "USB HOST OSC did not start");
}

Ethernet (w5500):
This is the initialization:
simplifyed code:

Ethernet.init(CS_ETH);
Ethernet.begin(mac);

if (Ethernet.hardwareStatus() != EthernetNoHardware)
{               
    vTaskDelay(100 / portTICK_PERIOD_MS );
                 
    if(Ethernet.linkStatus() != LinkOFF)
    {
        ESP_LOGD(TAG, "CABLE CONNECTED");
    }
    else
    {
        ESP_LOGE(TAG, "CABLE NOT CONNECTED");
    }
}

After the three initializations, each of which takes place in its own specific dedicated task,
after ethernet initialization, I can no longer communicate with either the SD or the MAX3421 module, although they worked before.

And it's not enough for me to re-initialize again.
I really don't know what to do

How do we behave in these cases?
Thank you very much for your attention

connect W5500 to HSPI port

Thanks for the fast reply.

The hardware is not in prototype form,
but it's already a PCB, do you think it's not possible to manage it on the same bus?

I had no experience with the W5500

Create a function like this to manage SS pins.

I have had issues mixing SD cards and LoRa devices on the same SPI bus on an ESP32, but the same sketch code is OK on other platforms.

The workaround I chose was to use the ESP32 hardware MMC interface for SD functions althouh you could also use the other SPI interface the ESP32 has free.

I did breadboard my mix of SD and LoRa before doing a PCB, and found the issue, so a workaround was not so difficult.

Create a function like this to manage SS pins.

Hi @FernandoGarcia ,
Thank you for your answer.

Unfortunately the problem is not the CS, it is managed within the functions that send the commands, it is correctly piloted.
I checked the correct management through an oscilloscope.

The problem is that after the lowering of each CS when I have to write to SPI, I don't see any movement on the MOSI signals, the problem is therefore on another level.

Hi @srnet,

Thanks for the advice, in my case this can't be a solution, it's a bypass of the problem.
The reason is that I can't use other pins, they are intended for other functions, and as I said, the hardware is now defined.

In any case, the SPI is a bus that by definition must allow the operation of multiple capacities connected to it, it was created for this. So hopefully I can find a solution with the current hardware setup :kissing_closed_eyes:

What happens if you try call begin function before write to device?

Three mistresses in one house, this definitely will not work, you need to look at how, for example, TFT and TOUCH are processed in the TFT_eSPI library

I tryed to call the init function of the MAX3421 after ethernet initialization...

SPI_USB.begin(SPI_SCK, SPI_MISO, SPI_MOSI, CS_MAX3421);
if (Usb.Init() == -1)
{
    ESP_LOGE(TAG, "USB HOST OSC did not start");
}

The result: USB HOST OSC did not start
As if it was no longer possible to communicate correctly with the device

This the body of the Init function:

template< typename SPI_SS, typename INTR >
int8_t MAX3421e< SPI_SS, INTR >::Init() {
    XMEM_ACQUIRE_SPI();
    // Moved here.
    // you really should not init hardware in the constructor when it involves locks.
    // Also avoids the vbus flicker issue confusing some devices.
    /* pin and peripheral setup */
    SPI_SS::SetDirWrite();
    SPI_SS::Set();
    spi::init();
    INTR::SetDirRead();
    XMEM_RELEASE_SPI();
    /* MAX3421E - full-duplex SPI, level interrupt */
    // GPX pin on. Moved here, otherwise we flicker the vbus.
    regWr(rPINCTL, (bmFDUPSPI | bmINTLEVEL));
    
    if(reset() == 0) { //OSCOKIRQ hasn't asserted in time
        return ( -1);
    }
    
    regWr(rMODE, bmDPPULLDN | bmDMPULLDN | bmHOST); // set pull-downs, Host
    
    regWr(rHIEN, bmCONDETIE | bmFRAMEIE); //connection detection
    
    /* check if device is connected */
    regWr(rHCTL, bmSAMPLEBUS); // sample USB bus
    while(!(regRd(rHCTL) & bmSAMPLEBUS)); //wait for sample operation to finish
    
    busprobe(); //check if anything is connected
    
    regWr(rHIRQ, bmCONDETIRQ); //clear connection detect interrupt
    regWr(rCPUCTL, 0x01); //enable interrupt pin
    
    return ( 0);
}

LOL :rofl:
but... Thanks to the CS the three mistresses never speak or see or hear at the same time!
Under these conditions I think it can work!! :rofl:

Thanks for the idea, as soon as I can I'll study the example you kindly recommended

Whith complete code and schematic of your board maybe you can get more help.

once I was at a service station where a friend was adjusting the engine, I told the master, why are you suffering, CO is normal, and he answered me and CH ??? Here also )))

Can you take control of the CS pins?
I had a similar problem some times ago with different SPI devices (7 display + SD card). It is never a good idea to "init" the SPI bus several times, since you have only 1 bus.
Every module/library takes the control of the SPI and at the end you don't know if a library is setting something more than just his slave device.

In my case, I got the control of the CS and so every device is managed when I set the CS, and not when the library want to set it :wink:

Maybe a SPI command is sent inside the W5500 interrupt routine?

You are right,
I will try to simplify the code with only the parts of interest,
it is a very big project, it will take me a long time, there are different tasks that communicate with the different peripherals, if I can't solve it, I will try

I think this is the problem,
for the moment I'm not using the interrupt on the ethernet,
but I see that the bus maintains the ethernet configuration.

I just implemented the function to manage the CSs but I still see the MAX3421 CS move at the wrong times, I probably have to understand the functioning of the w5500 library. What hard work :smiling_face_with_tear:

it was necessary to divert the ethernet to another spi BUS.
For the moment it seems that this allows an adequate functioning of the peripheral.

The protocol is very complex and it was highly inadvisable to place other peripherals on the same bus as the Ethernet.