MAX10 & Arduino SPI通信 (3)通信テスト【FPGA プログラム】

シェアする

元記事はこちら

プログラムはメインとSPIコントロール用に2種類あります。

メインプログラム中にシグナルタップ用の周波数逓倍回路(PLL)が組み込まれてますが、削除して問題ないです。PLL回路を入れたまま試す場合は、IPコアよりALTPLLを呼び出して周波数クロック48MHzの4倍、192MHzとなるよう設定してください。

メインモジュール


//MAX10_FB
module main(
 //system
 input wire  RST,        //48MHz PIN
 input wire  CLK,        //PIN 27
 
 output  wire  LED_R,        //PIN 120
 output  wire  LED_G,        //PIN 121
 output  wire  LED_B,        //PIN 122
 
 //SPI
 input wire    SCK,        //8MHz  PIN
 output  wire    MISO,       //PIN
 input wire    MOSI,       //PIN
 input wire  SS,         //PIN
 
 //LED
 output  wire  [0:7] ROW,    //PIN
 output  wire  [0:7] COL     //PIN
);
/**********************  REGSITER  **********************/
reg     [19:0]    COUNTER;
//regster
reg   [0:7]   AD;
reg   [0:7]   LEDR_reg;
reg   [0:7]   LEDG_reg;
reg   [0:7]   LEDB_reg;
reg         DOT_CNT;
reg   [0:7]   DOT_0;
reg   [0:7]   DOT_1;
reg   [0:7]   DOT_2;
reg   [0:7]   DOT_3;
reg   [0:7]   DOT_4;
reg   [0:7]   DOT_5;
reg   [0:7]   DOT_6;
reg   [0:7]   DOT_7;
//SPI control
reg   [0:7]   R_BYTE;
reg         RDt_rst;
reg         nR_W;
//SPI
reg         WDtrig;
//reg         WDt_rst;
reg   [0:7]   Rdata;
//LEDRGB
reg   [0:7]   LEDR;
reg   [0:7]   LEDG;
reg   [0:7]   LEDB;
reg   [0:7]   LEDR_C;
reg   [0:7]   LEDG_C;
reg   [0:7]   LEDB_C;
//8*8 DOT LED
reg   [0:3]   ROW_CNT;
/**********************    WIRE    **********************/
//SPI
wire        SS_sel;
wire        RDtrig;
wire  [0:7]   R_Data;
wire  [0:7]   W_Data;
/////////////////////////////////////////////////////////
//480kHzカウンター
always @(posedge CLK or negedge RST)
begin
   if(~RST)begin
       COUNTER <= 20'b0;
   end
   else if(COUNTER >= 48000)begin
       COUNTER <= 20'b0;
   end
   else begin
       COUNTER <= COUNTER + 1'b1;
   end
