nios-spi进阶实验:SPI环路用NIOS处理器生成激励数据发送、接收并验证

实验要求:

本次实验是在上一次spi自环和nios软核练习实验基础上的进阶实验。在nios软核和de0开发板之间建立spi通讯自环,用NIOS处理器生成激励数据(发送),并且用NIOS处理器读取结果数据(接收),每次发送一个数据同时接受一个数据,用软件进行验证读写是否正确。

实验的核心思想与主要问题:

本次实验的核心思想与大体架构并不复杂。只要使用nios软核充当master部分,并用IDE为nios软核写一个自动收发激励数据的c程序,连接上一次实验编译的myspi作为从机部分,构建spi通讯环路即可。然而,在实验进行过程中慢慢发现有很多难点和问题,以下是一些主要的问题:

1在实验前我查阅了很多有关spi读写通讯的博客和书籍资料,主要有stm32、sd卡等硬件设备作为从机的spi读写实验。然而这些实验都有一个共同点——每次连续发送多个数据并保存在该从机设备中,读取时也是一次性读取从机中存储的多个数据。这意味着这些实验在发送或者接受时,无需考虑时序问题。而本实验发一个数据就读一个数据就要考虑何时发送何时读取的问题。这需要使用中断来发送接收数据,或者使用nios-spi的状态寄存器来控制数据的收发,本次实验使用了后一种方法。

2使用nios作为master部分,就必须要考虑nios里sdram的clk与cpu的clk的时钟相位差。这是由于硬件本身布线造成的不可忽视的时延问题,其他实验的从机使用的大都为sd卡或stm32,而本实验使用的是de0开发板,从机硬件的不同pll的设置也不同,这直接影响nios的发送、接受数据寻址是否正确。同时nios里的spi使用何种输入clk也是一个关键问题。本次实验参考了alter友晶提供的sdramDEMO,里面给出了了de0开发板sdram与cup的时钟相位差,同时nios里的spi使用cpu-clk而非sdram-clk。

3主机与从机连接也会出现一些问题。本实验一开始用SOPC builder创建主机部分后使用block diagram文件连接从机构建自环,然后配置管脚,发现数据传输和编译都会报错。最后本实验使用Verilog代码写了一个.v文件来例化主机本分与从机部分,然后使用该例化文件直接使用Verilog代码配置管脚(管脚的配置需参考de0开发板使用手册)。

以上就是本次实验出现的一些主要问题。这些问题第一是缺乏指导资料和对应本实验要求的具体demo,不容易发现问题的原因和找寻解决方法;第二归根到底还是对nios手册和avalon-mm总线协议手册理解和学习得不够透彻导致的。所以即便本实验成功之后,仍有很多需要思考和继续改进的部分。

实验具体过程:

我们希望最终构建的spi环路如上图所示。本实验主要分为硬件设计和软件设计两大部分。硬件部分包括SOPC设计和从机主机连接、管脚分配。软件部分包括设计nios软核的自动生成激励数据并进行发送接收和验证。

一、硬件部分设计

1创建SOPC系统,生成nios软核

本实验的SOPC主要包括:CPU、 JTAG_UART、 SDRAM Controller、EPCS SerialFlash Controller、PIO、SPI、sysid、PLL。

SDRAM Controller的“presets”选择“custom”,“data widths”选择“16bits”,“addressess widths”选择12Row、8column。

CPU的“reset vector”选择“epcs controller”,“exception vector”选择“sdram”。

Pll-c0的“output clock frequency”设为“50Mhz”,“clock phase shift”设为“0ps”。

Pll-c1的“output clock frequency”设为“50Mhz”,“clock phase shift”设为“-60deg”。

本实验参考了de0的sdram-demo的SOPC设计。最终的设计如下图所示:

2建立系统顶层模块,构建spi自环并分配关键

在.v文件中分别例化nios软核和myspi从机部分,使用代码为其分配管脚和连接。(注意,连接nios与从机部分的信号必须为wire类型)。并将该文件作为工程的顶层文件。

构建完成后进行编译,此时管脚已经正确分配,查看RTL视图发现结构符合预期。

具体的Verilog代码将附在文末。

二、软件部分设计

硬件部分相对来说比较容易,只要按照de0的demo配置正确基本不会有什么问题。而软件部分设计出现的问题更多,也是本次实验耗费时间和精力的主要部分。

