Forum Discussion
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
Honored Contributor
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). - Altera_Forum
Honored Contributor
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. - Altera_Forum
Honored Contributor
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 - Altera_Forum
Honored Contributor
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).
- Altera_Forum
Honored Contributor
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. - Altera_Forum
Honored Contributor
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? - Altera_Forum
Honored Contributor
Are you using a recent (V9.0 or V9.1) sopc IP? There have been changes to the SPI slave code.
- Altera_Forum
Honored Contributor
I'm using Quartus II V9.1.
IP-Details: SPI (3 Wire Serial) Class: altera_avalon_spi Version: 9.1 - Altera_Forum
Honored Contributor
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. - Altera_Forum
Honored Contributor
Freezy,
Where did you get SP1? I can not find it yet in www.altera.com.