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++
12618 Discussions

SPI from HPS through FPGA not working

Honored Contributor II



Since 6 month i am working with SOC Cyclone V Evalboard from Altera. 

I use Yocto to build linux and EDS V 14.0 for development. 


For Knowledge and HowTo my first place is Rocketboards, but i also use Searchengines to find answers ;) 


With the Evalboard i use I2C, SPI and GPIOs(all from HPS) as interface to other devices like display, port expander, leds, gpios,... without problems. 


Now i want to route the spi pins from the hps to the fpga. 

  1. 'exported' the pins in qsys. 

  2. routed the exported pins to the leds in quartus 

  3. Create all needed files. preloader, u-boot, dtb 



After this, if i want to send something over the spi, i get a cpu stall and nothing works anymore. Need to reset the board. 


Is it not so simple to route the hps pins to the fpga? with the loanpins i also had no problems. 

I hope anybody can give me a hint. 


Best regards 

0 Kudos
6 Replies
Honored Contributor II

I have the same problem = (SPI can not transfer data (TFE in SR is cleared and no more changes) I think that it is related with clocking, but I doubt, because the controller makes changes in registers, and hence clocked all okay.  

I2С through FPGA working fine.
0 Kudos
Honored Contributor II

All works. 


root@socfpga:~# ./mem 0xfff00008 

data = 0x00000001 

root@socfpga:~# ./mem 0xfff00008 0 ;disable 

root@socfpga:~# ./mem 0xfff00010 1 ;cs 0 

root@socfpga:~# ./mem 0xfff00014 100 ; clock &per_base_clk / 100 

root@socfpga:~# ./mem 0xfff00000 0xcf ; cpol cpha 16-bit 

root@socfpga:~# ./mem 0xfff00008 1 ; enable 

root@socfpga:~# ./mem 0xfff00060 ;read 

data = 0x00000000 

root@socfpga:~# ./mem 0xfff00060 256 ;write 

root@socfpga:~# ./mem 0xfff00028 ;status 

data = 0x0000000e ; RX not empty... 

root@socfpga:~# ./mem 0xfff00024 ;rx data count 

data = 0x00000001 

root@socfpga:~# ./mem 0xfff00060 ;read 

data = 0x0000040a 


In QSYS SPI clock 100MHz 



.hps_0_spim0_txd (temp_mosi), //mosi hps_0_spim0.txd 

.hps_0_spim0_rxd (temp_miso), //miso .rxd 

.hps_0_spim0_ss_in_n (), // .ss_in_n 

.hps_0_spim0_ssi_oe_n (), // .ssi_oe_n 

.hps_0_spim0_ss_0_n (temp_cs_n), // .ss_0_n 

.hps_0_spim0_ss_1_n (), // .ss_1_n 

.hps_0_spim0_ss_2_n (), // .ss_2_n 

.hps_0_spim0_ss_3_n (), //sck .ss_3_n 

.hps_0_spim0_sclk_out_clk (spi_sck) /**/ 



wire spi_sck; 

assign temp_sclk=spi_sck & hps_fpga_reset_n;  



hps_0_spim0: spi@0xfff00000 { 

compatible = "snps,dw-spi-mmio-14.1", "snps,dw-spi-mmio"; 

reg = < 0xFFF00000 0x00000100 >; 

interrupt-parent = < &hps_0_arm_gic_0 >; 

interrupts = < 0 154 4 >; 

# address-cells = < 1 >; /* embeddedsw.dts.params.#address-cells type NUMBER */ 

# size-cells = < 0 >; /* embeddedsw.dts.params.#size-cells type NUMBER */ 

bus-num = < 0 >; /* embeddedsw.dts.params.bus-num type NUMBER */ 

num-chipselect = < 1 >; /* embeddedsw.dts.params.num-chipselect type NUMBER */ 

status = "okay"; /* embeddedsw.dts.params.status type STRING */ 

clocks = < &per_base_clk >; /* appended from boardinfo */ 


spidev0: spidev@0 { 

compatible = "spidev"; /* appended from boardinfo */ 

reg = < 4293918720 >; /* appended from boardinfo */ 

spi-max-frequency = < 100000000 >; /* appended from boardinfo */ 

enable-dma = < 1 >; /* appended from boardinfo */ 

}; //end spidev@0 (spidev0) 

}; //end spi@0xfff00000 (hps_0_spim0)
0 Kudos
Honored Contributor II

akaspar, how you send data to spi?

0 Kudos
Honored Contributor II

Hi ask 


I have the same issue as you described in this thread. How did you manage to get it to work? 


I'm not using Linux but uCos, but I still can't make the SPI controller start transmitting data. It just puts the data into the FIFO buffer. 


I have verified that my pin mapping is correct: 

- CS pin can be toggled (Can be set low by SPI controller or by PIO CS pin, both works) 

- SS pin can be toggled (selecting SPI mode 0 or 3). 


I can break in my code and using the debugger I can select another SPI frameformat (TI instead of Motorola). 

After this "trick" I can write data into the DR register and data gets transmitted (until SPI driver is disabled/enabled again). 


Here is my init function: 


ALT_STATUS_CODE FramDriver_Init(ALT_SPI_CTLR_t eAltSPIModNum){ static uint8_t u8RunOnce = 1; ALT_STATUS_CODE eAltStatusCode = ALT_E_SUCCESS; ALT_SPI_CONFIG_t cfg = { .frame_size = ALT_SPI_DFS_8BIT, .frame_format = ALT_SPI_FRF_SPI, .clk_phase = ALT_SPI_SCPH_TOGGLE_START, .clk_polarity = ALT_SPI_SCPOL_INACTIVE_HIGH, .transfer_mode = ALT_SPI_TMOD_TXRX, .loopback_mode = false, .slave_output_enable = true }; // Make sure CS pin is high before initializing SPI peripheral. Is also pulled up externally... SET_CS_PIN_HIGH; if (1 == u8RunOnce) { u8RunOnce = 0; eAltStatusCode = alt_spi_init(eAltSPIModNum, &stAltSPIdevice); } eAltStatusCode = alt_spi_disable(&stAltSPIdevice); if (eAltStatusCode == ALT_E_SUCCESS) { eAltStatusCode = alt_spi_config_set(&stAltSPIdevice, &cfg); } if (eAltStatusCode == ALT_E_SUCCESS) { eAltStatusCode = alt_spi_speed_set(&stAltSPIdevice, SPI_SPEED); } if (eAltStatusCode == ALT_E_SUCCESS) { eAltStatusCode = alt_spi_slave_select_enable(&stAltSPIdevice, SPI_SLAVE_DEVICE); } if (eAltStatusCode == ALT_E_SUCCESS) { eAltStatusCode = alt_spi_enable(&stAltSPIdevice); } return eAltStatusCode; }  


Here is my write function: 

ALT_STATUS_CODE FramDriverReadStatusRegister(uint8_t *uip8Status){ ALT_STATUS_CODE eAltStatusCode = ALT_E_SUCCESS; const uint16_t au16TxOpCodeBuffer = {(uint16_t)OP_CODE_RDSR, 0x0000}; uint16_t au16RxBuffer = {0x0000, 0x0000}; // Check if SPI is initialized! if (0 == stAltSPIdevice.location) { // SPI is not initialized -> Return BAD_OPERATION return ALT_E_BAD_OPERATION; } // Handle CS pin manually!!! SET_CS_PIN_LOW; // Debug alt_spi_int_clear(&stAltSPIdevice, ALT_SPI_STATUS_TXEI); alt_spi_int_clear(&stAltSPIdevice, ALT_SPI_STATUS_RXUI); alt_spi_int_clear(&stAltSPIdevice, ALT_SPI_STATUS_ALL); // Write Op Code for Read Status register (OP_CODE_RDSR) eAltStatusCode = alt_spi_tx_fifo_enq(&stAltSPIdevice, au16TxOpCodeBuffer); // Wait for FIFO to be empty while(ALT_E_TRUE != alt_spi_tx_fifo_is_empty(&stAltSPIdevice)); // Wait for transfer to complete! -> Poll busy flag! while (ALT_E_TRUE == alt_spi_is_busy(&stAltSPIdevice)); // Read back Status Register from device (Size is specified to 1 byte) eAltStatusCode = alt_spi_rx_fifo_deq(&stAltSPIdevice, au16RxBuffer); // Return status register in uip8Status *uip8Status = (uint8_t) (au16RxBuffer & 0x00FF); // Handle CS pin manually!!! SET_CS_PIN_HIGH; return eAltStatusCode; }  


I have read all manuals for HPS and Cyclone V regarding SPI and TX should start if the following conditions are met: 



--- Quote Start ---  


The SPI master starts data transfers when all the following conditions are met: 

• The SPI master is enabled 

• There is at least one valid entry in the transmit FIFO buffer 

• A slave device is selected 


--- Quote End ---  



I can see all three conditions in my SPI status registers, but still no output. 


Any help would be appreciated! 


Best regards 




I tried the command sequence above from u-boot, but I can't make it write out data...
0 Kudos
Honored Contributor II

Hi all 


I found my problem. Remember to initialize this pin to '1' in the FPGA, if using Motorola SPI frame format ('0' for TI SSP): 


hps_0_spim0_ss_in_n => '1' 


Now it works! 


Best regards 


Thank you so much for letting us know to tie this signal off. Had been struggling to get SPI Master working.

0 Kudos