SPI clock and edge

Technical questions regarding the XTC tools and programming with XMOS.
Post Reply
User avatar
ahenshaw
Experienced Member
Posts: 96
Joined: Mon Mar 22, 2010 8:55 pm

SPI clock and edge

Post by ahenshaw »

I'm using the xmos-supplied SPI library with a device that seems to be having a problem with the clocking scheme.

The SPI code produces a signal that looks like this

Code: Select all

      __                   ____
SEL    \__________________/
      ____   _       _   ______
CLK       \_/ \_/ ... \_/ 
I hope this is readable.
The spec sheet for the device calls for the clk signal to be low when the SEL line goes low.

So, I modified the code so that the CLK starts and stop in a low state, but now my CLK line goes low as the data is clocked out of MOSI (which makes some sense, as it is tied to the clock block for MOSI). It looks like I need to delay the CLK signal by half-a-clock period. Is there a straightforward method for handling this?

Here's the relevant code:

Code: Select all

void spi_init()
{
	// configure ports and clock blocks
	configure_clock_rate(blk1, 100, SPI_CLOCK_DIV);
	configure_out_port(spi_sclk, blk1, 0);
	configure_clock_src(blk2, spi_sclk);
	configure_out_port(spi_mosi, blk2, 0);
	configure_in_port(spi_miso, blk2);
	clearbuf(spi_mosi);
	clearbuf(spi_sclk);
	start_clock(blk1);
	start_clock(blk2);
	spi_sclk <: 0x00;   // here's one of my changes
}

// read in response to previous byte, while issuing a new byte.
unsigned char spi_in_out_byte(unsigned char data)
{
    // MSb-first bit order - SPI standard
    unsigned x = bitrev(data) >> 24;
    clearbuf(spi_miso);
    spi_mosi <: x;
    spi_sclk <: 0xaa;
    spi_sclk <: 0xaa;
    spi_sclk <: 0x0;
    sync(spi_sclk);
    spi_miso :> x;
    return bitrev(x) >> 24;
}


User avatar
Andy
Respected Member
Posts: 279
Joined: Fri Dec 11, 2009 1:34 pm

Post by Andy »

Do you have a link to the SPI library? I'd quite like to look at it as I'm currently working on my own SPI driver.

There is indeed a function in xs1.h that should do what you request:

Code: Select all

/** Sets the delay on the pins connected to the port. The input signals sampled on the
 *  port's pins are delayed by this number of processor-clock cycles before they
 *  they are seen on the port. The default delay on the pins is 0.
 *  The delay must be set to values in the range 0 to 5 inclusive.
 *  If there are multiple enabled ports connected to the same pin then the delay
 *  on that pin is set by the highest priority port.
 *  \param p The port to configure.
 *  \param n The number of processor-clock cycles by which to delay the input
 *           signal.
 *  \sa set_clock_rise_delay
 *  \sa set_clock_fall_delay
 */
void set_pad_delay(void port p, unsigned n);
Hope this is of use.
User avatar
ahenshaw
Experienced Member
Posts: 96
Joined: Mon Mar 22, 2010 8:55 pm

Post by ahenshaw »

The code is contained in spi_master.zip, which you can find on the xmos.com site.

Unfortunately, it doesn't look like the fix that you suggested will work for me, as it only accommodates a pretty small pad delay. The SPI signal that I need to generate is clocking too slowly for that.

However, I believe that I have a working solution - I had to add a third clock block which controls the MOSI pin. I then set it's clock bit pattern to 0x5555, instead of 0xAAAA and the data pops out one-half of a clock period ahead of the SPI_CLK signal. Here's the relevant code:

Code: Select all

clock blk1 = XS1_CLKBLK_1;
clock blk2 = XS1_CLKBLK_2;
clock blk3 = XS1_CLKBLK_3;

void spi_init()
{
    // configure ports and clock blocks
    configure_clock_rate(blk1, 100, SPI_CLOCK_DIV);
    configure_out_port(spi_sclk, blk1, 0);
    configure_out_port(spi_mosi_clk, blk1, 0);
    configure_clock_src(blk2, spi_sclk);
    configure_clock_src(blk3, spi_mosi_clk);
    configure_out_port(spi_mosi, blk3, 0);
    configure_in_port(spi_miso, blk2);
    clearbuf(spi_mosi);
    clearbuf(spi_sclk);
    clearbuf(spi_mosi_clk);
    start_clock(blk1);
    start_clock(blk2);
    start_clock(blk3);
    spi_sclk <: 0x00;
    spi_mosi_clk <: 0xFF;
}

unsigned char spi_in_out_byte(unsigned char data)
{
    // MSb-first bit order - SPI standard
    unsigned x = bitrev(data) >> 24;
    clearbuf(spi_miso);
    spi_mosi <: x;
    spi_mosi_clk <: 0x55;
    spi_mosi_clk <: 0x55;
    spi_sclk <: 0xaa;
    spi_sclk <: 0xaa;
    spi_sclk <: 0x0;
    sync(spi_sclk);
    spi_miso :> x;
    return bitrev(x) >> 24;
}

Post Reply