Forum Discussion

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

SPI Slave bug?

Has anybody used the SPI core as a slave device in a NIOS II implementation? If so, have you had relatively frequent data errors?

There is no HAL for the SPI as slave, so I'm just using the IORD... and IOWR... macros defined in altera_avalon_spi_regs.h. I've tried both polling and ISR implementations, yet I keep getting data errors. I originally suspected noise on the SCLK or MOSI lines, but they look golden -- no glitches.

Example: the SPI master sends 3 bytes -- 0xF1, 0x41, 0xF6. Most times, that's what I get, but over 10% of the time (!) I see examples such as: 0xF1 0x20 0xF6, or 0xF1 0xA8 0x81 0xF6 (and there are only 3 bytes sent, looking at the SCLK and MOSI lines), or 0xF1 0x41 0xBD.

Here's my interrupt handler (the protocol stuff isn't relevant):

void SpiSlave::InterruptHandler(void)

{

U_INT32 irq_flag_reg;

U_INT32 irq_mask_reg;

U_BYTE RxChar;

static U_BYTE GotHeader = FALSE;

IsrCount++;

// read register to determine which flags are set

irq_flag_reg = IORD_ALTERA_AVALON_SPI_STATUS(BaseAddress);

// read the interrupt mask register

irq_mask_reg = IORD_ALTERA_AVALON_SPI_CONTROL(BaseAddress);

while (irq_flag_reg &= irq_mask_reg) {

// Check for Rxed character

if (irq_flag_reg & ALTERA_AVALON_SPI_STATUS_RRDY_MSK) {

RxIsrCount++;

if (RxMsgSize >= SPI_SLAVE_RX_BUFFER_SIZE) { // buffer overflow

// queue an event

RxMsgSize = 0;

GotHeader = FALSE;

}

RxChar = IORD_ALTERA_AVALON_SPI_RXDATA(BaseAddress);

if (GotHeader) {

RxDataBuffer[RxMsgSize++] = RxChar; // store char in temp buffer

if (RxChar == (U_BYTE)0xF6) { // ETX char received

GotHeader = 0;

DisableInterrupt(ALTERA_AVALON_SPI_CONTROL_ITRDY_MSK); // no more TRDY

if (NewMsgRxed) { // app hasn't processed the last msg yet!

// queue event

}

else { // ready to give msg to application

// copy data to app buffer

while (RxMsgSize--) {

AppRxBuffer[RxMsgSize] = RxDataBuffer[RxMsgSize];

}

NewMsgRxed = TRUE;

RxMsgSize = 0;

}

} // end if ETX

else { // not ETX

if (RxChar > (U_BYTE)0xF0) { // unexpected header

// start msg all over, beginning with the new header

// note that GotHeader is already TRUE

RxMsgSize = 0;

RxDataBuffer[RxMsgSize++] = RxChar;

} // end if unexpected header

} // end if not ETX

} // end if GotHeader

else if ((RxChar > (U_BYTE)0xF0) && (RxChar != (U_BYTE)0xF6)) { // Header rxed

GotHeader = TRUE;

RxMsgSize = 0;

RxDataBuffer[RxMsgSize++] = RxChar;

}

} // end if Rx Rdy interrupt

if (irq_flag_reg & ALTERA_AVALON_SPI_STATUS_TRDY_MSK) {

TxIsrCount++;

if ((BytesToSend) && (TxData)) { // data to tx

IOWR_ALTERA_AVALON_SPI_TXDATA(BaseAddress, *TxData++);

BytesToSend--;

}

else {

// nothing more to send, so disable ints to avoid infinite ints

DisableInterrupt(ALTERA_AVALON_SPI_CONTROL_ITRDY_MSK);

}

}

if (irq_flag_reg & ALTERA_AVALON_SPI_STATUS_ROE_MSK) {

// Rx overrun error -- queue event?

}

if (irq_flag_reg & ALTERA_AVALON_SPI_STATUS_TOE_MSK) {

// Tx overrun error -- queue event?

}

// re-read register to determine which flags are set

irq_flag_reg = IORD_ALTERA_AVALON_SPI_STATUS(BaseAddress);

// Clear status bits by writing anything to the status register

//IOWR_ALTERA_AVALON_SPI_STATUS(BaseAddress, 0);

// read the interrupt mask register

irq_mask_reg = IORD_ALTERA_AVALON_SPI_CONTROL(BaseAddress);

} // end while

} // end SpiSlave::InterruptHandler()

17 Replies

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

    I use the SOPC-Builder to build my project. You can find that module in the SOPC-Builder Library under "Interface Protocols" -> "Serial" -> "SPI (3 Wire Serial)".

    Or, you may find it in your install directory:

    <root>/altera/<version>/ip/altera/sopc_builder_ip/altera_avalon_spi/
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Not the SPI (as in Serial Periperal Interface), I wrote SP1 (as in QII 9.1 Service Pack1). Where did you get it from ?

    Update: Nevermind, I found it now. It was not announced in the front page as I expected it to be.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Ah, I missunderstood this.

    Go to altera.com --> "Products" --> "Design Software" --> on the right side "Download Software"

    There you can choose to download the latest Version of QuartusII. It includes this SP1. I think there is no small SP1 installer, you need to install the whole QuartusII.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    SOPC bilder generates, as seems, wrong verilog code for SPI slave, at SS_n rise edge rx register shifted one more time, and ROE bit is set to 1. To avoid this, you should read RX register before SS_n rise edge or delay SS_n edge, if it possible.

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

    --- Quote Start ---

    SOPC bilder generates, as seems, wrong verilog code for SPI slave, at SS_n rise edge rx register shifted one more time, and ROE bit is set to 1. To avoid this, you should read RX register before SS_n rise edge or delay SS_n edge, if it possible.

    --- Quote End ---

    Could you elaborate on this?

    Also, is Altera going to fix this bug?
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    I believe I found the solution to this problem. I had my SPI slave running from a 40MHz source. The data rate I was using was <1MHz. I found that the lower data rate I would run my master at, the worse these errors became. I changed my SPI slave to run at a 1MHz rate. The errors went away. So it seems that your SPI slave clock should be close to the data rate you intend to run at. I'm not sure how close it has to be or what the upper limit on the SPI slaves data rate is.

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

    Hi, you said if the clock rate over 1MHz the transmission error went away. I tried it, and it had a little effect, the errors reduced ,but sometimes it still came. Would you please provide some code for the slave and master program ?I just want to implement transmitting 32bit data from master side to slave one and then read back. I have paste some of my code and post it, the link is alteraforum.com/forum/showthread.php?t=36274

    Thanks a lot!:)