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