Easiest way is to get a single
SPI.sendcommand to transfer a big chunk of data...
var sendData = new Uint8Array(256); sendData.fill(0); // now in the loop: var result = SPI2.send(sendData); // result will have 256 bytes in it
You could also include any required SPI commands at the beginning of the sendData array, and could then use ArrayBufferViews to cut out the data you need without a copy:
var sendData = new Uint8Array(4+256); sendData.fill(0); sendData = ...; sendData = ...; sendData = ...; sendData = ...; // now in the loop: var result = SPI2.send(sendData); var data = new Uint8Array(sendData.buffer,4,256);
... and you can write that new array into another array with a simple
...bothers me that there is still no better solution for this pattern. I suggested a while ago to use the same pattern for SPI.send() as provided for SPI.write(), where an object can be passed which includes the data and a repetition count. That way, no extra memory has to be wasted to just keep the peripheral sending... @Gordon, what's the constraint that does not allow something like that?
Cool, I didn't know it was that simple (and that
spi.sendcan return arrays). But if I understand correctly, there is no way to shovel the data from SPI directly into the buffer of the waveform (waveforms bring their own buffers), so I always have to copy it? And I also have to temporarily allocate the space for the outgoing zeros, so effectively I need 3 times as much memory as the received payload?
I suggested a while ago to use the same pattern for SPI.send() as provided for SPI.write()
It tries to return a buffer of the same type as the arguments, so it's not quite as easy. It is possible though - I've just had other things on my mind and this is firmly in the 'optimisation' pile of things :)
there is no way to shovel the data from SPI directly into the buffer of the waveform (waveforms bring their own buffers), so I always have to copy
waveform.buffer.set(dataFromSPI), which is quite fast.
I need 3 times as much memory as the received payload?
If you don't absolutely need zeros, you could just pass the waveform's buffer in?
I got it to work! I posted my findings about waveform streaming here and I also published my module for interfacing Winbond flash memory.
@Gordon, good to know... and I know very well that there are priorities... ;-) In case you get there - even when later than sooner - choosing a reasonable default is good enough for to get started (usually UInt8). After some thinking, the passed object could pass the constructor in addition to data and repeat. As far as I see, @Dennis got it working, and small buffers render better results than large one and the extra memory to drive the sending is not a primary killer. I'm not surprised about the smaller buffer, because garbage collection is one of the primary challenge for real time things... I know that Espruino has a very smart memory management and thus an affordable garbage collect... I noticed though hick-ups when driving steppers (continuously)... which is time sensitive kind of waves a real time thing too.
Oh, garbage collection... yes, that could be the reason for some oddities.
@Gordon, one little tweak with (hopefully) a big impact could be to change the
SPI.writefunction so that you can pass a target buffer to it and it will write the results into that buffer instead of returning a new one.
...or buffer object, that would hold information about last (read and) written byte. Withe the read information the buffer can become cyclic.
I'd been wondering about that. I wonder whether thats almost another function call that's needed though? I think it would be hard to implement in a nice way with the existing
The existing functions could take additional optional arguments, and they could do the same as before if these arguments are omitted.
I'm not so much in favor of having a multitude of functions doing essentially the same thing in different ways; I find flexible calling patterns more elegant. But it's not that important, and if dedicated functions are more efficient, maybe that's the way to go.
I like the idea of being able to give it a buffer to fill too (or to have it send stuff from a buffer, while stuffing the response data into the same buffer?)
Yes - the send+receive into the same buffer seems like a great idea really. Nice and flexible.
I want to stream a waveform from an external SPI flash RAM (Winbond). Once the RAM has been prepared, reading back sequential data into is just a loop of
SPI2.send(0)instructions whose return values are sequentially written into a uInt8Array.
As mentioned in the docs, a function containing SPI calls cannot be compiled... how can I speed it up?