MAX10でSPIを作る

MAX10でSPIを作りました。  
 QuartusPrimeでSPI IP を探したのですがAvalonバス接続のものは有るのですが、単独のものは見つけられませんでした。 FPGAボードのピン数が限られているので作ることにしました。
 参考になるものをWEBで探したのですが、FPGA内部クロック同期式のものは見つかったのですが、同期のために速い内部クロックが必要なのでSPIクロックを使う方式で作ることにしました。


●構成

 次は、構成図、実験の状況の概要です。  

 Rx23TからSPIで送られてきたデータを一旦レジスターで受け、外部HostであるExtErnal Bus To Avalon Bridgeに送ります。AvalonバスのSlave側はAvalonPIO に接続しています。このAvalonPIO の出力は、7セグLEDに接続しています。
 制御データは複数バイトでRx23tから送られてきます。例えば、データ転送と書込み指令は、モードバイトと2バイトのデータです。モードバイトは、SPIのデータ方向と、レジスタアドレスと、動作指令を指定できます。
 動作波形は、4バイトのアドレスと2バイトのデータを転送している状況です。  


 



 



 



 


●SPIのタイミングとリスト

 次は、SPIのタイミングとリストです。

 動作は、SPIのクロックを使っています。 FPGA内部クロックを使った所は nCS 信号の立上りと立下りの検出する所です
 リストは、SPI関連を抜き出しました。

 



//=======================================================
// SPI interface control
//=======================================================

// ********** Spi interface Signal Change
wire w_nSpiCs, w_SpiMoSi, w_SpiMiSo, w_SpiSck;
wire w_SpiGpio5, w_SpiGpio6, w_SpiGpio7, w_SpiGpio8;

assign w_nSpiCs = ARDUINO_IO[0];
assign w_SpiSck = ARDUINO_IO[1];

assign w_SpiMoSi = ARDUINO_IO[2];
assign ARDUINO_IO[3] = w_SpiMiSo;

assign w_SpiGpio5 = ARDUINO_IO[4];
assign w_SpiGpio6 = ARDUINO_IO[5];
assign w_SpiGpio7 = ARDUINO_IO[6];
assign w_SpiGpio8 = ARDUINO_IO[7];

// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// ********** Spi rSpiEnd/Start control
wire w_nSpiStart, w_SpiEnd;
reg[1:0] rSpiEnd;

