Nios® V/II Embedded Design Suite (EDS)
Support for Embedded Development Tools, Processors (SoCs and Nios® V/II processor), Embedded Development Suites (EDSs), Boot and Configuration, Operating Systems, C and C++

SPI Slave bug?

Altera_Forum
Honored Contributor II
2,258 Views

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()
0 Kudos
17 Replies
Altera_Forum
Honored Contributor II
1,034 Views

What version of the tools and speeds (Avalon clock and sclk) are you using? 

 

Enhancements to the SPI component have reduced the maximum speed of the SPI slave device (so don't run it at speeds up to half the Avalon clock rate anymore). I do not recommend exceeding 1/10th the Avalon speed. 

 

Also I didn't look at the code but in case you were not aware, this is important: If the SPI slave is selected and it has not readied it's TX register, when data is recieved (via RX) it will be looped around and sent back through the TX signal (SPI is fully duplex so it has to send something back).
0 Kudos
Altera_Forum
Honored Contributor II
1,034 Views

I'm using Quartus II v5.0 Build 168, NIOS II v5.0 Build 73c. The clock speed is 65 MHz, and the SCLK is currently about 1MHz, though we've tried a range from about 44 KHz to about 2 MHz, with no difference in results. 

 

I've found that if I have never loaded the TX register, the master reads back 0xFF, and that if I have loaded it with some byte, that same byte will be read out until I re-load the TX register. 

 

Thanks for the interest. You've gotten the SPI slave to work reliably? I haven't seen anything on this or the Altera forums about anybody using the SPI core as a slave. Everybody's always talking about it as a master. I have no problems at all with my SPI master, which makes this seem kinda weird.
0 Kudos
Altera_Forum
Honored Contributor II
1,034 Views

Doug, 

I have the same issues submitted to Altera's "MySupport". In addition to what Doug has stated, the Status register error bits also do not clear after a write operation, like they are supposed to. Does anyone know why Altera provides a Master SPI driver but not a slave one? Granted, it's not that hard to implement, but nonetheless it would seem that if they had actually written a driver, these things would have fallen out during test and verification...??? 

 

John
0 Kudos
Altera_Forum
Honored Contributor II
1,034 Views

Email me if you are not up and running and I can give you some code I made for a slave device (it's not interupt based but it may point out what's failing in your design).

0 Kudos
Altera_Forum
Honored Contributor II
1,034 Views

Any news here? 

 

I'm experiencing similar problems. My Cyclone III is configured as Slave another controller as Master. 

 

For testing I set up the master to send 0x5555 and the slave to send 0xffff all the time. As I did not receive the right values in both direction I took a look at the bus. You may want to have a look at the screenshots: 

yellow - clock 

green - slave select 

blue - MOSI 

red - MISO 

 

The data the code of the master shows are exactly the same I can see on an oscilloscope. So there cant be a problem on masters side. 

 

The data I want to send from slave's side varies on the bus (as shown on the screenshots). And the data I receive on slave's side seems to be totally random. I've never received valid data in slave. 

 

I've not tried yet to interchange master-slave to see if this is caused by a faulty slave driver. I anyway prefer it to have it the way it is and to solve the problems. 

 

Any hints are appreciated. 

 

Kind Regards.
0 Kudos
Altera_Forum
Honored Contributor II
1,034 Views

Just testet to switch master and slave. 

 

The FPGA is working flawless as master. I only have problems if I use it as slave. 

 

Any idea how to solve the slave bug?
0 Kudos
Altera_Forum
Honored Contributor II
1,034 Views

Are you using a recent (V9.0 or V9.1) sopc IP? There have been changes to the SPI slave code.

0 Kudos
Altera_Forum
Honored Contributor II
1,034 Views

I'm using Quartus II V9.1. 

 

IP-Details: 

SPI (3 Wire Serial) 

Class: altera_avalon_spi 

Version: 9.1
0 Kudos
Altera_Forum
Honored Contributor II
1,034 Views

Recently upgraded to 91sp1 but still the same. As master everthing is flawless as slave everthing seems to be random. 

 

I just noticed that the signal from slave also toggles sometimes at the wrong clock edges. 

On the screenshot: 

yellow:clock 

blue: slave select 

green: MISO (here is the problem) 

red: MOSI 

 

The settings ( Clock Polarity and Clock Phase ) in SOPC-Builder are both set to 1. So the data should only toggle on negative clock edges. 

 

Does anyone of you got the SPI Slave running without errors? Perhaps someone can send me his code?! 

 

Thanks.
0 Kudos
Altera_Forum
Honored Contributor II
1,034 Views

Freezy, 

 

Where did you get SP1? I can not find it yet in www.altera.com.
0 Kudos
Altera_Forum
Honored Contributor II
1,034 Views

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/
0 Kudos
Altera_Forum
Honored Contributor II
1,034 Views

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.
0 Kudos
Altera_Forum
Honored Contributor II
1,034 Views

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.
0 Kudos
Altera_Forum
Honored Contributor II
1,034 Views

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.

0 Kudos
Altera_Forum
Honored Contributor II
1,034 Views

 

--- 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?
0 Kudos
Altera_Forum
Honored Contributor II
1,034 Views

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.

0 Kudos
Altera_Forum
Honored Contributor II
1,034 Views

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!:)
0 Kudos
Reply