最开始,我只是简单地设计了一个循环来生成发送数据并进行发送和读取,然后比较两个数据验证读写是否正确,发现结果一直报错。这时我才意识到要考虑发送和接收数据的时序问题,即何时应该发送数据?何时应该读取数据?通过思考和查阅资料发现,主流的解决方法主要为两种:一是发送数据时进入中断,发送完成后等待TX发送完成中断号结束中断,然后等待RX发送接收中断后进入接收状态,等接收完成后结束中断;二是通过spi的状态寄存器控制读写。本次实验最终选择了后一种方法。

Nios-spi自带状态寄存器。其中TRDY置为1时表示TX为空,可以写入新的发送数据,此时让nios发送这一次send_data。RRDY置为1时表示RX为满,等待读取该接收数据,此时读取这一次从机发送过来的recive_data。TMT置为1时表示移位寄存器为空,程序没有进行新的发送或接收操作。参考spi手册后按照nios-spi的位域定义一个spi的结构体,可以观察发送寄存器、接收寄存器和状态寄存器各位的值。此时发送数据一直正确,然而发现接收寄存器每三次读取同一次数据,第四次读取为0,第五次才更新为上一次发送的数据。如下所示:

这个问题我的理解是,因为de0从机硬件设计中包含大量的D触发器,导致主机发送数据给从机接收时,从机需经过一段时延后才能正确读取,然后再把该数据自环发送给主机。于是我根据已经得到的时延规律,每个周期里发送四次同一数据(仍然是发送一个数据就读取一个数据),前两次读取的数据和第四次读取的数据舍弃,只保留第三次的数据作为接收数据进行验证。得到结果正确。

以上就是本次实验。然而仍有两个遗留问题没有解决:

1在通过编写的spi结构体观察寄存器状态时,发现“SPI_ADC->CONTROL.BITS.IRRDY”和“SPI_ADC->RXDATA”始终读不到数据,而通过IORD()函数来读取对应寄存器则可以正确读取。

2就是上文提到的时延问题。本实验虽然通过规律改进读写得到了正确结果,但如果只一次发送一次读取,那应该如何根据时延进行软件设计呢?改换到其他硬件设备作为从机时这个时延又会如何影响读写呢?

这就需要进一步加深对avalon-mm总线协议手册和nios-spi手册的学习和认识。希望能在接下来的学习实验过程中彻底解决以上遗留问题。

 

参考文献及博客:

Nios-spi手册:https://wenku.baidu.com/view/cd289d6925c52cc58bd6be50.html

用nios读写串行flash-M25P16:http://bbs.eeworld.com.cn/thread-294856-1-1.html

nios自带spi核如何编程:https://www.amobbs.com/thread-3914691-1-1.html

 

具体实验代码如下:

Verilog部分:

