machine.SPI.write() taking too long?
machine.SPI.write() taking too long?
I measured how many CPU ticks does it take to write 2 bytes with machine.SPI.write() function and it is always more than 9000 CPU ticks. SPI baudrate is set to 1000000.
Is it somehow possible to accelerate SPI write command execution time?
Is it somehow possible to accelerate SPI write command execution time?
- danicampora
- Posts: 342
- Joined: Tue Sep 30, 2014 7:20 am
- Contact:
Re: machine.SPI.write() taking too long?
Hello,
A way to speed it up is to cache the method in a local variable, e.g.:
Increasing the baudrate to 10 MHz might help as well.
Cheers,
Daniel
A way to speed it up is to cache the method in a local variable, e.g.:
Code: Select all
write = spi.write
write(...)
Increasing the baudrate to 10 MHz might help as well.
Cheers,
Daniel
Re: machine.SPI.write() taking too long?
Daniel,
I did several tests and here are the results:
Cashing spi.write method speeds up sequential SPI writes by approx. 2,5%
Switching baudrate from 1MHz to 10Mhz speeds up sequential SPI writes by approx. 7%
Combined - approx. 10%
As you see, the difference in sequential execution of SPI writes is not significant.
Here are traces recorded by logic analyzer for sending of integer converted to 2-byte payload two times via cashed spi.write method. I believe that there could be some more efficient way how to do the conversion.
The test sequence:
And the traces:
Signals: CS/NSS, SCK, MOSI, MISO As you can see, time difference between those two SPI transfers is really long. Is there anything I could do to make it shorter?
It is necessary to raise CS/NSS pin of SPI slave (2-channel 12-bit DAC MCP4922) to high level after every two transffered bytes.
I did several tests and here are the results:
Cashing spi.write method speeds up sequential SPI writes by approx. 2,5%
Switching baudrate from 1MHz to 10Mhz speeds up sequential SPI writes by approx. 7%
Combined - approx. 10%
As you see, the difference in sequential execution of SPI writes is not significant.
Here are traces recorded by logic analyzer for sending of integer converted to 2-byte payload two times via cashed spi.write method. I believe that there could be some more efficient way how to do the conversion.
Code: Select all
class GalvoBoard():
...
def _sendGalvoData(self, data):
data_bytes = data.to_bytes(2)
data_array = bytearray([data_bytes[1],data_bytes[0]])
self.spiNSS.value(0)
self.spiWrite(data_array)
self.spiNSS.value(1)
Code: Select all
def seqTest(self):
print("Starting sequence test")
startTime = time.ticks_ms()
self.galvoBoard._sendGalvoData(16962)
self.galvoBoard._sendGalvoData(16962)
print("Scan test ended in %sms" % (time.ticks_ms() - startTime))
Signals: CS/NSS, SCK, MOSI, MISO As you can see, time difference between those two SPI transfers is really long. Is there anything I could do to make it shorter?
It is necessary to raise CS/NSS pin of SPI slave (2-channel 12-bit DAC MCP4922) to high level after every two transffered bytes.
Re: machine.SPI.write() taking too long?
Daniel, I did some more experiments using following simple code in main.py:
I omitted switching of CS pin on purpose just to determine raw speed of SPI interface. I set the frequency to 8MHz because of limited sample rate of my logic analyzer. Interface is set to operate in 16-bit mode because this is word width my SPI slave is using.
Here are two traces from the logic analyzer - detail and sequence. As you can see, time difference between two transfers of 2-byte payload is approx. 42us, which translates to 47,6 kbytes/sec.
In this thread user Oliv suggested to activate DMA mode in WiPy's FW: http://forum.micropython.org/viewtopic. ... ency#p7709
You explained that it is not enabled because of impact to heap space. Could you please elaborate more on how significant the impact would be?
Is it possible to implement some global settings whether to use DMA for SPI at the expense of free heap size?
Code: Select all
import gc
gc.disable
spi = machine.SPI(machine.SPI.MASTER, baudrate=8000000, polarity=1, phase=1, bits=16, pins=('GP14', 'GP16', 'GP15'))
spiWrite = spi.write
while True:
spiWrite(b'\x00\x00')
Here are two traces from the logic analyzer - detail and sequence. As you can see, time difference between two transfers of 2-byte payload is approx. 42us, which translates to 47,6 kbytes/sec.
In this thread user Oliv suggested to activate DMA mode in WiPy's FW: http://forum.micropython.org/viewtopic. ... ency#p7709
You explained that it is not enabled because of impact to heap space. Could you please elaborate more on how significant the impact would be?
Is it possible to implement some global settings whether to use DMA for SPI at the expense of free heap size?
- pythoncoder
- Posts: 5956
- Joined: Fri Jul 18, 2014 8:01 am
- Location: UK
- Contact:
Re: machine.SPI.write() taking too long?
I'm not convinced DMA would help. It's sending the two bytes quickly: the time is taken executing the while loop. It might be instructive to look at the timing for (fragment):
Code: Select all
while True:
spiWrite(b'\x00\x00')
spiWrite(b'\x00\x00')
Peter Hinch
Index to my micropython libraries.
Index to my micropython libraries.
Re: machine.SPI.write() taking too long?
I was thinking of doing some raw test, by just toggling a GPIO pin. From tests I made with PyBoard I learned that the while loop plus function call would take about 6us per loop at 168 MHz (see https://github.com/robert-hh/SSD1963-TF ... or-PyBoard, README.md, section Remarks). Since WiPy runs at 80MHz, at least twice the time should be needed.
The underlying SPI tranfer code should be fast. Therefore data should be sent & received in as big chunks as possible.
The underlying SPI tranfer code should be fast. Therefore data should be sent & received in as big chunks as possible.
- pythoncoder
- Posts: 5956
- Joined: Fri Jul 18, 2014 8:01 am
- Location: UK
- Contact:
Re: machine.SPI.write() taking too long?
@RoberthhThere's a big disparity between your entirely reasonable estimate of 12uS and the 42uS measured by @danielm. A GPIO toggle would be informative.
Peter Hinch
Index to my micropython libraries.
Index to my micropython libraries.
Re: machine.SPI.write() taking too long?
Obviously it is. I just wanted to point out, that the python part is often much slower than the low level drivers.
Re: machine.SPI.write() taking too long?
Unfortunatelly I cannot send data in big chunks because I need to toggle CS pin in between each two bytes sent to SPI slave.
Please take a look at these test results of forum member @manitou. Not sure if he made the comparison for CC3200 platform with pure compiled C code or with MicroPython. It seems that DMA might help to speed up SPI communication.
CC3200 LAUNCHPAD @ 80MHz (SPI max clock 20mhz)
SPI
SPI clock transfer DMA (4-byte)
2MHz 1.2 mbs 1.9
4MHz 1.7 mbs 3.8
5MHz 4.8
10MHz 2.2 mbs 9.2
20MHz 2.7 mbs 17.2
https://github.com/manitou48/DUEZoo/blo ... PIperf.txt
Please take a look at these test results of forum member @manitou. Not sure if he made the comparison for CC3200 platform with pure compiled C code or with MicroPython. It seems that DMA might help to speed up SPI communication.
CC3200 LAUNCHPAD @ 80MHz (SPI max clock 20mhz)
SPI
SPI clock transfer DMA (4-byte)
2MHz 1.2 mbs 1.9
4MHz 1.7 mbs 3.8
5MHz 4.8
10MHz 2.2 mbs 9.2
20MHz 2.7 mbs 17.2
https://github.com/manitou48/DUEZoo/blo ... PIperf.txt
Re: machine.SPI.write() taking too long?
The loop test gave 12.8 µs per loop iteration. Any additional code makes it slower. Test code:
Regards
Code: Select all
from machine import Pin
#
p_out = Pin('GP3', mode=Pin.OUT)
while True:
p_out.toggle()