Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
20 years ago

SPI Example?

Hello Everyone,

I'm working on a project that utilizes the SPI interface of the SOPC builder. I'm having some trouble getting it to work though, mostly because I'm not sure if I'm writing the command correctly. Does anyone have some sample code they can share on how to use the SPI command to send and receive data?

Thanks,

Dan

8 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Hello,

    some sample code without comments,

    it talkes to a dsp via spi interface, NIOS is MASTER and DSP is

    slave

    perhaps it helps

    ...# include"global.h"# include"system.h"# include"hw_base.h"

    # include <unistd.h>

    # include"dspctrl_spi.h"

    # define INTWORD_DELAY 10

    /*

    void dsp_write16(WORD *data,WORD len) {

    IOWR_ALTERA_AVALON_SPI_SLAVE_SEL(SPI_0_BASE,BIT0);

    IOWR_ALTERA_AVALON_SPI_CONTROL(SPI_0_BASE, ALTERA_AVALON_SPI_CONTROL_SSO_MSK);

    // spi_write_16(SPI_0_BASE,data,len);

    IOWR_ALTERA_AVALON_SPI_SLAVE_SEL(SPI_0_BASE,BIT0);

    IOWR_ALTERA_AVALON_SPI_CONTROL(SPI_0_BASE,0);

    }

    */

    # define SLAVE0 0# define HREGSIZE 32

    //############################################################################

    void dsp_write_reg(BYTE reg,WORD data) {

    WORD tempdata[2];

    tempdata[0]=CMD_FIRSTBYTE | (reg&(HREGSIZE-1));

    tempdata[1]=data&~CMD_FIRSTBYTE;

    // spi_write_16(base,tempdata[0]);

    // spi_write_16(base,tempdata[1]);

    spi_write_block(SPI_0_BASE,SLAVE0,tempdata,2);

    spi_wait_TRDY(SPI_0_BASE);

    }

    //############################################################################

    WORD dsp_read_reg(BYTE reg) {

    WORD tempdata[2];

    // dsp checks first byte and knows then that he has to put some data on the bus

    tempdata[0]= CMD_FIRSTBYTE | CMD_READ | (reg&(HREGSIZE-1));

    spi_write_block(SPI_0_BASE,SLAVE0,tempdata,1);

    // spi_write_16(base,tempdata[0]);

    spi_read_block(SPI_0_BASE,SLAVE0,tempdata,1);

    return tempdata[0];

    }

    //############################################################################

    void spi_write_block(DWORD base,BYTE slave,WORD *data,DWORD len) {

    DWORD i;

    for(i=0;i<len;i++) {

    spi_select_slave(base,slave);

    spi_write_16(base,(*data++));

    spi_deselect_slave(base,slave);

    usleep(INTWORD_DELAY);

    }

    }

    //############################################################################

    void spi_read_block(DWORD base,BYTE slave,WORD *data,WORD len) {

    WORD i;

    for(i=0;i<len;i++) {

    spi_select_slave(base,slave);

    *data++=spi_read_16(base);

    spi_deselect_slave(base,slave);

    usleep(INTWORD_DELAY);

    }

    }

    //############################################################################

    void spi_select_slave(DWORD base,DWORD slave) {

    IOWR_ALTERA_AVALON_SPI_SLAVE_SEL(base, 1 << slave);

    // Set the SSO bit (force chipselect)

    IOWR_ALTERA_AVALON_SPI_CONTROL(base, ALTERA_AVALON_SPI_CONTROL_SSO_MSK);

    }

    //############################################################################

    void spi_deselect_slave(DWORD base,DWORD slave) {

    IOWR_ALTERA_AVALON_SPI_SLAVE_SEL(base, 1 << slave);

    // reset the SSO bit (force chipselect)

    IOWR_ALTERA_AVALON_SPI_CONTROL(base,0);

    }

    //############################################################################

    void spi_write_16(DWORD base,WORD data) {

    DWORD status;

    do {

    status = IORD_ALTERA_AVALON_SPI_STATUS(base);

    } while ((status & ALTERA_AVALON_SPI_STATUS_TRDY_MSK) == 0);

    IOWR_ALTERA_AVALON_SPI_TXDATA(base,data);

    }

    //############################################################################

    WORD spi_read_16(DWORD base) {

    DWORD status;

    WORD data;

    IORD_ALTERA_AVALON_SPI_RXDATA(base);

    IOWR_ALTERA_AVALON_SPI_TXDATA(base,0x00);

    do {

    status = IORD_ALTERA_AVALON_SPI_STATUS(base);

    } while ((status & ALTERA_AVALON_SPI_STATUS_RRDY_MSK) == 0);

    data=IORD_ALTERA_AVALON_SPI_RXDATA(base);

    return data;

    }

    /*

    void spi_write_16(DWORD base,BYTE slave,WORD *data,DWORD len) {

    DWORD i;

    DWORD status;

    IOWR_ALTERA_AVALON_SPI_SLAVE_SEL(base, 1 << slave);

    for(i=0;i<len;i++) {

    // select slave

    IOWR_ALTERA_AVALON_SPI_CONTROL(base, ALTERA_AVALON_SPI_CONTROL_SSO_MSK);

    do {

    status = IORD_ALTERA_AVALON_SPI_STATUS(base);

    } while ((status & ALTERA_AVALON_SPI_STATUS_TRDY_MSK) == 0);

    // deselect slave

    IOWR_ALTERA_AVALON_SPI_CONTROL(base, 0);

    IOWR_ALTERA_AVALON_SPI_TXDATA(base,*data++);

    }

    while ((status & ALTERA_AVALON_SPI_STATUS_TRDY_MSK) == 0);

    }

    */

    void spi_wait_TRDY(DWORD base) {

    DWORD status;

    do {

    status = IORD_ALTERA_AVALON_SPI_STATUS(base);

    } while ((status & ALTERA_AVALON_SPI_STATUS_TRDY_MSK) == 0);

    }
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Hello dpiessens.

    First I&#39;ll explain the SPI interface so that there is no misunderstanding about how it works (since it happens a lot).

    SPI is fully duplexed so when you need to write data it reads back data at the same time. When you read data it has to write data at the same time. A SPI master is capable of accessing up to 16 SPI slaves. A SPI master is capable of starting a transfer whereas the slave cannot (slave just reacts to the master). If you have multiple slave devices in your system that will be read by the slave master you must buffer their MISO (master in slave out) signals/pins using the slave select signals and tristate buffers.

    Now before I go further I need to ask the million dollar question. Are you using a SPI configured as a master device or as a slave device? The hardware is different and the HAL code only works for SPI masters.

    I also recommend giving this a read: http://www.altera.com/literature/hb/nios2/...pu_nii51011.pdf (http://www.altera.com/literature/hb/nios2/n2cpu_nii51011.pdf)

    I&#39;m pretty busy now so I&#39;m not checking the forum very often so if you need more help contact me by email.

    Good-luck
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    originally posted by dpiessens@Apr 29 2005, 04:50 PM

    hello everyone,

    i&#39;m working on a project that utilizes the spi interface of the sopc builder. i&#39;m having some trouble getting it to work though, mostly because i&#39;m not sure if i&#39;m writing the command correctly. does anyone have some sample code they can share on how to use the spi command to send and receive data?

    thanks,

    dan

    --- Quote End ---

    This is my best guess...

    This routine is based on the legacy SPI routine and does a single-character write to a 16-bit spi DAC. Or will when I get back from vacation.

    The benefit of this routine over HAL&#39;s "alt_avalon_spi_command" is that it supports a 16-bit data word.

    The downside is that it is too simple. Try not to break it. http://forum.niosforum.com/work2/style_emoticons/<#EMO_DIR#>/rolleyes.gif

    #include <stdio.h># include <alt_types.h># include <io.h># include <string.h>
    // Project-specific headers# include "system.h"
    /* SPI status and control bits */# define STAT_TMT_MSK   (0x20)# define STAT_TRDY_MSK  (0x40)# define STAT_RRDY_MSK  (0x80)# define CTRL_SSO_MSK   (0x400)
    /* From system.h - base address of DAC at U6.
     * # define SPI_DAC_U6_BASE 0x00000820
     */
    .
    .
    .
    void spi_tx_char(int tx_data, long spi_DAC_addr)
    {
    /* Barebones SPI tx routine.
     *
     * Strategy:
     * Write the slave select bit to pick an SS_n.
     *        (Writing all 3 as a unit, will change later.)
     * Force SS_n
     * Wait until ready then tx
     * Wait until ready then rx and ignore data
     * Wait until last bit is transferred
     * Deassert SS_n
     * Deselect slave
     *
     * Set your spi device for uC mode, not DSP since SSn drops before SCLK starts.
     * 
     */
     
      int ctrlbyte;
    /* select all 3 DACs */
      IOWR(spi_DAC_addr, 5, 0x7); 
    /* Assert SS_n */
      ctrlbyte = IORD(spi_DAC_addr, 3);
      IOWR(spi_DAC_addr, 3, (ctrlbyte | CTRL_SSO_MSK));
    /* Transmit a byte: */
      while (!(IORD(spi_DAC_addr, 2) & STAT_TRDY_MSK));
      IOWR(spi_DAC_addr, 1, tx_data);
    /* Read and ignore the received data: */
      while (!(IORD(spi_DAC_addr, 2) & STAT_RRDY_MSK));
      IORD(spi_DAC_addr, 0);
    /* Wait until the last byte is transmitted: */
      while (!(IORD(spi_DAC_addr, 2) & STAT_TMT_MSK));
    /* Release SS_n: */
      IOWR(spi_DAC_addr, 3, IORD(spi_DAC_addr, 3) & ~CTRL_SSO_MSK );
    /* Deselect all DACs: */
      IOWR(spi_DAC_addr, 5, 0x0);
    }
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    leslie

    I found that the function above has a problem,

    void spi_tx_char(int tx_data, long spi_DAC_addr)

    for the parameter of " long spi_dac_addr" if I use it such as 0x008200,the programe can run ,but if I use it such as SPI_0_BASE,The programe cann&#39;t run,why?
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    originally posted by kedimike@Jan 25 2006, 08:23 AM

    leslie

    i found that the function above has a problem,

    void spi_tx_char(int tx_data, long spi_dac_addr)

    for the parameter of " long spi_dac_addr" if i use it such as 0x008200,the programe can run ,but if i use it such as spi_0_base,the programe cann&#39;t run,why?

    <div align='right'><{post_snapback}> (index.php?act=findpost&pid=12383)

    --- quote end ---

    --- Quote End ---

    Probably because I seem to have pasted the wrong file. I will double-check on Monday to be sure that I pasted one where the subroutine is correct.

    SPI_0_BASE is the base address of an spi core named spi_0. Find out what you called yours in SOPC builder or look for the name of it in system.h.

    To transmit data of 0xaaaa out through spi_0:

    mydata = 0xaaaa;

    spi_tx_char(mydata, SPI_0_base);

    This is simplistic. It doesn&#39;t check for errors.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    <div class='quotetop'>QUOTE </div>

    --- Quote Start ---

    The benefit of this routine over HAL&#39;s "alt_avalon_spi_command" is that it supports a 16-bit data word.[/b]

    --- Quote End ---

    alt_avalon_spi_command support only 8 bit data.

    but a simple change will make it work for 16 bit data

    just change the alt_u8 to alt_u16 every where in the code and you have

    a method that read and write 16 bit
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    thanks

    I have resolve the problem, the problem above is produced by myself