module DE0_TOP

         (

                  ////////////////////         Clock Input             ////////////////////        

                  CLOCK_50,                                                  //     50 MHz

                  CLOCK_50_2,                                             //     50 MHz

                  ////////////////////         Push Button             ////////////////////

                  BUTTON,                                                     //     Pushbutton[2:0]

                  ////////////////////         DPDT Switch            ////////////////////

                  SW,                                                               //     Toggle Switch[9:0]

                  ////////////////////         7-SEG Dispaly  ////////////////////

                  HEX0_D,                                                      //     Seven Segment Digit 0

                  HEX0_DP,                                                     //     Seven Segment Digit DP 0

                  HEX1_D,                                                      //     Seven Segment Digit 1

                  HEX1_DP,                                                     //     Seven Segment Digit DP 1

                  HEX2_D,                                                      //     Seven Segment Digit 2

                  HEX2_DP,                                                     //     Seven Segment Digit DP 2

                  HEX3_D,                                                      //     Seven Segment Digit 3

                  HEX3_DP,                                                     //     Seven Segment Digit DP 3

                  ////////////////////////  LED           ////////////////////////

                  LEDG,                                                           //     LED Green[9:0]

                  ////////////////////////  UART       ////////////////////////

                  UART_TXD,                                                 //     UART Transmitter

                  UART_RXD,                                                 //     UART Receiver

                  UART_CTS,                                                  //     UART Clear To Send

                  UART_RTS,                                                  //     UART Request To Send

                  /////////////////////       SDRAM Interface             ////////////////

                  DRAM_DQ,                                                 //     SDRAM Data bus 16 Bits

                  DRAM_ADDR,                                             //     SDRAM Address bus 13 Bits

                  DRAM_LDQM,                                                    //     SDRAM Low-byte Data Mask

                  DRAM_UDQM,                                                   //     SDRAM High-byte Data Mask

                  DRAM_WE_N,                                                    //     SDRAM Write Enable

                  DRAM_CAS_N,                                                    //     SDRAM Column Address Strobe

                  DRAM_RAS_N,                                                    //     SDRAM Row Address Strobe

                  DRAM_CS_N,                                             //     SDRAM Chip Select

                  DRAM_BA_0,                                              //     SDRAM Bank Address 0

                  DRAM_BA_1,                                              //     SDRAM Bank Address 1

                  DRAM_CLK,                                                //     SDRAM Clock

                  DRAM_CKE,                                                //     SDRAM Clock Enable

                  ////////////////////         Flash Interface                 ////////////////

                  FL_DQ,                                                         //     FLASH Data bus 16 Bits

                  FL_ADDR,                                                    //     FLASH Address bus 22 Bits

                  FL_WE_N,                                                   //     FLASH Write Enable

                  FL_RST_N,                                                   //     FLASH Reset

                  FL_OE_N,                                                    //     FLASH Output Enable

                  FL_CE_N,                                                     //     FLASH Chip Enable

                  FL_WP_N,                                                   //     FLASH Hardware Write Protect

                  FL_BYTE_N,                                                //     FLASH Selects 8/16-bit mode

                  FL_RY,                                                          //     FLASH Ready/Busy

                  ////////////////////         LCD Module 16X2            ////////////////

                  LCD_BLON,                                                 //     LCD Back Light ON/OFF

                  LCD_RW,                                                     //     LCD Read/Write Select, 0 = Write, 1 = Read

                  LCD_EN,                                                      //     LCD Enable

                  LCD_RS,                                                       //     LCD Command/Data Select, 0 = Command, 1 =Data

                  LCD_DATA,                                                  //     LCD Data bus 8 bits

                  ////////////////////         SD_Card Interface  ////////////////

                  SD_DAT,                                                       //     SD Card Data

                  SD_CMD,                                                     //     SD Card Command Signal

                  SD_CLK,                                                       //     SD Card Clock

                  SD_WP_N,                                                  //     SD Card Write Protect

 

                  ////////////////////         PS2           ////////////////////////////

                  PS2_KBDAT,                                                 //     PS2 Keyboard Data

                  PS2_KBCLK,                                                 //     PS2 Keyboard Clock

                  PS2_MSDAT,                                                //     PS2 Mouse Data

                  PS2_MSCLK,                                                //     PS2 Mouse Clock

                  ////////////////////         VGA          ////////////////////////////

                  VGA_HS,                                                      //     VGA H_SYNC

                  VGA_VS,                                                      //     VGA V_SYNC

                  VGA_R,                                                     //     VGA Red[3:0]

                  VGA_G,                                                      //     VGA Green[3:0]

                  VGA_B,                                                      //     VGA Blue[3:0]

                  ////////////////////         GPIO        ////////////////////////////

                  SS_N,SCK,MISO,MOSI,

                  /////////////////////////////////////////////////////////////////

                  GPIO0_CLKIN,                                            //     GPIO Connection 0 Clock In Bus

                  GPIO0_CLKOUT,                                         //     GPIO Connection 0 Clock Out Bus

                  GPIO0_D,                                                    //     GPIO Connection 0 Data Bus

                  GPIO1_CLKIN,                                   //     GPIO Connection 1 Clock In Bus

                  GPIO1_CLKOUT,                                         //     GPIO Connection 1 Clock Out Bus

                  GPIO1_D                                                      //     GPIO Connection 1 Data Bus

                 

         );

 

////////////////////////  Clock Input             ////////////////////////

input                          CLOCK_50;                                //     50 MHz

input                          CLOCK_50_2;                            //     50 MHz

////////////////////////  Push Button (low-active)        ////////////////////////

input        [2:0]         BUTTON;                                    //     Pushbutton[2:0]

////////////////////////  DPDT Switch            ////////////////////////

input        [9:0]         SW;                                              //     Toggle Switch[9:0]

////////////////////////  7-SEG Dispaly  ////////////////////////

output     [6:0]         HEX0_D;                                     //     Seven Segment Digit 0

output                       HEX0_DP;                                   //     Seven Segment Digit DP 0

