SPI delay

Technical questions regarding the XTC tools and programming with XMOS.
User avatar
CousinItt
Respected Member
Posts: 360
Joined: Wed May 31, 2017 6:55 pm

Post by CousinItt »

Good work. I hope xmos takes note for their next release.


User avatar
RedDave
Experienced Member
Posts: 77
Joined: Fri Oct 05, 2018 4:26 pm

Post by RedDave »

I have now transferred the code over to my actual application and the phenomenon has resurfaced.

The ADC read is triggered every 10us for 10 triggers. It then waits 10ms before another block of 10 triggers. This is so that a laser that is being fired is eye safe. Final application will be continuous 10us firing.

When I trigger the 'scope I sometimes see that the 10 reads happen successfully in good time (~8us per ADC read) and are ready for the following read.
Most of the time this is not the case, it will perform a few reads at 8us per read and then perform one or two 600us.

As far as I can tell in my test application the reads were consistently 8us.

Any explanation of what the sync() is waiting for in the spi_master would be very helpful.
User avatar
mon2
XCore Legend
Posts: 1913
Joined: Thu Jun 10, 2010 11:43 am
Contact:

Post by mon2 »

sync operation is explained inside the following document:


https://www.google.com/url?sa=t&rct=j&q ... z3IIwt2nQZ
User avatar
RedDave
Experienced Member
Posts: 77
Joined: Fri Oct 05, 2018 4:26 pm

Post by RedDave »

There is nothing that I can find in that document that explains the 600us wait for the sync. I could understand a few clock cycles, but not many thousands!

I have configured the ssn port with a different clock, since otherwise the clock that drives the chip select line is being stopped and started with the SPI clock. This is not desirable. However, this did not help.

Anecdotally, when the tile is busy the phenomenon is worse. One of the cores has a "default" case in its looped select. It is continually polling for new data. If this default is removed then the SPI read (in a different task) happens a lot more reliably. I have refactored that task to not use the default. This is good because it has resulted in more lean code.

But I am left with SPI reads that work correctly and in good time about 99.5% of the time. Roughly 5 in every 1000 reads takes this massive 600us. I still have no real explanation for that.

I have modified the lib_spi as a test.

I have replaced this block

Code: Select all

                p_ss[selected_device] <: 1 @ time;

                //TODO should this be allowed? (0.6ms max without it)
                if(ss_deassert_time > 0xffff)
                   delay_ticks(ss_deassert_time&0xffff0000);

                time += ss_deassert_time;

                p_ss[selected_device] @ time <: 1;
with an immediate write

Code: Select all

p_ss[selected_device] <: 1;
.

This seems to fix things and the write is now reliable.

But I do not understand why the original causes problems. I am passing ss_deassert_time=4. So my understanding of the code is this.

1) Write 1 to the port and record the time of the write in 'time'
2) If statement will not be entered because my value is small.
3) add 4 ticks to time.
4) Cause 1 to be written to the port, 4 ticks after the previous write. This will have no effect [writing the same value], but will mean that the sync() or writing of the 0 in the subsequent begin_transaction cannot happen until the dessert period.

So, the original code and my code, is that the next transaction cannot be run for a further 83ns. (given 48MHz clock). This is insufficient machine cycles to get around to it anyway.
User avatar
RedDave
Experienced Member
Posts: 77
Joined: Fri Oct 05, 2018 4:26 pm

Post by RedDave »

New hypothesis.

My deassert time is too low.

By the time this line

Code: Select all

p_ss[selected_device] @ time <: 1;
is executing the time has already passed. The system therefore waits for the port clock to completely loop around. Could that be 600us?

[Edit: Just noticed the comment in the code I posted above. It makes a mention of 0.6ms being the maximum deassert time without the delay_ticks. This implies that is the wrap around time.]

This would explain why the phenomenon is worse when the tile is busy as the chance of not getting to that line within 83ns is increased.

Changing deassert time to 10 and using a 48MHz clock on the port and all seems to be working (for now).
User avatar
RedDave
Experienced Member
Posts: 77
Joined: Fri Oct 05, 2018 4:26 pm

Post by RedDave »

After some testing, this has been confirmed.

The deassert time passed to end_transaction must be at least enough time for it to calculate when the end of that deassert is. Otherwise it waits for the clock to wrap around to that value again (0.6ms).

With the 48MHz clock that I have set up and a deassert time of 4, this was usually enough time, depending on tile load. It was thus failing ~0.5% of the time. A value of 10 was sufficient to make it reliable.

---

I perceive this as a bug in the lib_spi code.
Post Reply