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 Problems

Altera_Forum
Honored Contributor II
3,796 Views

Hi, 

 

I'm trying to get handle with the SPI on a Nios II Core but I don't get it. I have a SPI master and a SPI Slave that I can try to transmit some data from the master to the slave. I connected them with the "loopback board". 

My Code is: 

 

//Write some data to the Slave IOWR_ALTERA_AVALON_SPI_SLAVE_SEL(SPI_SLAVE_BASE,0x04); //Check the TRDY bit if data is written(TRDY=0 means it is writing and //TRDY=1 again means the data was written) trdyNumber=(IORD_ALTERA_AVALON_SPI_STATUS(SPI_SLAVE_BASE)& ALTERA_AVALON_SPI_STATUS_TRDY_MSK)>>6; //Read from the register int data=(IORD_ALTERA_AVALON_SPI_RXDATA(SPI_SLAVE_BASE)&0xFF); printf("%d",data); 

 

I also read the manuel for the SPI Core but it doesn't work. Can somebody help my with an exsample or give me an advice? 

 

Regards
0 Kudos
22 Replies
Altera_Forum
Honored Contributor II
1,528 Views

Your code contains several mistakes: 

 

IOWR_ALTERA_AVALON_SPI_SLAVE_SEL(SPI_SLAVE_BASE,0x04) 

This doesn't write data to the slave, but it selects (enables) slave whose address is 4 for receiving data 

 

SPI slave is not supposed to transmit data autonomously. It sends data upon  

reception of a master request. 

 

You both send and receive data on slave. 

I think you meant send with master and receive with slave.
0 Kudos
Altera_Forum
Honored Contributor II
1,528 Views

First thanks! 

And yes I want to send some data from Master to Slave but how? Thats what I don't understand precicely. May you can bring light in the dark.
0 Kudos
Altera_Forum
Honored Contributor II
1,528 Views

The correct procedure is something like this: 

 

// select slave (not required in single slave system) 

IOWR_ALTERA_AVALON_SPI_SLAVE_SEL(master_base, n_slave); 

 

// assert CS  

IOWR_ALTERA_AVALON_SPI_CONTROL(master_base, ALTERA_AVALON_SPI_CONTROL_SSO_MSK); 

 

// wait tx channel ready 

do 

status = IORD_ALTERA_AVALON_SPI_STATUS(master_base); 

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

(status & ALTERA_AVALON_SPI_STATUS_RRDY_MSK) == 0); 

 

// (optional) data possibly to be transmitted back from slave to master upon request 

IOWR_ALTERA_AVALON_SPI_TXDATA(slave_base, data_answer); 

 

// tx data 

IOWR_ALTERA_AVALON_SPI_TXDATA(master_base, data_tx); 

// this will initiate the transfer; in the same time the slave sends out on miso pin 

// the data ready in its tx register 

 

 

// Wait until the interface has finished transmitting 

do 

status = IORD_ALTERA_AVALON_SPI_STATUS(master_base); 

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

 

// release CS 

IOWR_ALTERA_AVALON_SPI_CONTROL(master_base, 0); 

 

// read received data from slave 

data_rx = IORD_ALTERA_AVALON_SPI_RXDATA(slave_base); 

// data_rx must match data_tx 

 

// (optional) read answer from master 

recvd_answer = IORD_ALTERA_AVALON_SPI_RXDATA(master_base); 

// recvd_answer must match data_answer 

 

 

Please note that I wrote this code by heart. I'm not sure this it will compile without errors.
0 Kudos
Altera_Forum
Honored Contributor II
1,528 Views

Thanks again! 

I just tried your code and it is compileable but it doesen't work complitly correct. The Code looks like: 

 

--- Quote Start ---  

int status=0; 

int countTMT; 

 

// select slave (not required in single slave system) 

IOWR_ALTERA_AVALON_SPI_SLAVE_SEL(SPI_MASTER_BASE, SPI_SLAVE_BASE); 

 

// assert CS 

IOWR_ALTERA_AVALON_SPI_CONTROL(SPI_MASTER_BASE, ALTERA_AVALON_SPI_CONTROL_SSO_MSK); 

 

// wait tx channel ready 

do 

status = IORD_ALTERA_AVALON_SPI_STATUS(SPI_MASTER_BASE); 

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

 

// (optional) data possibly to be transmitted back from slave to master upon request 

IOWR_ALTERA_AVALON_SPI_TXDATA(SPI_SLAVE_BASE, 0x01); 

 

// tx data 

IOWR_ALTERA_AVALON_SPI_TXDATA(SPI_MASTER_BASE, 0x10); 

// this will initiate the transfer; in the same time the slave sends out on miso pin 

// the data ready in its tx register 

 

 

// Wait until the interface has finished transmitting 

