32-bit SPI setup (urgent)

Technical questions regarding the XTC tools and programming with XMOS.
allanw
New User
Posts: 2
Joined: Thu Jan 19, 2012 8:58 pm

32-bit SPI setup (urgent)

Post by allanw »

Hi guys, I'm doing a week-long hackathon type event for my school which is making a propeller clock out of RGB LED's being driven by a 12-bit color resolution shift register. I've been trying to figure out how to modify the SPI library to send out data at 32-bits in SPI mode 0 at around 16MHz, and I've looked at a lot of threads but found no definitive answer. We've been using an ARM Cortex as the MCU but have an XMOS X1-A in case we need more processing horsepower. Anyway, we only have 24 hours until the demo and I'd like to be able to quickly switch over to the XMOS.

Supposedly this is the code for 8-bit SPI. I'm not sure I understand why sclk is being written to twice. I'll modify the ports to be 32-bit buffered and get rid of the bitshift, but how do I change the sclk statements? Should I just make them 0xAAAAAAAA?

Code: Select all

void spi_out_byte(unsigned char data)
{
   // MSb-first bit order - SPI standard
   unsigned x = bitrev(data) << 24;
   spi_mosi <: x;
   spi_sclk <: 0xAA;
   spi_sclk <: 0xAA;
   sync(spi_sclk);
   spi_miso :> void;
}
Thanks!


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

Post by Andy »

Hi allanw,

What version of the SPI library are you using? If you download the latest from Github, it has a function spi_master_out_word() that will output 32 bit data:

http://github.xcore.com/repo_index/sc_spi_readme.html

See some example code of how it's used here:

https://github.com/xcore/sc_spi/blob/ma ... er_demo.xc

If you're not familiar with Git and our build system, there are instructions here:

http://github.xcore.com/repo_index/gith ... _11_2.html
MaxFlashrom
Experienced Member
Posts: 82
Joined: Fri Nov 05, 2010 2:59 pm

Post by MaxFlashrom »

allanw wrote:Hi guys, I'm doing a week-long hackathon type event for my school which is making a propeller clock out of RGB LED's being driven by a 12-bit color resolution shift register. I've been trying to figure out how to modify the SPI library to send out data at 32-bits in SPI mode 0 at around 16MHz, and I've looked at a lot of threads but found no definitive answer. We've been using an ARM Cortex as the MCU but have an XMOS X1-A in case we need more processing horsepower. Anyway, we only have 24 hours until the demo and I'd like to be able to quickly switch over to the XMOS.

Supposedly this is the code for 8-bit SPI. I'm not sure I understand why sclk is being written to twice. I'll modify the ports to be 32-bit buffered and get rid of the bitshift, but how do I change the sclk statements? Should I just make them 0xAAAAAAAA?

Code: Select all

void spi_out_byte(unsigned char data)
{
   // MSb-first bit order - SPI standard
   unsigned x = bitrev(data) << 24;
   spi_mosi <: x;
   spi_sclk <: 0xAA;
   spi_sclk <: 0xAA;
   sync(spi_sclk);
   spi_miso :> void;
}
Thanks!
I'm not sure about that direction of the bit shift for the 8-bit case you show: it looks wrong to me. Here's a snippet from an XMOS library:

Code: Select all

void spi_out_byte(spi_master_interface &i, unsigned char data)
{
	// MSb-first bit order - SPI standard
	unsigned x = bitrev(data) >> 24;
	i.mosi <: x;
	i.sclk <: 0xAA;
	i.sclk <: 0xAA;
	sync(i.sclk);
	i.miso :> void;
}
The ports shift out LSB first. The bitrev is to reverse this so that the MSB is shifted out first as per the SPI protocol. Anyway we can ignore the shift for the 32-bit case.

Try

Code: Select all

void spi_out_byte(spi_master_interface &i, unsigned int data)
{
	// MSb-first bit order - SPI standard
	unsigned x = bitrev(data);
	i.mosi <: x;
	i.sclk <: 0xAAAAAAAA; // send 16 clocks. Each 0xA is 0b1010 i.e. 2 clocks
	i.sclk <: 0xAAAAAAAA; // send 16 clocks
	sync(i.sclk);
	i.miso :> void;
}
This example used a struct to encapsulate the ports. Make ports 32-bit buffered.
As per my comments above, the clock is written twice as you need 32 rising clock edges.
You will need to configure the ports to be clocked off a different clock block if you want it to run slower than the default 50MHz that this will run the clocks at (100MHz ref clock clocking out 0xAAAAAAAA) when running from the default system reference clock of 100MHz.

Try this first. For completeness, I include some code cut from the xcore github spi project.

See https://github.com/xcore/sc_spi
Unfortunately this example uses some inline embedded assembler to perform some trickery on shifting the 1st bit when using modes 0 or 2 for outputting bytes, which is difficult to understand for your average user! The reason for this is not clear to me yet.

Code: Select all

static inline void spi_master_out_byte_internal(spi_master_interface &spi_if, unsigned char data)
{
    // MSb-first bit order - SPI standard
    unsigned x = bitrev(data) >> 24;
    
#if (SPI_MASTER_MODE == 0 || SPI_MASTER_MODE == 2) // modes where CPHA == 0
    // handle first bit
    asm("setc res[%0], 8" :: "r"(spi_if.mosi)); // reset port
    spi_if.mosi <: x; // output first bit
    asm("setc res[%0], 8" :: "r"(spi_if.mosi)); // reset port
    asm("setc res[%0], 0x200f" :: "r"(spi_if.mosi)); // set to buffering
    asm("settw res[%0], %1" :: "r"(spi_if.mosi), "r"(32)); // set transfer width to 32
    stop_clock(spi_if.blk2);
    configure_clock_src(spi_if.blk2, spi_if.sclk);
    configure_out_port(spi_if.mosi, spi_if.blk2, x);
    start_clock(spi_if.blk2);
    
    // output remaining data
    spi_if.mosi <: (x >> 1);
#else
    spi_if.mosi <: x;
#endif
    spi_if.sclk <: sclk_val;
    spi_if.sclk <: sclk_val;
    sync(spi_if.sclk);
    spi_if.miso :> void;
}
Hope this helps
Regards,
Max.
allanw
New User
Posts: 2
Joined: Thu Jan 19, 2012 8:58 pm

Post by allanw »

Andy wrote:Hi allanw,

What version of the SPI library are you using? If you download the latest from Github, it has a function spi_master_out_word() that will output 32 bit data:

http://github.xcore.com/repo_index/sc_spi_readme.html

See some example code of how it's used here:

https://github.com/xcore/sc_spi/blob/ma ... er_demo.xc

If you're not familiar with Git and our build system, there are instructions here:

http://github.xcore.com/repo_index/gith ... _11_2.html
Hi Andy,

I'm using the latest sc_spi version. I did see that there is a 32-bit write function, but it simply calls the 8-bit write function four times. While this is work, I'd like to squeeze more performance out by writing the 32-bits directly. It seems like this would work since the buffered ports can be sized to 32 bits. I tried to work off that code but like Max said, I couldn't understand the ASM

Max, I'll try that code.

Here's some pretty pictures! Hopefully we'll be able to switch over to the XMOS pretty soon.