Batch SPI settable pause between bytes

Want a new feature? Discuss what you would like to see in Ultibo.
Brutus
Posts: 22
Joined: Sun Jan 20, 2019 1:24 pm

Batch SPI settable pause between bytes

Postby Brutus » Mon Jan 28, 2019 2:39 pm

Hi everyone,

I have an SPI communication running with an ATMega 328P (arduino uno hardware) which uses hardware SPI interrupts.
I do very little in the ATMega interrupt, basically using the first received byte to decide where to store the second received byte.

The issue is that I had to decrease the SPI bitrate from 1 MHz to 100kHz in Ultibo because otherwise the AT Mega wouldn't see the split between the two bytes.

If I use byte per byte sending (more than one SPIReadWrite with 1 byte sending each time), I can set the clock to 1MHz without any issue, probably because of the 500µs delay between each sending created by the scheduler.

So my humble request would be to introduce a settable inbetween-bytes delay in the SPIReadWrite function parameters in order to allow slow SPI peripherals to recover inbetween bytes when Ultibo is doing batch SPI with this function.

Thanks for reading! :)
User avatar
Ultibo
Site Admin
Posts: 2121
Joined: Sat Dec 19, 2015 3:49 am
Location: Australia

Re: Batch SPI settable pause between bytes

Postby Ultibo » Tue Jan 29, 2019 10:22 am

Brutus wrote:I have an SPI communication running with an ATMega 328P (arduino uno hardware) which uses hardware SPI interrupts.
I do very little in the ATMega interrupt, basically using the first received byte to decide where to store the second received byte.

The issue is that I had to decrease the SPI bitrate from 1 MHz to 100kHz in Ultibo because otherwise the AT Mega wouldn't see the split between the two bytes.

If I use byte per byte sending (more than one SPIReadWrite with 1 byte sending each time), I can set the clock to 1MHz without any issue, probably because of the 500µs delay between each sending created by the scheduler.

So my humble request would be to introduce a settable inbetween-bytes delay in the SPIReadWrite function parameters in order to allow slow SPI peripherals to recover inbetween bytes when Ultibo is doing batch SPI with this function.

Two quick questions:

1. Do you have any idea of the length of the interbyte delay you would need for this to work with your device?

