SPI transactions in batches

I’m using the W5100 paired with an ESP32 MCU, and esp-idf’s SPI master library.
In the ESP32 world, unlike simpler MCUs like the AVR, SPI transactions are costly, which greatly affects performance, and it’s what’s bottlenecking my application right now.
I was testing grouping each of the 4-byte transactions into batches, doing multiple writes and reads in one go (sort of emulating W6100’s Variable Length Data Mode), but apparently it doesn’t work, as I only get garbage (either FF’s or 00’s) on the MISO line after the first 4-byte transaction finishes.

What’s going on? Does it not work?

2 Likes

Thank you for using our products.
But I don’t get the point of the question. Please let us know more details.
I recommend you to use iolibrary to use our ethernet products. You can find and download it from github link below.

Thanks.

Didn’t know about that library on github, thanks for the reference. But that’s not really related to the problem I’m having.

My question is: can I perform more than one read/write operation without de-asserting and asserting the CS line every time for each byte read/written? In other words, can I do back-to-back read/writes? Or in other words, can I read, say, 10 bytes while asserting and de-asserting the CS line only once?
Here’s an example: I want to read data that just arrived on the chip on the RX buffer through the SPI. The way the ioLibrary_Driver does is assert the CS line, write the 32 bits while also reading 32 bits containing one byte of data, and de-asserting the CS line, and repeat that for the amount of bytes received.
What I want is to skip the de-assertion and following assertion part, and if I have 10 bytes in the RX buffer to be read, I assert CS once, send the 320 bits all at once on the MOSI line while also reading 320 bits on the MISO line, and de-assert the CS line.

I need this because the SPI is abstracted in the form of transactions with the ESP32, and mapping the model used by your driver is absurdly inefficient since each read and each write is one transaction in itself, so if I want to read or write 10 bytes, that’s 10 transactions, each 32 bits in size. But if it’s possible to put a series of read/write operations in only 1 transaction, or 320 bits in a single transaction, that would greatly improve performance of reading and writing to the TX and RX buffers on the W5100. But I don’t know if the chip works with it, because when I tried it, the data coming in from the MISO line was right for the 1 byte read/written, but for the 2nd byte onward, the usual 0x00 0x01 0x02 0x{data} was replaced with 0xFF’s on the MISO line.

So I want to know if that doesn’t work with the W5100, if it needs the CS line to be asserted and de-asserted for each byte read or written.

Hi.
If you are not going to share spi line with other devices, you don’t need to register CS assert or de-assert function. They will be connected to the null functions. It means that those cs functions in iolibrary will do nothing. But CS line should be asserted always. It should be connected to gnd or something.

/* CS function register */
reg_wizchip_cs_cbfunc( NULL, NULL); //add null or just comment this function not to use.

Even if you are gonna control CS line to share spi line with other devices, ioLibrary does not repeat that.
Because when you read/write multiple bytes via iolibrary, WIZCHIP_WRITE_BUF is gonna be used for it instead of WIZCHIP_WRITE. WIZCHIP_WRITE_BUF or WIZCHIP_READ_BUF is asserted and de-asserted only once when you read or write multiple bytes.

Thanks.

I think you still misunderstand me.

Here: ioLibrary_Driver/w5100.c at master · Wiznet/ioLibrary_Driver · GitHub
What does this mean?

Does it mean that I cannot change this?

  for(i = 0; i < len; i++)
  {
     //M20160715 : Depricated "M20150601 : Remove _select() to top-side"
     //            CS should be controlled every SPI frames
     WIZCHIP.CS._select();
     WIZCHIP.IF.SPI._write_byte(0xF0);
     WIZCHIP.IF.SPI._write_byte((((uint16_t)(AddrSel+i)) & 0xFF00) >>  8);
     WIZCHIP.IF.SPI._write_byte((((uint16_t)(AddrSel+i)) & 0x00FF) >>  0);
     WIZCHIP.IF.SPI._write_byte(pBuf[i]);    // Data write (write 1byte data)
     //M20160715 : Depricated "M20150601 : Remove _select() to top-side"
	  WIZCHIP.CS._deselect();
  }

to this

  WIZCHIP.CS._select();
  for(i = 0; i < len; i++)
  {
     //M20160715 : Depricated "M20150601 : Remove _select() to top-side"
     //            CS should be controlled every SPI frames
     WIZCHIP.IF.SPI._write_byte(0xF0);
     WIZCHIP.IF.SPI._write_byte((((uint16_t)(AddrSel+i)) & 0xFF00) >>  8);
     WIZCHIP.IF.SPI._write_byte((((uint16_t)(AddrSel+i)) & 0x00FF) >>  0);
     WIZCHIP.IF.SPI._write_byte(pBuf[i]);    // Data write (write 1byte data)
     //M20160715 : Depricated "M20150601 : Remove _select() to top-side"
  }
  WIZCHIP.CS._deselect();

??

Sorry! There is a mistake on our code in w5100.c
CS select and deselect line inside the for loop should be commented out.
The code will be fixed today. Nice day~

Thanks.

Then why doesn’t it work if I do that? Here, take a look
multiple_reads_w5100
Everything returned after the first byte on the MISO line is garbage.

Sorry I totally misunderstood what you were saying.

W5100 doesn’t support sequential reading.
So you need to assert and de-assert the CS line for every 4 spi frame.
image

So if the esp32 doesn’t have enough resources to control cs line every 4 spi frame, I think you need to use W5500.
W5500 supports sequential reading like the picture below.

Thanks.

1 Like