end
/////////////////////////////////////////////////////////
// RGB LED
/////////////////////////////////////////////////////////
//LEDR counter
always @(posedge CLK or negedge RST)
begin
   if(~RST)begin
       LEDR_C <= 8'b0;
   end
   else if(LEDR_reg == 8'h00)begin
       LEDR_C <= 8'b0;
   end
   else begin
       LEDR_C <= LEDR_C + 1'b1;
   end
end
//LEDR
always @(posedge CLK or negedge RST)
begin
   if(~RST)begin
       LEDR <= 1'b1;
   end
   else if(LEDR_C < LEDR_reg)begin
       LEDR <= 1'b0;
   end
   else begin
       LEDR <= 1'b1;
   end
end
//LEDG counter
always @(posedge CLK or negedge RST)
begin
   if(~RST)begin
       LEDG_C <= 8'b0;
   end
   else if(LEDG_reg == 8'h00)begin
       LEDG_C <= 8'b0;
   end
   else begin
       LEDG_C <= LEDG_C + 1'b1;
   end
end
//LEDG
always @(posedge CLK or negedge RST)
begin
   if(~RST)begin
       LEDG <= 1'b1;
   end
   else if(LEDG_C < LEDG_reg)begin
       LEDG <= 1'b0;
   end
   else begin
       LEDG <= 1'b1;
   end
end
//LEDB counter
always @(posedge CLK or negedge RST)
begin
   if(~RST)begin
       LEDB_C <= 8'b0;
   end
   else if(LEDB_reg == 8'h00)begin
       LEDB_C <= 8'b0;
   end
   else begin
       LEDB_C <= LEDB_C + 1'b1;
   end
end
//LEDB
always @(posedge CLK or negedge RST)
begin
   if(~RST)begin
       LEDB <= 1'b1;
   end
   else if(LEDB_C < LEDB_reg)begin
       LEDB <= 1'b0;
   end
   else begin
       LEDB <= 1'b1;
   end
end
assign LED_R = LEDR;
assign LED_G = LEDG;
assign LED_B = LEDB;
/////////////////////////////////////////////////////////
// 8*8 DOT LED
/////////////////////////////////////////////////////////
always @(posedge CLK or negedge RST)
begin
   if(~RST)begin
       ROW_CNT <= 4'b0;
   end
   else if(DOT_CNT == 1'b0)begin
       ROW_CNT <= 4'b0;
   end
   else if( COUNTER >= 48000 )begin
       if(ROW_CNT >= 4'd8)begin
         ROW_CNT <= 4'b1;
       end
       else begin
         ROW_CNT <= ROW_CNT + 1'b1;
       end
   end
   else begin
       ROW_CNT <= ROW_CNT;
   end
end
assign COL = (ROW_CNT == 4'd0)  ? 8'h00:
     ((ROW_CNT == 4'd1)  ? DOT_0:
     ((ROW_CNT == 4'd2)  ? DOT_1:
     ((ROW_CNT == 4'd3)  ? DOT_2:
     ((ROW_CNT == 4'd4)  ? DOT_3:
     ((ROW_CNT == 4'd5)  ? DOT_4:
     ((ROW_CNT == 4'd6)  ? DOT_5:
     ((ROW_CNT == 4'd7)  ? DOT_6:
     ((ROW_CNT == 4'd8)  ? DOT_7:
     8'h000))))))));
     
assign ROW = (ROW_CNT == 4'd0)  ? 8'h00:
     ((ROW_CNT == 4'd1)  ? 8'b0000_0001:
     ((ROW_CNT == 4'd2)  ? 8'b0000_0010:
     ((ROW_CNT == 4'd3)  ? 8'b0000_0100:
     ((ROW_CNT == 4'd4)  ? 8'b0000_1000:
     ((ROW_CNT == 4'd5)  ? 8'b0001_0000:
     ((ROW_CNT == 4'd6)  ? 8'b0010_0000:
     ((ROW_CNT == 4'd7)  ? 8'b0100_0000:
     ((ROW_CNT == 4'd8)  ? 8'b1000_0000:
     8'h000))))))));
/////////////////////////////////////////////////////////
// registeres
/////////////////////////////////////////////////////////
//
always @(posedge CLK or negedge RST)
begin
   if(~RST)begin
       AD <= 8'b0;
   end
   else if( (R_BYTE == 8'h00) && RDtrig )begin
       AD <= R_Data;
   end
   else begin
       AD <= AD;
   end
end
//AD(00)
always @(posedge CLK or negedge RST)
begin
   if(~RST)begin
       LEDR_reg <=8'b0;
   end
   else if((AD==8'h00) && RDtrig && nR_W && (R_BYTE==8'd3))begin
       LEDR_reg <= R_Data;
   end
   else begin
       LEDR_reg <= LEDR_reg;
   end
end
//AD(01)
always @(posedge CLK or negedge RST)
begin
   if(~RST)begin
       LEDG_reg <= 8'b0;
   end
   else if((AD==8'h01) && RDtrig && nR_W && (R_BYTE==8'd3))begin
       LEDG_reg <= R_Data;
   end
   else begin
       LEDG_reg <= LEDG_reg;
   end
end
//AD(02)
always @(posedge CLK or negedge RST)
begin
   if(~RST)begin
       LEDB_reg <= 8'b0;
   end
   else if((AD==8'h02) && RDtrig && nR_W && (R_BYTE==8'd3))begin
       LEDB_reg <= R_Data;
   end
   else begin
       LEDB_reg <= LEDB_reg;
   end
end
//AD(08)
always @(posedge CLK or negedge RST)
begin
   if(~RST)begin
       DOT_CNT <= 1'b0;
   end
   else if((AD==8'h08) && RDtrig && nR_W && (R_BYTE==8'd3))begin
       DOT_CNT <= R_Data[7];
   end
   else begin
       DOT_CNT <= DOT_CNT;
   end
end
//AD(10)
always @(posedge CLK or negedge RST)
begin
   if(~RST)begin
       DOT_0 <= 8'b0;
   end
   else if((AD==8'h10) && RDtrig && nR_W && (R_BYTE==8'd3))begin
       DOT_0 <= R_Data;
   end
   else begin
       DOT_0 <= DOT_0;
   end
end
//AD(11)
always @(posedge CLK or negedge RST)
begin
   if(~RST)begin
       DOT_1 <= 8'b0;
   end
   else if((AD==8'h11) && RDtrig && nR_W && (R_BYTE==8'd3))begin
       DOT_1 <= R_Data;
   end
   else begin
       DOT_1 <= DOT_1;
   end
end
//AD(12)
always @(posedge CLK or negedge RST)
begin
   if(~RST)begin
       DOT_2 <= 8'b0;
   end
   else if((AD==8'h12) && RDtrig && nR_W && (R_BYTE==8'd3))begin
       DOT_2 <= R_Data;
   end
   else begin
       DOT_2 <= DOT_2;
   end
end
//AD(13)
always @(posedge CLK or negedge RST)
begin
   if(~RST)begin
       DOT_3 <= 8'b0;
   end
   else if((AD==8'h13) && RDtrig && nR_W && (R_BYTE==8'd3))begin
       DOT_3 <= R_Data;
   end
   else begin
       DOT_3 <= DOT_3;
   end
end
//AD(14)
always @(posedge CLK or negedge RST)
begin
   if(~RST)begin
       DOT_4 <= 8'b0;
   end
   else if((AD==8'h14) && RDtrig && nR_W && (R_BYTE==8'd3))begin
       DOT_4 <= R_Data;
   end
   else begin
       DOT_4 <= DOT_4;
   end
end
//AD(15)
always @(posedge CLK or negedge RST)
begin
   if(~RST)begin
       DOT_5 <= 8'b0;
   end
   else if((AD==8'h15) && RDtrig && nR_W && (R_BYTE==8'd3))begin
       DOT_5 <= R_Data;
   end
   else begin
       DOT_5 <= DOT_5;
   end
end
//AD(16)
always @(posedge CLK or negedge RST)
begin
   if(~RST)begin
       DOT_6 <= 8'b0;
   end
   else if((AD==8'h16) && RDtrig && nR_W && (R_BYTE==8'd3))begin
       DOT_6 <= R_Data;
   end
   else begin
       DOT_6 <= DOT_6;
   end
end
//AD(17)
always @(posedge CLK or negedge RST)
begin
   if(~RST)begin
       DOT_7 <= 8'b0;
   end
   else if((AD==8'h17) && RDtrig && nR_W && (R_BYTE==8'd3))begin
       DOT_7 <= R_Data;
   end
   else begin
       DOT_7 <= DOT_7;
   end
end
assign W_Data = (AD==8'h00)  ? LEDR_reg:
       ((AD==8'h01) ? LEDG_reg:
       ((AD==8'h02) ? LEDB_reg:
       ((AD==8'h08) ? DOT_CNT:
       ((AD==8'h10) ? DOT_0:
       ((AD==8'h11) ? DOT_1:
       ((AD==8'h12) ? DOT_2:
       ((AD==8'h13) ? DOT_3:
       ((AD==8'h14) ? DOT_4:
       ((AD==8'h15) ? DOT_5:
       ((AD==8'h16) ? DOT_6:
       ((AD==8'h17) ? DOT_7:
       8'h00))) ) )))))));
/////////////////////////////////////////////////////////
// SPI Control
/////////////////////////////////////////////////////////
//受信トリガ
always @(posedge CLK or negedge RST)
begin
   if(~RST)begin
       RDt_rst <= 1'b0;
   end
   else if(RDtrig)begin
       RDt_rst <= 1'b1;
   end
   else begin
       RDt_rst <= 1'b0;
   end
end
//リード/ライト
always @(posedge CLK or negedge RST)
begin
   if(~RST)begin
       nR_W <= 1'b0;
   end
    else if(SS)begin
       nR_W <= 1'b0;
   end
   else if((R_BYTE==8'd1) && RDtrig)begin
       nR_W <= R_Data[7];
   end
end
//送信データ
always @(posedge CLK or negedge RST)
begin
   if(~RST)begin
       WDtrig <= 1'b0;
   end
    else if( SS )begin
       WDtrig <= 1'b0;
   end
   else if(R_BYTE==8'd2)begin
       WDtrig <= 1'b1;
   end
   else begin
       WDtrig <= WDtrig;
   end
end
//バイト数
always @(posedge CLK or negedge RST)
begin
   if(~RST)begin
       R_BYTE <= 8'b0;
   end
   else if(SS)begin
       R_BYTE <= 8'b0;
   end
   else if(RDtrig && ~RDt_rst)begin
       R_BYTE <= R_BYTE + 1'b1;
   end
   else begin
       R_BYTE <= R_BYTE;
   end
end
assign SS_sel = SS;
//SPIモジュール
mySPI mySPI (
 //system
 .RST    (RST),
 .CLK    (CLK),
 
 
 .SCK    (SCK),
 .MOSI   (MOSI),
 .MISO   (MISO),
 .SS     (SS_sel),
 
 .WDtrig   (WDtrig),       //input     準備できたらHIGHにする
 .WData    (W_Data),       //input [7:0] 送信データ
 
 
 .RDtrig   (RDtrig),       //output    受信したらHIGHなる
 .RDt_rst  (RDt_rst),        //input     受信完了
 .RData    (R_Data)        //output[7:0] 受信データ
);
wire        CLK98M;
wire        locked;
pll pll (
 .areset   (~RST),
 .inclk0   (CLK),
 .c0     (CLK98M),
 .locked   (locked)
 
);
endmodule

SPIモジュール


module mySPI (
 //system
 input wire      RST,
 input wire      CLK,
 
 //SPI
 input wire      SCK,
 input wire      MOSI,
 output  reg       MISO,
 input wire      SS,
 
 //MISO
 input wire      WDtrig,
//  output  wire      WDt_rst,
 input wire  [0:7] WData,
 
 //MOSI
 output  reg       RDtrig,
 input wire      RDt_rst,
 output  wire  [0:7] RData
);
/**********************  REGSITER  **********************/
reg   [0:1]   SCK_EDGE;
reg   [0:3]   BYTE_counter;
reg   [0:7]   READ_DATA;
reg   [0:7]   WRITE_DATA;
/**********************    WIRE    **********************/
wire  [0:1]   sck_load;
wire  [0:1]   sck_latch;
/***************************************************
SPI interface
CHAP = 0
SCK1クロック始めでデータのロード、次のでラッチ
CPOL = 0:立上がりロード、立下りラッチ
CPOL = 1:立下りロード、立上がりラッチ
CHAP = 1
SCK1クロック始めでデータのロード、次のでラッチ
但し、FPGA側のMISOはSSと同時にデータをロード
CPOL = 0:立下りロード、立上がりラッチ
CPOL = 1:立上がりロード、立下りラッチ
***************************************************/
parameter CPHA = 0;
parameter CPOL = 0;
assign  sck_load =  (CPHA == 0) ?   ((CPOL == 0) ? 2'b10: 2'b01):
                 ((CPOL == 0) ? 2'b01: 2'b10);
assign  sck_latch = (CPHA == 0) ?   ((CPOL == 0) ? 2'b01: 2'b10):
                 ((CPOL == 0) ? 2'b10: 2'b01);
/////////////////////////////////////////////////////////
//SCKエッジ
always @(posedge CLK or negedge RST)
begin
 if(~RST)begin
   SCK_EDGE <= 2'b0;
 end
 else begin
   SCK_EDGE <= {SCK_EDGE[1],SCK};
 end
end
//ビット数カウンタ
always @(posedge CLK or negedge RST)
begin
 if(~RST)begin
   BYTE_counter <= 4'b0;
   RDtrig <= 1'b0;
 end
 else if( SS )begin
   BYTE_counter <= 4'b0;
   RDtrig <= 1'b0;
 end
 else if( RDt_rst )begin
   RDtrig <= 1'b0;
 end
 else if( (BYTE_counter >= 4'd8) && (SCK_EDGE == sck_load) )begin
   BYTE_counter <= 4'b0;
   RDtrig <= 1'b1;
 end
 else if( SCK_EDGE == sck_latch )begin
   BYTE_counter <= BYTE_counter + 1'b1;
 end
 else begin
   BYTE_counter <= BYTE_counter;
   RDtrig <= RDtrig;
 end
end
//MOSI 受信データ
always @(posedge CLK or negedge RST)
begin
 if(~RST)begin
   READ_DATA <= 8'b0;
 end
 else if( SS || RDt_rst)begin
   READ_DATA <= 8'b0;
 end 
 else if( SCK_EDGE == sck_latch )begin
   READ_DATA <= {READ_DATA[1:7],MOSI};
 end
 else begin
   READ_DATA <= READ_DATA;
 end
end
//受信データ 送り
assign  RData = (RDtrig == 1) ? READ_DATA : 8'h00;
//MISO 送信データ
always @(posedge CLK or negedge RST)
begin
 if(~RST)begin
   WRITE_DATA <= 8'b0;
 end
 else if( SS )begin
   WRITE_DATA <= 8'b0;
 end
 else if( WDtrig )begin
   WRITE_DATA <= WData;
 end
 else begin
   WRITE_DATA <= WRITE_DATA;
 end
end
//送信データ 送り
always @(posedge CLK or negedge RST)
begin
 if(~RST)begin
   MISO <= 1'b0;
 end
 else if( SS )begin
   MISO <= 1'b0;
 end
 else if( SCK_EDGE == sck_load )begin
   MISO <= WRITE_DATA[BYTE_counter];
 end
 else if( (CPHA == 0) && (BYTE_counter==0) )begin
   MISO <= WRITE_DATA[0];
 end
 else begin
   MISO <= MISO;
 end
end
endmodule

フォローする