2. Can you have a look at the issue described here (https://raspberrypi.stackexchange.com/q ... byte-delay) and here (https://www.raspberrypi.org/forums/view ... 4&t=181154) and tell us if those match with your issue? We recently added the change described in the second link to Ultibo to remove the "unwanted" interbyte delay but we could easily add a flag to turn that behaviour on or off if that would cover your requirement.
Ultibo.org | Make something amazing
https://ultibo.org
Brutus
Posts: 22
Joined: Sun Jan 20, 2019 1:24 pm

Re: Batch SPI settable pause between bytes

Postby Brutus » Wed Jan 30, 2019 1:51 am

Ultibo wrote:Two quick questions:

1. Do you have any idea of the length of the interbyte delay you would need for this to work with your device?

2. Can you have a look at the issue described here (https://raspberrypi.stackexchange.com/q ... byte-delay) and here (https://www.raspberrypi.org/forums/view ... 4&t=181154) and tell us if those match with your issue? We recently added the change described in the second link to Ultibo to remove the "unwanted" interbyte delay but we could easily add a flag to turn that behaviour on or off if that would cover your requirement.


1. Not really, it's probably no more than a few microseconds, but I have very little clue about it yet.

2.Thanks for the links, the first link talking about the MLX90316 sensor requiring inter byte delay matches my problem.
A flag might not cover every case. Some people might need to put some more code in the SPI interrupt of the AVR and in that case the inter byte might become inappropriate again.
I would suggest an SPI clock iteration delay instead of a simple flag.

If this helps, I can bit bang the SPI and find out the required inter byte for my application, but this will only cover my (not so) specific case.

Thanks again for your answers.
Gavinmc42
Posts: 1460
Joined: Sun Jun 05, 2016 12:38 pm
Location: Brisbane, Australia

Re: Batch SPI settable pause between bytes

Postby Gavinmc42 » Wed Jan 30, 2019 3:21 am

Thanks Brutus for putting me onto Melexis.

Melexis have some interesting versions.
MLX90393 is a SPI/i2c one with 4 addresses :D
4 different types so 16 sensors all on one i2c bus?
I was looking for something like that last week.

Wanted angle sensors to make a robot arm puppet to teach a robot arm ;)
I hate reverse kinematic matrix calculations, easier just to show the arm how to move?
More axes = full body animatronic digitizers. Teaching bots how to walk?
Full body motion capture?

Just spent 2 days writing a 24bit SPI routine for a quad DAC, still debuging it.
SPI is not SPI, such a mix and then you thow in an Arduino :o
Even with a CRO this stuff is hard to figure out.

2 days with Ultibo is nothing, I had already spent 2 weeks with a TI DSP tool and got nowhere.
Mostly fighting the tool not actually doing SPI.
Ultibo is becoming the one hammer to iron out all problems :D
User avatar
Ultibo
Site Admin
Posts: 2121
Joined: Sat Dec 19, 2015 3:49 am
Location: Australia

Re: Batch SPI settable pause between bytes

Postby Ultibo » Thu Jan 31, 2019 10:42 am

Brutus wrote:A flag might not cover every case. Some people might need to put some more code in the SPI interrupt of the AVR and in that case the inter byte might become inappropriate again.
I would suggest an SPI clock iteration delay instead of a simple flag.

We can add a configurable interbyte delay option to the SPI API, something like SPIDeviceSetByteDelay() or similar. The only caveat will be that it will have a limitation on how it can be used.

Because adding a small delay (potentially a few microseconds) will need to be done as a loop inside SPIDeviceWriteRead() and associated functions the delay will only be able to be applied in PIO mode, there is no way to make the DMA controller insert a delay and adding it to interrupt mode would likely mean adding a loop inside the interrupt handler which would be very bad for performance.

The one question this does raise is why not simply reduce the clock speed? In your earlier post you said it works if you set it to 100Khz instead of 1MHz, wouldn't adding a delay between every byte give effectively the same (or less) throughput than reducing the clock speed?
Ultibo.org | Make something amazing
https://ultibo.org
Brutus
Posts: 22
Joined: Sun Jan 20, 2019 1:24 pm

Re: Batch SPI settable pause between bytes

Postby Brutus » Fri Feb 01, 2019 2:25 am

I did a bit of research and found this:

// USART_SPIReadWrite(uint8_t data)
//
// Taken from ATmega328P datasheet (Atmel-42735B-ATmega328/P_Datasheet_Complete-11/2016, p. 258)
// and with a couple of tips from: https://feilipu.me/2015/02/17/avr-atmeg ... spi-mspim/
void USART_SPIWrite(uint8_t* data, uint8_t noOfBytes)
{
while (noOfBytes > 0)
{
// Wait for empty transmit buffer
while ( !( UCSR0A & (1 << UDRE0)) )
;

// Put data into buffer (this sends the data)
UDR0 = *(data++);
noOfBytes--;
}

_delay_us(1); // *** NOTE: this is necessary for proper sync of signals ***
// Wait until transmission is complete
while ( !( UCSR0A & (1 << TXC0)) )
;
}


It seems like a 1µs delay is required for sending a byte, so it should be safe to assume a delay of the same magnitude is required on receiving too.

Ultibo wrote:We can add a configurable interbyte delay option to the SPI API, something like SPIDeviceSetByteDelay() or similar. The only caveat will be that it will have a limitation on how it can be used.

Because adding a small delay (potentially a few microseconds) will need to be done as a loop inside SPIDeviceWriteRead() and associated functions the delay will only be able to be applied in PIO mode, there is no way to make the DMA controller insert a delay and adding it to interrupt mode would likely mean adding a loop inside the interrupt handler which would be very bad for performance.


Haven't thought about DMA. I understand your point...

Ultibo wrote:The one question this does raise is why not simply reduce the clock speed? In your earlier post you said it works if you set it to 100Khz instead of 1MHz, wouldn't adding a delay between every byte give effectively the same (or less) throughput than reducing the clock speed?


It actually really depends on the delay between the bytes.
Let's say I need to do a continuous data transfer for 10 milliseconds and my inter byte delay is 5µs (worst case scenario).
At 100Khz, this means 100000(Hz)*0.01(second)/8(bits) = 125 bytes transmitted (no inter byte delay required).
At 1000Khz, this means 1000000(Hz)*0.01(second)/8(bits) would mean 1250 bytes transmitted if we had no inter bytes delay so we need to remove 5*1250=6250µs.
We end up with around 3750µs remaining for the data: 1000000(Hz)*0.00375(second)/8(bits) = 468.75Hz (I know, my calculation is wrong and just a very rough approximation).

This is 3.6 times more data in the same period, so a significant difference even with this worst case scenario with a pessimistic approximation.

EDIT: I will do some tests by adding Microsecond delays in BCM2710SPI0ReadFIFO and see if it helps in getting faster SPI communication with the ATMega.
User avatar
Ultibo
Site Admin
Posts: 2121
Joined: Sat Dec 19, 2015 3:49 am
Location: Australia

Re: Batch SPI settable pause between bytes

Postby Ultibo » Sat Feb 02, 2019 12:56 am

Brutus wrote:It seems like a 1µs delay is required for sending a byte, so it should be safe to assume a delay of the same magnitude is required on receiving too.

Given that the errata I pointed to earlier added a 1.5 bit time gap between each byte then it should give you a 1.5us delay at 1MHz.

You can try removing the fix we added by commenting out the lines which set the DLEN value here and here and rebuilding your RTL.

With that change removed the gap should be present again for both PIO and IRQ mode (it never applies to DMA mode).

Brutus wrote:EDIT: I will do some tests by adding Microsecond delays in BCM2710SPI0ReadFIFO and see if it helps in getting faster SPI communication with the ATMega.

BCM2710SPI0ReadFIFO might not be the correct place to add a delay as that will apply to IRQ mode as well as PIO mode, the better choice would be to look at the loop here and apply the delay during each iteration.

You will also need to pass a flag or other value to BCM2710SPI0WriteFIFO to tell it to write only 1 byte at a time otherwise it will attempt to fill the FIFO on each pass.
Ultibo.org | Make something amazing
https://ultibo.org
Brutus
Posts: 22
Joined: Sun Jan 20, 2019 1:24 pm

Re: Batch SPI settable pause between bytes

Postby Brutus » Sat Feb 02, 2019 3:12 am

Thank you so much for your help.

I'll post the results of the tests when I done with it.

Return to “Feature requests”

Who is online

Users browsing this forum: No registered users and 0 guests