always @(posedge MAX10_CLK1_50 or negedge w_nSysRst )
begin
if ( w_nSysRst == 1'b0) rSpiEnd <= 2'h0; // reset
else rSpiEnd <= {rSpiEnd[0], w_nSpiCs}; // Shift In
end

assign w_SpiEnd = rSpiEnd == 2'h1;
assign w_nSpiStart = ~(rSpiEnd == 2'h2);

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// ********** Spi rSpiCtrlC In control & Spi control
wire w_SpiTxSftLoadT, w_SpiRxDataLoadT, w_SpiRxAdrsLoadT;
wire w_SpiRxLoad_0, w_SpiRxLoad_1, w_SpiRxLoad_2, w_SpiRxLoad_3, w_SpiRxLoad_4;
wire w_rSpiModeLoad;


reg[7:0] rSpiCtrlC; // bitCntr:3bit, ByteCntr;5bit

always @(posedge w_SpiSck or negedge w_nSpiStart )
begin
if ( w_nSpiStart == 1'b0) rSpiCtrlC <= 8'h00; // reset
else rSpiCtrlC <= rSpiCtrlC + 8'h01; // + 1
end

assign w_SpiTxSftLoadT = rSpiCtrlC[2:0] == 3'h1;
assign w_SpiRxDataLoadT = (rSpiCtrlC[2:0] == 3'h0) & (rSpiMode[3:1] == 3'h2);
assign w_SpiRxAdrsLoadT = (rSpiCtrlC[2:0] == 3'h0) & (rSpiMode[3:1] == 3'h1);

assign w_SpiRxLoad_0 = rSpiCtrlC[7:3] == 5'h01;
assign w_SpiRxLoad_1 = (rSpiCtrlC[7:3] == 5'h02) & (~rSpiMode[0]);
assign w_SpiRxLoad_2 = (rSpiCtrlC[7:3] == 5'h03) & (~rSpiMode[0]);
assign w_SpiRxLoad_3 = (rSpiCtrlC[7:3] == 5'h04) & (~rSpiMode[0]);
assign w_SpiRxLoad_4 = (rSpiCtrlC[7:3] == 5'h05) & (~rSpiMode[0]);

assign w_rSpiModeLoad = (rSpiCtrlC[2:0] == 3'h0) & w_SpiRxLoad_0;

// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// ********** Spi rSpiMode In control
reg[7:0] rSpiMode;

always @(negedge w_SpiSck or negedge w_nSpiStart )
begin
if ( w_nSpiStart == 1'b0) rSpiMode <= 8'h00; // reset
else if (w_rSpiModeLoad) rSpiMode <= rSpiRxSft ; // Shift
else rSpiMode <= rSpiMode; // Hold
end

// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// ********** Spi rSpiRxSft In control
reg[7:0] rSpiRxSft;

always @(posedge w_SpiSck or negedge w_nSpiStart )
begin
if ( w_nSpiStart == 1'b0) rSpiRxSft <= 8'h00; // reset
else rSpiRxSft <= {rSpiRxSft[6:0], w_SpiMoSi}; // Sft In
end

// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// ********** Spi rSpiTxSft Out control
wire[7:0] w_rSpiTxSftInD ;
reg[7:0] rSpiTxSft;

assign w_rSpiTxSftInD =
(rSpiMode[0] & (rSpiCtrlC[7:3] == 5'h01)) ? rExtH_RdD[15:8] :
(rSpiMode[0] & (rSpiCtrlC[7:3] == 5'h02)) ? rExtH_RdD[7:0] :
8'h00;

always @(negedge w_SpiSck or negedge w_nSpiStart )
begin
if ( w_nSpiStart == 1'b0) rSpiTxSft <= 8'h00; // Status In
else if (w_SpiTxSftLoadT) rSpiTxSft <= w_rSpiTxSftInD ; // Shift
else rSpiTxSft <= {rSpiTxSft[6:0], 1'b0}; // Shift Out
end

assign w_SpiMiSo = (~w_nSpiCs) ? rSpiTxSft[0] : 1'bz;

//=======================================================
// ExtHost interface control
//=======================================================

// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// ********** ExtHost rExtH_WrD, rExtH_RdD control
wire[15:0] wI_AvalonMM_RdData;
reg[15:0] rExtH_WrD, rExtH_RdD;


always @(negedge w_SpiSck or negedge w_nSysRst )
begin
if ( w_nSysRst == 1'b0) rExtH_WrD <= 16'h0000; // reset
else if (w_SpiRxDataLoadT & w_SpiRxLoad_1) rExtH_WrD[15:8] <= rSpiRxSft; // HighB In
else if (w_SpiRxDataLoadT & w_SpiRxLoad_2) rExtH_WrD[7:0] <= rSpiRxSft; // LowB In
else rExtH_WrD <= rExtH_WrD; // Hold
end

always @(posedge MAX10_CLK1_50 or negedge w_nSysRst )
begin
if ( w_nSysRst == 1'b0) rExtH_RdD <= 16'h0000; // reset
// else if (wMcuCs1Wr & (rAdrsLatch == 8'h0D)) rExtH_RdD[15:8] <= wI_AvalonMM_RdData; // In
else rExtH_RdD <= rExtH_RdD; // Hold
end

// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// ********** ExtHost rExtHAdrs In control
reg[31:0] rExtHAdrs;

always @(negedge w_SpiSck or negedge w_nSysRst )
begin
if ( w_nSysRst == 1'b0) rExtHAdrs <= 31'h00000000; // reset
else if (w_SpiRxAdrsLoadT & w_SpiRxLoad_1) rExtHAdrs[31:24] <= rSpiRxSft; // HighB In
else if (w_SpiRxAdrsLoadT & w_SpiRxLoad_2) rExtHAdrs[23:16] <= rSpiRxSft; // MidHighB In
else if (w_SpiRxAdrsLoadT & w_SpiRxLoad_3) rExtHAdrs[15:8] <= rSpiRxSft; // MidLowB In
else if (w_SpiRxAdrsLoadT & w_SpiRxLoad_4) rExtHAdrs[7:0] <= rSpiRxSft; // LowB In
else rExtHAdrs <= rExtHAdrs; // Hold
end


ホームへ戻る