output     [6:0]         HEX1_D;                                     //     Seven Segment Digit 1

output                       HEX1_DP;                                   //     Seven Segment Digit DP 1

output     [6:0]         HEX2_D;                                     //     Seven Segment Digit 2

output                       HEX2_DP;                                   //     Seven Segment Digit DP 2

output     [6:0]         HEX3_D;                                     //     Seven Segment Digit 3

output                       HEX3_DP;                                   //     Seven Segment Digit DP 3

////////////////////////////    LED           ////////////////////////////

output     [9:0]         LEDG;                                          //     LED Green[9:0]

////////////////////////////    UART       ////////////////////////////

output                       UART_TXD;                                //     UART Transmitter

input                          UART_RXD;                               //     UART Receiver

output                       UART_CTS;                                //     UART Clear To Send

input                          UART_RTS;                                //     UART Request To Send

///////////////////////            SDRAM Interface    ////////////////////////

inout        [15:0]       DRAM_DQ;                                //     SDRAM Data bus 16 Bits

output     [12:0]       DRAM_ADDR;                           //     SDRAM Address bus 13 Bits

output                       DRAM_LDQM;                                   //     SDRAMLow-byte Data Mask

output                       DRAM_UDQM;                                  //     SDRAM High-byte Data Mask

output                       DRAM_WE_N;                                   //     SDRAM Write Enable

output                       DRAM_CAS_N;                                  //     SDRAM Column Address Strobe

output                       DRAM_RAS_N;                                  //     SDRAM Row Address Strobe

output                       DRAM_CS_N;                            //     SDRAM Chip Select

output                       DRAM_BA_0;                            //     SDRAM Bank Address 0

output                       DRAM_BA_1;                            //     SDRAM Bank Address 1

output                       DRAM_CLK;                               //     SDRAM Clock

output                       DRAM_CKE;                               //     SDRAM Clock Enable

////////////////////////  Flash Interface        ////////////////////////

inout        [15:0]       FL_DQ;                                       //     FLASH Data bus 16 Bits

output     [21:0]       FL_ADDR;                                   //     FLASH Address bus 22 Bits

output                       FL_WE_N;                                  //     FLASH Write Enable

output                       FL_RST_N;                                 //     FLASH Reset

output                       FL_OE_N;                                   //     FLASH Output Enable

output                       FL_CE_N;                                   //     FLASH Chip Enable

output                       FL_WP_N;                                  //     FLASH Hardware Write Protect

output                       FL_BYTE_N;                               //     FLASH Selects 8/16-bit mode

input                          FL_RY;                                         //     FLASH Ready/Busy

////////////////////         LCD Module 16X2   ////////////////////////////

inout        [7:0]         LCD_DATA;                                //     LCD Data bus 8 bits

output                       LCD_BLON;                               //     LCD Back Light ON/OFF

output                       LCD_RW;                                    //     LCD Read/Write Select, 0 = Write, 1 = Read

output                       LCD_EN;                                     //     LCD Enable

output                       LCD_RS;                                     //     LCD Command/Data Select, 0 = Command, 1 =Data

////////////////////         SD Card Interface   ////////////////////////

inout                          SD_DAT;                                 //     SDCard Data 0

inout                          SD_CMD;                                   //     SD Card Command Signal

output                       SD_CLK;                                      //     SD Card Clock

input                          SD_WP_N;                                 //     SD Card Write Protect

////////////////////////  PS2           ////////////////////////////////

inout                        PS2_KBDAT;                               //     PS2 Keyboard Data

inout                          PS2_KBCLK;                               //     PS2 Keyboard Clock

inout                        PS2_MSDAT;                              //     PS2 Mouse Data

inout                          PS2_MSCLK;                              //     PS2 Mouse Clock

////////////////////////  VGA                   ////////////////////////////

output                       VGA_HS;                                     //     VGA H_SYNC

output                       VGA_VS;                                     //     VGA V_SYNC

output     [3:0]         VGA_R;                                   //     VGA Red[3:0]

output     [3:0]         VGA_G;                                     //     VGA Green[3:0]

output     [3:0]         VGA_B;                                   //     VGA Blue[3:0]

////////////////////////  GPIO        ////////////////////////////////

input        [1:0]         GPIO0_CLKIN;                  //     GPIO Connection 0 Clock In Bus

output     [1:0]         GPIO0_CLKOUT;                       //     GPIO Connection 0 Clock Out Bus

