What happens when the write buffer and the read buffer are the same?

 address, int count) {
            byte[] _data = new byte[count + 3];
            port.WriteRead(_data, _data);
            return _data;
        }

(port is an instance of SPI)
Let’s say I give the WriteRead method the same byte array. What happens? Does each byte of the array get written and then overwritten?

I’ve used the same write and read buffer, but I always used the overload that let’s you specify offsets, delays, and lengths. I did that to reduce the number of buffer allocations. I just used a single pre-allocated buffer. Since every api sequence in the wiznet chips needs to be executed atomically and mutually exclusively, it was safe to reuse the buffer. But I have never used the same offset in the same array, which is what your example shows.

@ mcalsyn - Hey, true; that’s pretty smart. So you pre-compose every possible command, and alloc it in a global write buffer, then it’s just about writing form the correct place.

In that case I could setup a write buffer with every address. The my getters and setters just read and write from and to that array, then call a method giving it the index to start writing from, and the length to write to.


using System;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using System.Threading;

namespace PolyNCBeta {
    public static class Wiznet5100 {

        static OutputPort reset = new OutputPort((Cpu.Pin)FEZCerbuino.Pin.Digital.D9, true);
        static InterruptPort interrupt = new InterruptPort((Cpu.Pin)FEZCerbuino.Pin.Digital.D8, false, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeLevelLow);
        static SPI.Configuration config = new SPI.Configuration((Cpu.Pin)FEZCerbuino.Pin.Digital.D10,
            false, // Chip Select, active-low
            1, // 1 millisecond setup time
            1, // 1 millisecond hold time
            true, // Clock low on idle
            true, // Data valid on falling edge         
            625, // 5Mhz Clock Rate
            SPI.SPI_module.SPI1);
        static SPI port = new SPI(config);

        static byte[] commonBuffer = new byte[]{
            0x00, //Mode Register: index 0, 4 bytes long
            0x00, 
            0x00, 
            0x00, 
            0x00, //Gateway Address: index 4: 7 bytes long
            0x00, 
            0x01,
            0x00, // IP starts at index 7
            0x00, 
            0x00,  
            0x00 
        };
        
        const int GATEWAY_ADDRESS = 4;
        public static byte[] Gateway{
            get {
                Read(GATEWAY_ADDRESS, 7);
                return new byte[]{ commonBuffer[GATEWAY_ADDRESS + 3], 
                    commonBuffer[GATEWAY_ADDRESS + 4],
                    commonBuffer[GATEWAY_ADDRESS + 5], 
                    commonBuffer[GATEWAY_ADDRESS + 6]};
            }
            set{
                value.CopyTo(commonBuffer, GATEWAY_ADDRESS + 3);
                Write(GATEWAY_ADDRESS, 7);
            }
        }

        public static void Reset() {
            reset.Write(false);
            Thread.Sleep(10);
            reset.Write(true);
        }

        static void Write(int fromOffset, int length){
            commonBuffer[fromOffset] = 0xF0;
            port.WriteRead(commonBuffer, fromOffset, length, new byte[0], 0, 0, 0);
        }

        static void Read(int fromOffset, int length) {
            commonBuffer[fromOffset] = 0x0F;
            port.WriteRead(commonBuffer, fromOffset, length, commonBuffer, fromOffset + 3, length - 3, 3);
        }
    }   
}

The beginnings of craziness. Just to clarify that last value in the WriteRead: startReadOffset :- The offset in time, measured in transacted elements from writeBuffer, when to start reading back data into readBuffer. This means that the system will only start putting values into the read buffer AFTER a certain number of write buffer values have been sent; Is that correct?

Correct. The wording in the docs is terrible - no surprise there. SPI writes a byte and reads a byte at the same time. The last argument is how many of those reads to throw away before starting to write into your buffer. Since Wiznet needs three bytes of preamble, setting this to 3 means you can avoid storing the preamble responses into your array. FWIW, the Wiznet W5500 sends 1, 2, 3 back during the preamble - not sure what W5100 does.


    public static void Test() {
        port.Write(new byte[] {0xF0, 0x00, 0x01, 192 });
        byte[] _read = new byte[4];
        port.WriteRead(new byte[] { 0x0F, 0x00, 0x01, 0 }, _read);

    }

Well try as I may I can’t get it to work. I am pretty sure it’s hooked up correctly (pretty sure). It just returns a bunch of zeros into the _read buffer

EDIT: reset was enabled. Now it returns 0,2,4,0

Ok I think I got it to talk properly


    static SPI.Configuration config = new SPI.Configuration((Cpu.Pin)FEZCerbuino.Pin.Digital.D10,
        false, // Chip Select, active-low
        1, // 1 millisecond setup time
        1, // 1 millisecond hold time
        true, // Clock low on idle
        false, // Data valid on rising edge         
        625, // 5Mhz Clock Rate
        SPI.SPI_module.SPI1);

Data is valid on rising edge not falling edge.

@ mcalsyn - W5500 supports Sequential Data Read/Write. It processes the data from the base (the Offset Address which is set for 2/4/N byte Sequential data processing) and the next data by increasing the Offset Address (auto increment addressing) by 1.

Looks like that is only supported on the W5500 not the W5100.

Now I shed tears of blood.

@ Mr. John Smith - It’s not just the leading edge of technology that is the ‘bleeding edge’. The trailing edge can cut too.

1 Like

@ mcalsyn - Yea but there is no option to configure the trailing clock edge.

1 Like

Well, the thing is unstable. Sometimes it works, sometimes it doesn’t and I have no idea why. How on earth does the GHI driver work?

I suspect “very well” isn’t the answer you are looking for.

Again, my experience is very 5500-specific, but every time you write to the CR register (global or per-socket), are you waiting for it to drop to 0 again, which indicates that the command was executed? Things go badly if you set CR before it has completed the previous command.

Each time IR (global or per-socket) becomes non-zero, are you writing that bit back to IR again to clear the interrupt? If not, you will get repeat indications of interrupts.

After each recv or send are you updating the appropriate WR pointers and for recv, send (and listen, connect and accept, I think) setting CR to indicate that you have completed the previous read/write?

There’s a ton of fiddly order-sensitive writes to take care of, and a fair bit of reading SR, IR, MR and CR required to pace things correctly. In my experience, doing the register dance in the wrong order or missing a step is what causes unpredictable behavior.

…there’s a reason it took me a month of spare-time investment to get the 5500 driver working reliably

Actually, no I haven’t got that far. I’m just trying to read one value from the device that is known to be non zero. It’s not working out thus far.

1ms is a long time in processor speak. I normally use 0 for both of these and never had issues with SPI working.

@ Dave McLaughlin - Cool, I’ll adopt 0 in all my drivers from now on.