do{ 

status = IORD_ALTERA_AVALON_SPI_STATUS(SPI_MASTER_BASE); 

IOWR_ALTERA_AVALON_PIO_DATA(LED_PIO_BASE,countTMT & 0x01); 

usleep(50000); 

countTMT++; 

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

 

// release CS 

IOWR_ALTERA_AVALON_SPI_CONTROL(SPI_MASTER_BASE, 0); 

 

// read received data from slave 

int data_rx = IORD_ALTERA_AVALON_SPI_RXDATA(SPI_SLAVE_BASE); 

// data_rx must match data_tx 

printf("Daten aus dem Slave:%d\n",data_rx); 

 

// (optional) read answer from master 

int recvd_answer = IORD_ALTERA_AVALON_SPI_RXDATA(SPI_MASTER_BASE); 

// recvd_answer must match data_answer 

printf("Daten aus dem Master:%d\n",recvd_answer); 

--- Quote End ---  

 

 

The result is: 

 

 

--- Quote Start ---  

Daten aus dem Slave:0 

Daten aus dem Master:0 

--- Quote End ---  

 

 

I don't understand why it doesn't work because it should. 

Maybe you can help me one more time. Thanks for your helt! 

 

Regards
0 Kudos
Altera_Forum
Honored Contributor II
1,528 Views

I presume you already checked the loopback connections: 

- mosi output from master connected to mosi input pin to slave 

- miso output from slave connected to miso input to master 

- sclk from master feeds sclk slave input 

- slave select output from master drives ss input pin on slave 

 

What's your master sclk frequency? Can you test the mosi signal? 

 

Also check the status and control register on both master and slave, both before and after the execution of the above code. If you don't find anything wrong, post their values and I'll take a look. 

For similar spi example, you can also refer to the alt_avalon_spi_command() function in HAL driver library.
0 Kudos
Altera_Forum
Honored Contributor II
1,528 Views

Hi chris 72, 

 

thanks for your support! 

I tried what you`ve told me and also control the pin assignment for the loopback board. For this I used the loopback_test_lowcost.pdf from Altera. 

My assignment looks like it is benife: 

 

spi_master_MISO,Input,PIN_Y4 spi_master_MOSI,Output,PIN_R6 spi_master_SCLK,Output,PIN_R7 spi_master_SS_n,Output,PIN_V3 spi_slave_MISO,Output,PIN_V4 spi_slave_MOSI,Input,PIN_AB1 spi_slave_SCLK,Input,PIN_AB2 spi_slave_SS_n,Input,PIN_Y3  

I also tested to connect the MOSI of the Master to a LED on the board but I can't see anything. Maybe it is because of the frequency:). The frequency of my system is 50MHZ and the frequency for the SPI is 128kHZ. could this be a problem? 

 

I also looked through the Controlregs and the Statusregs of the Spi: 

Befor transmitting data: 

Statusregister of the Master: 0x260.(1001100000) 

Controlregister of the Master: 0x400.(10000000000) 

Statusregister of the Slave: 0x310.(1100010000) 

Controlregister of the Slave: 0x0(0) 

 

After transmitting and reading data: 

Statusregister of the Master: 0x260.(1001100000) 

Controlregister of the Master: 0x0.(0) 

Statusregister of the Slave: 0x310.(1100010000) 

Controlregister of the Slave: 0x0.(0) 

 

I thank you in advance for your help!
0 Kudos
Altera_Forum
Honored Contributor II
1,528 Views

I don't know about your board schematics, so I can't check your signal to pin connections. 

Routing mosi signal to a LED is useless: you would never be able to see it (or maybe are you kind of guy sensitive to kryptonite? are you? :D) 

You must use an oscilloscope to test it. If you do, test especially the sclk signal. 

If you can't afford an oscilloscope, you can SignalTap the design. 

Focus on sclk and ss signals, not on mosi. 

SPI registers seems to indicate that the master has correctly transmitted data, but the slave has received nothing. Moreover, slave status shows an overrun error. This is usually due to a missing sclk or unasserted ss on slave side. 

Writing anything to slave status register should clear the overrun error. Clear it and verify if your spi command code set this error again.
0 Kudos
Altera_Forum
Honored Contributor II
1,528 Views

Unfortunately I'm not sensitive to kryptonite;-) 

I tried like you told to use the SignalTap II but it didn't work. The triggering didn't appear. So I tried to read and write the registers by my on. I started my code with writing in the statusreg of the master and the slave and i recognized that I'm not bale to write data in the slave statusreg. Why?  

Maybe you can help my. 

You also said that the overrun error accure because of missing sclk, could this be related with a false pin assignment? Do I need to turn on something on the cyclon III developement board if I useing the HSMCA port?  

 

Thanks in advance!
0 Kudos
Altera_Forum
Honored Contributor II
1,528 Views

Hi, 

 

I tried the SignalTap II again whith some other adjustmens and it worked.  

It is shown in the diagram that the data transmission from the master is ok but how to understand the spi_master_SS_n signal i don't understand exactly. Now my question is how could it be that the data is transmitted correct but can't be read correct? Could it be that it is something wrong with the slave or its pin assignment? 

 

Thanks in advance!
0 Kudos
Altera_Forum
Honored Contributor II
1,528 Views

 

--- Quote Start ---  

Unfortunately I'm not sensitive to kryptonite;-) 

I started my code with writing in the statusreg of the master and the slave and i recognized that I'm not bale to write data in the slave statusreg. Why?  

 

--- Quote End ---  

 

You are not supposed to write to the status reg and read back data. 

The write command is fake and is only used to instruct the spi core to reset the error bits, as stated in the spi datasheet, page 7-11.
0 Kudos
Altera_Forum
Honored Contributor II
1,528 Views

Your ss signal is not asserted. Must be low when master is transmitting. 

I see only now that you code is: 

IOWR_ALTERA_AVALON_SPI_SLAVE_SEL(SPI_MASTER_BASE, SPI_SLAVE_BASE); 

That's wrong. The correct one is: 

IOWR_ALTERA_AVALON_SPI_SLAVE_SEL(SPI_MASTER_BASE, 1);
0 Kudos
Altera_Forum
Honored Contributor II
1,528 Views

I think that it is not necessary to deassert ss signal when there's just one slave. It should be deasserted automatically once the transmission is started.

0 Kudos
Altera_Forum
Honored Contributor II
1,528 Views

HI Cris72, 

 

first of all thanks finally it works!  

But how it is sometimes I want to know more about the SPI. So I want to know why I can't use the dummy which is transmitted from the Slave to the master as a control signal for example that the data was transmitted correct or complitly? I just recognized that the data which was written from the slave to the master as a dummy is just in the rxdata register from the master when I lode my C-Code from the NIOSII IDE the seconde time. If I when reset the system it disappear from the Master and I can just read the data from the slave.  

Where does the data is which is at the second time in the rxdata register from the master at the first time? And why I'm not able to read it at the first time?  

And is it possible to write some data from the slave to the master? Because I want to connect my FPGA with two uC which have to receive data from the FPGA but also have to send data to the FPGA. 

 

I thanks in advance for your help!
0 Kudos
Altera_Forum
Honored Contributor II
1,528 Views

Hi siedler. 

I'm not sure I have understood your questions. 

It seems you want to transmit data from the master to the slave but also from slave to master, and this is feasible. 

But this is possible only upon master request. Namely, when master sends data, the slave transmits back the content of its tx register. The two data transfers (M->S and S->M) take place in the same time, on the same clock pulses, so slave tx register must be preloaded with correct data and ready to answer at the very first sclk pulse. 

The slave, being a slave, can't initiate a transmission itself: it always must respond to a master request.
0 Kudos
Altera_Forum
Honored Contributor II
1,528 Views

Thanks for your answer cris. 

Ok I understand the circumstances. And this means for me that I need a master and a slave to send and receive data at different time.  

But what is about my question, that I can just read the data which was transmitted from the slave to the master at the second time I load my C-Code to the FPGA? And how it is possible to read the dummy at the same time as the data from the slave? 

 

Thanks in advance for you help!
0 Kudos
Altera_Forum
Honored Contributor II
1,528 Views

Try changing the wait completion loop this way: 

 

do{ IOWR_ALTERA_AVALON_PIO_DATA(LED_PIO_BASE,countTMT & 0x01); usleep(50000); countTMT++; status = IORD_ALTERA_AVALON_SPI_STATUS(SPI_MASTER_BASE); } while( ((status & ALTERA_AVALON_SPI_STATUS_TMT_MSK) == 0) || ((status & ALTERA_AVALON_SPI_STATUS_TRDY_MSK) == 0) );  

 

Also check if timing parameters (clock polarity and phase) match master and slave. 

Your problem can be possibly due to the fact that slave is missing a clock pulse, then the rx word would be completed only on the first clock pulse of next tx word, thus leading to shifted results.
0 Kudos
Altera_Forum
Honored Contributor II
1,528 Views

I changed the waiting completion loop like you told me and it doesn't work. I also tried instead to wait on the TRDY-Flag to wait on the RRDY-Flag because how far I understand if the RRDY-Flag is "1" it is possible to read the register. But it also doesn't work.  

I`m also checked the setup in QSYS of the both SPI Cores and till the difference that one is a master and the other one is a slave they have the same setting in relation to the clock polarity and phase. So may I change the setting for the slave or the master? Or what can I do farther? 

 

Thanks in advance for your help!
0 Kudos
Altera_Forum
Honored Contributor II
1,528 Views

Hi cris72, 

me again. I recognized something which is looking quite bewildering for me. If you take a look at the picture in the attachment where you can see that in the SignalTap II the SCLK is just 25kHz and not how I set it up 128kHz. Am I wrong or where is the problem? 

 

Thanks in advance for your help!
0 Kudos
Altera_Forum
Honored Contributor II
1,528 Views

Hi I have the same problem. No matter what clock value I set up, the clock is always 64kHz. The clock polarity setting aren't working as well. I'm using Quartus II 10.1 Build 153 (and Qsys beta 10.1 build 153). Thanks for every hint!

0 Kudos
Altera_Forum
Honored Contributor II
1,421 Views

 

--- Quote Start ---  

Hi I have the same problem. No matter what clock value I set up, the clock is always 64kHz.  

--- Quote End ---  

 

What is the cause of this problem and what is the workaround?
0 Kudos
Reply