inout        [31:0]       GPIO0_D;                                   //     GPIO Connection 0 Data Bus

input        [1:0]         GPIO1_CLKIN;                  //     GPIO Connection 1 Clock In Bus

output     [1:0]         GPIO1_CLKOUT;                       //     GPIO Connection 1 Clock Out Bus

inout        [31:0]       GPIO1_D;                                   //     GPIO Connection 1 Data Bus

output  SS_N,SCK,MISO,MOSI;

//=======================================================

// REG/WIRE declarations

//=======================================================

 

 

 

//=======================================================

// Structural coding

//=======================================================

wire system_reset_n;

 

assign system_reset_n = 1'b1;

assign FL_RST_N = system_reset_n;

assign FL_WP_N = 1'b1; // notwrite protect

assign FL_BYTE_N = 1'b1; // 16-bitmode

wire FLASH_16BIT_IP_A0;

 

 

wire SS_N_W,SCK_W;

wire MISO_W,MOSI_W;

assign SS_N = SS_N_W;

assign SCK = SCK_W;

assign MISO = MISO_W;

assign MOSI = MOSI_W;

 

DE0_SOPC DE0_SOPC_inst(

                  // 1) global signals:

                   .clk(CLOCK_50),

                   .pll_cpu(),

                   .pll_sdram(DRAM_CLK),

                   .reset_n(system_reset_n),

                  

                

 

                  // the_buttons

                  .in_port_to_the_buttons(BUTTON),

                  

                  // the_switches

                  .in_port_to_the_switches(SW),

                  

                  

                  // the_seg7

                  .out_port_from_the_seg7({HEX3_DP, HEX3_D, HEX2_DP, HEX2_D, HEX1_DP,HEX1_D, HEX0_DP, HEX0_D}),                  

                  

                  

                  

                  // the_lcd

                  .LCD_E_from_the_lcd(LCD_EN),

                  .LCD_RS_from_the_lcd(LCD_RS),

                  .LCD_RW_from_the_lcd(LCD_RW),

                  .LCD_data_to_and_from_the_lcd(LCD_DATA),

                  .out_port_from_the_lcd_light(LCD_BLON),

 

                  // the_leds

                  .out_port_from_the_leds(LEDG),

 

 

                  // the_sd_clk

                  .out_port_from_the_sd_clk(SD_CLK),

 

                  // the_sd_cmd

                  .bidir_port_to_and_from_the_sd_cmd(SD_CMD),

 

                  // the_sd_dat

                  .bidir_port_to_and_from_the_sd_dat(SD_DAT),

 

                  // the_sd_wp_n

                  .in_port_to_the_sd_wp_n(SD_WP_N),

 

 

                  // the_sdram

                  .zs_addr_from_the_sdram(DRAM_ADDR),

                  .zs_ba_from_the_sdram({DRAM_BA_1,DRAM_BA_0}),

                  .zs_cas_n_from_the_sdram(DRAM_CAS_N),

                  .zs_cke_from_the_sdram(DRAM_CKE),

                   .zs_cs_n_from_the_sdram(DRAM_CS_N),

                  .zs_dq_to_and_from_the_sdram(DRAM_DQ),

                  .zs_dqm_from_the_sdram({DRAM_UDQM,DRAM_LDQM}),

                  .zs_ras_n_from_the_sdram(DRAM_RAS_N),

                   .zs_we_n_from_the_sdram(DRAM_WE_N),

 

                  //the_tristate_bridge_avalon_slave (16-bit mode)

                  .address_to_the_cfi_flash({FL_ADDR, FLASH_16BIT_IP_A0}),

                  .data_to_and_from_the_cfi_flash(FL_DQ),

                   .read_n_to_the_cfi_flash(FL_OE_N),

                  .select_n_to_the_cfi_flash(FL_CE_N),

                  .write_n_to_the_cfi_flash(FL_WE_N),

                  

 

                  // the_uart

                  .cts_n_to_the_uart(UART_CTS),

                   .rts_n_from_the_uart(UART_RTS),

                   .rxd_to_the_uart(UART_RXD),

                  .txd_from_the_uart(UART_TXD),

                  

                  //  the_spi

                   .MOSI_from_the_spi(MOSI_W),

                   .SCLK_from_the_spi(SCK_W),

                   .SS_n_from_the_spi(SS_N_W),

                   .MISO_to_the_spi(MISO_W)

                  

                 

                );

               

               

               

