Trimming Down SPI

Technical questions regarding the XTC tools and programming with XMOS.
User avatar
rp181
Respected Member
Posts: 395
Joined: Tue May 18, 2010 12:25 am

Post by rp181 »

Yes, I assumed the variations is indeed from the slow sampling rate. When I sample the clock with my 100MHz analog scope, it is very consistent. My analog probes right now aren't comped properly so there is a bunch of noise, so I didn't post that.

I have never used strobed ports, so I will look into that.
After you execute:
sclk <: 0xAA;
sclk <: 0xAA;
sclk <: 0xAA;
sclk <: 0xAA;
sync(sclk);
spi_ss <: 1;

You cannot expect spi_ss <: 1 to execute after all the proceeding 4 statements instead it will probably come after 2nd downfalling clock.
Are you familiar with the sync() statement? I noticed you never used it in your code chunks, but the SPI code I started with had it, so I kept it. I do get junk if I comment that out. According to the xs1.h file, the sync statement will block untill all pending outputs are completed.

I output 4x 8 bit values. The sync statement would wait for the edges to be clocked out. At least that is how I understand it. Only when sclk is done outputting the buffer will sync() stop blocking, and then spi_ss is pulsed (after it is completed), and the same thing happens.
Also since the fifo is 4 deep the processor should block after 4x writes to sclk. I'm not sure how it's possible to trigger pmiso :> data with a 32bit clock expectation with only 16 clock cycles.
With the sync() method, the fifo should be clear after the first 4 bytes (all outputted). It then repeats, reaching 32 clock cycles for the miso port (8 bytes, 2x doing the above).

If it wasn't reaching 32 cycles, it would just hang forever (took me awhile to get it to not do that).

If I can confirm it is working properly now (on actual hardware), shouldn't I be guaranteed it will always work? The same code is just looped a bunch.

Thank you all for your input!


ale500
Respected Member
Posts: 259
Joined: Thu Sep 16, 2010 9:15 am

Post by ale500 »

I do not see why you need the sync before the read... Is it because the ADC needs some clock pulses before it delivers the data ?
If all ports are clocked, and you use the clock directly from the clock block (instead of outputting through the pin which is imho not needed as it already outputs the clock) and a strobed output to control ss wouldn't that be a better solution ?

Code: Select all


on stdcore[0]: clock sclkblk = XS1_CLKBLK_1;
...

   set_clock_div(sclkblk, SPI_DIV_RATE);
   configure_port_clock_output(sclk, sclkblk);
   configure_out_port_strobed_master(mosi, ss, sclkblk, 0);
   set_port_inv(ss);
   configure_in_port_no_ready(miso, sclkblk, 0);
   start_clock(sclkblk);
   
   // we output something
   mosi <: 0; // dummy write we can read miso now
   data8 <: miso;

that should take care of everything... I think...
User avatar
rp181
Respected Member
Posts: 395
Joined: Tue May 18, 2010 12:25 am

Post by rp181 »

Ah, I think you're right, I don't need the second sync() line, as the reading should wait until 32 bits have been clocked in.

I looked at strobed ports, and that does seem like a better solution. I will try that when I get home. The problem I can see is when I do:

sclk <: 0xAA;
sclk <: 0xAA;
sclk <: 0xAA;
sclk <: 0xAA;

Would SS be pulsed, or stay down for the whole duration? Also, what makes the SS go low when I am reading data? I only write once at the very beginning, just to configure the sequencer. From then on, it is just pulsing SS, and clocking the data in.
ale500
Respected Member
Posts: 259
Joined: Thu Sep 16, 2010 9:15 am

Post by ale500 »

As SS will be active during the whole output through MOSI (that is why I tied it to it) it will not toggle with clk.As long as you write to MOSI, it will remain asserted, just write again to MOSI before a new cycle begins (if not an empty cycle of sclk will be introduced). For 20 MHz clock it shouldn't be a problem.

Avoid this :

Code: Select all

  MOSI <: 0; // dummy
  long_function(); // <- SS will toggle here if this function takes too long, more than 1 cycle + length of buffered port
  MOSI <: 0; // dummy
User avatar
rp181
Respected Member
Posts: 395
Joined: Tue May 18, 2010 12:25 am

Post by rp181 »

Alright, I will try and out and see what gives the best performance!
ale500
Respected Member
Posts: 259
Joined: Thu Sep 16, 2010 9:15 am

Post by ale500 »

BTW, nice oscilloscope !
kster59
XCore Addict
Posts: 162
Joined: Thu Dec 31, 2009 8:51 am

Post by kster59 »

rp181 wrote: Are you familiar with the sync() statement? I noticed you never used it in your code chunks, but the SPI code I started with had it, so I kept it. I do get junk if I comment that out. According to the xs1.h file, the sync statement will block untill all pending outputs are completed.
p53 of Programming Xc on XMOS devices states:
The statement sync (p); causes the processor to wait until the next falling edge on which the last data in
the buffer has been driven for a full period, ensuring that the next instruction is
executed just after a falling edge.

If you do:
pa <: 0xaa; //assume 8 bit buffered port
sync(pa);
pdata <: 1;

Then pa will start producing cycles then you get the third statement somewhere in the middle. It doesn't block until pa has finished outputting then executes the pdata <:1

This is intended behavior and useful for ensuring the third statement executes at the intended time.

Someone at xmos can correct me if I am wrong.
User avatar
rp181
Respected Member
Posts: 395
Joined: Tue May 18, 2010 12:25 am

Post by rp181 »

Isn't the keyword "last"? The xs1.h file says:

Waits output all until a port has completed any pending outputs and the
last port-width bits of data has been held on the pins for one clock period.

The way I am interpreting this (and how I am interpreting my results) is that it does wait for all of the data in the buffer and fifo. I will try some more code later, to see if what you are saying is correct.
kster59
XCore Addict
Posts: 162
Joined: Thu Dec 31, 2009 8:51 am

Post by kster59 »

Seems I was wrong about sync. After running it in the simulator it does indeed block until all the data is outputted.

However this leads to the second problem, if it blocks until all the clock cycles are gone, how can your miso :> data input get any clock cycles since it follows the sync?
User avatar
rp181
Respected Member
Posts: 395
Joined: Tue May 18, 2010 12:25 am

Post by rp181 »

I was under the impression that buffered in ports are constantly sampling, with a rolling buffer. Old data is pushed out and new data is stored every clock edge (hence the neccesity of the clearbuf statement - and empty buffer means it has to wait for atleast 32). I forgot the clearbuf once, and I just get garbage (mangled points, I assumed).

EDIT: Also, this is advantageous as SPI is actually simultaneous read/write. If it wasn't rolling, this wouldn't be feasible.