MYSPI SPI_SLAYER(

                                      .nrst(system_reset_n),

                                      .clk(CLOCK_50),

                                      .ncs(SS_N_W),

                                      .mosi(MOSI_W),

                                      .miso(MISO_W),

                                      .sck(SCK_W)     

                                     

                                                                     

                                   ); 

 

endmodule

 

 

module MYSPI(

nrst  ,

clk             ,

ncs            ,

mosi         ,

miso         ,

sck            ); 

 

input clk, nrst; 

input ncs, mosi, sck; 

output miso; 

 

reg[2:0] sck_edge;

reg[7:0] byte_received; 

reg[3:0] bit_received_cnt; 

reg rec_flag; 

reg[1:0] rec_status;  //SPI接收部分状态机 

reg[7:0] rec_data; 

reg[2:0] rec_flag_width;  //SPI接收完成标志位脉冲宽度寄存器 

reg miso; 

reg sending_flag;  //正在发送标志位 

reg[7:0] byte_sended;  //发送移位寄存器 

reg[3:0] bit_sended_cnt;  //SPI发送位计数器 

reg[1:0] send_status;  //SPI发送部分状态机 

 

wire sck_riseedge,sck_falledge; 

assign sck_riseedge =(sck_edge[2:1] == 2'b01);  //检测到SCK由0变成1,则认为发现上跳沿 

assign sck_falledge = (sck_edge[2:1]== 2'b10);  //检测到SCK由1变成0,则认为发现下跳沿 

 

always @ (posedge clk or negedgenrst) begin 

   if(~nrst) begin 

        sck_edge <= 3'b000; 

   end 

   else begin 

        sck_edge <= {sck_edge[1:0],sck}; 

   end 

end    

 

always @ (posedge clk or negedgenrst) begin

   if(~nrst) begin 

        byte_received <= 8'h00; 

        bit_received_cnt <= 4'h0; 

        rec_flag <= 1'b0; 

        rec_status <= 2'b00; 

        rec_flag_width <= 3'b000;

   end 

   else begin 

        if(~ncs) begin 

          if(~sending_flag) begin

            case (rec_status) 

            2'b00: begin 

                if(sck_riseedge) begin 

                    byte_received <={byte_received[6:0], mosi}; 

                    if(bit_received_cnt ==4'b0111) begin 

                        bit_received_cnt <=4'b0000; 

                        rec_status <=2'b01; 

                    end 

                    else begin 

                        bit_received_cnt <=bit_received_cnt+1; 

                    end 

                end 

            end 

            2'b01: begin 

                rec_data <=byte_received; 

                rec_flag <= 1'b1; 

                if(rec_flag_width==3'b100)begin 

                    rec_flag_width <=3'b000; 

                    rec_status <=2'b11; 

                end 

                else begin 

                    rec_flag_width <=rec_flag_width+1; 

                end 

            end 

            2'b11: begin 

                rec_flag <= 1'b0; 

                rec_status <= 2'b00; 

            end 

            endcase

          end 

        end      

   end 

end 

 

always @ (posedge clk or negedgenrst) begin 

   if(~nrst) begin 

        byte_sended <= 8'h00; 

        bit_sended_cnt <= 4'b0000; 

        send_status <= 2'b00; 

        sending_flag <= 1'b0; 

   end 

   else begin 

        if(~ncs) 

        begin

            case (send_status) 

            2'b00: begin

                                   if(rec_flag== 1'b1) begin

                                            sending_flag<= 1'b1;   

                    byte_sended <= rec_data;

                    send_status <=2'b01; 

                end 

            end 

            2'b01: begin 

                if(sck_riseedge) begin 

                    //miso <=byte_sended[7]; 

                    send_status <=2'b11; 

                end 

            end 

            2'b11: begin

                                   miso<= byte_sended[7];

                if(sck_falledge) begin

                    byte_sended <={byte_sended[6:0], 1'b0}; 

                    if(bit_sended_cnt ==4'b0111) begin 

                        send_status <=2'b10; 

                        bit_sended_cnt <=4'b0000; 

                        sending_flag <=1'b0; 

                    end 

                    else begin 

                        bit_sended_cnt <=bit_sended_cnt+1;

                        //send_status <=2'b01;

                    end 

                end 

            end 

            2'b10: begin

                                   //sending_flag<= 1'b0;

                send_status <= 2'b00;

                miso <= 1'b0; 

            end 

            endcase 

        end 

   end 

end   

 

endmodule

 

c语言部分:

#include"stdio.h"

#include"unistd.h"

#include"system.h"

#include"io.h"

 

#include"altera_avalon_spi.h"

#include"altera_avalon_pio_regs.h"

#include"altera_avalon_spi_regs.h"  //定义了SPI寄存器的基本信息

#include"alt_types.h"    //Altera自定义的一些数据类型

#include"string.h"

 

 

typedefstruct{

 

    volatileunsignedlongint RXDATA;

 

    volatileunsignedlongint TXDATA;

 

    union{

        struct{

            volatileunsignedlongint NC       :3;

            volatileunsignedlongint ROE      :1;

            volatileunsignedlongint TOE      :1;

            volatileunsignedlongint TMT      :1;

            volatileunsignedlongint TRDY     :1;

            volatileunsignedlongint RRDY     :1;

            volatileunsignedlongint E        :1;

            volatileunsignedlongint NC1      :23;        

        }BITS;

        volatileunsignedlongint WORD;

    }STATUS;

 

    union{

        struct{

            volatileunsignedlongint NC       :3;

            volatileunsignedlongint IROE     :1;

            volatileunsignedlongint ITOE     :1;

            volatileunsignedlongint NC1      :1;

            volatileunsignedlongint ITRDY    :1;

            volatileunsignedlongint IRRDY    :1;

            volatileunsignedlongint IE       :1;

            volatileunsignedlongint NC2      :1;

            volatileunsignedlongint SSO      :21;

        }BITS;

        volatileunsignedlongint CONTROL;

    }CONTROL;

 

    unsignedlongint RESERVED0;

    unsignedlongint SLAVE_SELECT;

 

}SPI_ADC_T;

 

#define SPI_ADC         ((SPI_ADC_T *) SPI_BASE)//SPI_ADC_BASE是在system.h里产生的地址

 

 

void send_data(alt_u8 data)

{   

    while(!SPI_ADC->STATUS.BITS.TRDY);

    //printf("0x%x\n",SPI_ADC->TXDATA);

    IOWR(SPI_BASE, 5, 1);

    IOWR(SPI_BASE , 1, data);

    while(!SPI_ADC->STATUS.BITS.TMT);   

    //printf("SENDDATA=0x%x\n",SPI_ADC->TXDATA);

    IOWR(SPI_BASE, 5, 0);

    

}

 

alt_u8 read_data()

{

    alt_u8 data;

 

    while(!(IORD(SPI_BASE, 2)&0x80));

    IOWR(SPI_BASE, 5, 1);

    data = IORD(SPI_BASE, 0);

    //printf("READDATA=0x%x\n",data);

    //printf("RXDATA=0x%x\n",SPI_ADC->RXDATA);

    IOWR(SPI_BASE, 5, 0);

 

    return data;

}

 

int main(void)

{

    alt_u8 i;

    alt_u8 buf;

    alt_u8 check;

   

//    IOWR(SPI_BASE, 5, 1);

//    IOWR(SPI_BASE , 1, 0xc7);

//    IOWR(SPI_BASE, 5, 0);

  

    printf("--------start spi!----------\n");

    for(i=0;i<63;i++)

    {

 

        int cnt = 500;

       

        alt_u8 status;

        status = IORD(SPI_BASE, 2);

        printf("status = 0x%x\n",status);

       

       

        buf = (alt_u8)i+1;

       

       

        int j;

        for(j = 0;j < 2;j++)

        {

            send_data(buf);

            status = IORD(SPI_BASE, 0);

            printf("false_read = 0x%x\n",status);

        }

        send_data(buf);

       

        status = IORD(SPI_BASE, 2);

        printf("status = 0x%x\n",status);

        //printf("RRDY=%d\n",SPI_ADC->STATUS.BITS.RRDY);

       

        check = read_data();

       

       

        while(cnt--);

       

       

        if(check == buf)

        {

            printf("----time %d is right! buf = %d,check = %d!----\n",i,buf,check);

        }

        else

        {

            printf("----time %d is false! buf = %d,check = %d!----\n",i,buf,check);

        }

        send_data(buf);

        check = read_data();

    }

    return 0;

   

}

 

猜你喜欢

转载自blog.csdn.net/weixin_41033536/article/details/80242194
SPI