• FPGA SPI 驱动程序


    1.引言

    驱动程序已经完成很久了,花了2个星期的时间,主要是提升程序运行的效率。最近整理文件的时候又看到了,记录一下。

    2.程序框架分解

    1. module adc7254_Ctrl(
    2. input sys_clk, //system clkc 50M
    3. input reset_n, //reset flag
    4. input iData_a_in, //ADC to fpga
    5. input iData_b_in,
    6. output sclk_out, //to ADC
    7. output cs_out, //to ADC
    8. output sdin, //to ADC
    9. output [11:0] oData_a, //get data
    10. output [11:0] oData_b //get data
    11. );
    12. wire clk_200M; //PLL驱动
    13. AD_PLL AD_PLL_inst(
    14. .inclk0(sys_clk),
    15. .c0(Clk_200M),
    16. .c1(sclk_out)
    17. );
    18. wire En_conv,En_send; //定义ADC发送和接收程序的状态切换时间
    19. adc_test adc_test_inst(
    20. .iRst_n(reset_n),
    21. .iDclk(sclk_out),
    22. .iSend_down(Send_down),
    23. .oAdc_rst_n(adc_rst_n),
    24. .oEn_conv(En_conv),
    25. .oEn_send(En_send)
    26. );
    27. wire Send_down; //ADC指令发送部分
    28. adc_in_send adc_in_send_inst
    29. (
    30. .iClk_200M(Clk_200M),
    31. .iRst_n(adc_rst_n),
    32. .iDcLK(sclk_out),
    33. .iEn_send(En_send),
    34. .oSDATA(sdin),
    35. .oSend_down(Send_down)
    36. );
    37. wire Conv_down;
    38. adc_out_conv adc_out_conv_inst //ADC数据采样部分
    39. (
    40. .iClk_200M ( Clk_200M ),
    41. .iRst_n ( adc_rst_n ),
    42. .iEn_conv ( En_conv ),
    43. .iDcLK ( sclk_out ),
    44. .iData_a_in ( iData_a_in ),
    45. .iData_b_in ( iData_b_in ),
    46. .oData_a ( oData_a ),
    47. .oData_b ( oData_b ),
    48. .oConv_down ( Conv_down )
    49. );
    50. assign cs_out = Conv_down & Send_down; //状态完成
    51. endmodule

    3.子任务分解

    (1)状态控制程序

    其主要是以空状态,写状态,读状态三个状态顺序执行的。

    1. module adc_test(
    2. input iRst_n,
    3. input iDclk,
    4. input iSend_down,
    5. output oAdc_rst_n,
    6. output reg oEn_send,
    7. output reg oEn_conv
    8. );
    9. reg [1:0] state;
    10. reg [5:0] sclk_cnt;
    11. localparam state_IDLE = 2'd0;
    12. localparam state_Write = 2'd1;
    13. localparam state_Read = 2'd3;
    14. assign oAdc_rst_n = (iRst_n & state);
    15. always @(posedge iDclk or negedge iRst_n) begin
    16. if(!iRst_n)begin
    17. sclk_cnt <= 6'd0;
    18. state <= state_IDLE;
    19. oEn_conv = 1'd0;
    20. oEn_send = 1'd0;
    21. end else begin
    22. case(state)
    23. state_IDLE:
    24. begin
    25. if (sclk_cnt > 6'd30 ) begin
    26. sclk_cnt <= 6'd0;
    27. state <= state_Write;
    28. oEn_conv = 1'd0;
    29. oEn_send = 1'd1;
    30. end else begin
    31. sclk_cnt <= sclk_cnt + 1'd1;
    32. state <= state_IDLE;
    33. oEn_conv = 1'd0;
    34. oEn_send = 1'd0;
    35. end
    36. end
    37. state_Write:
    38. begin
    39. if (iSend_down == 1'd1 && sclk_cnt > 6'd30 ) begin
    40. sclk_cnt <= 0;
    41. state <= state_Read;
    42. oEn_conv = 1'd1;
    43. oEn_send = 1'd0;
    44. end else begin
    45. sclk_cnt <= sclk_cnt + 1'd1;
    46. state <= state_Write;
    47. oEn_conv = 1'd0;
    48. oEn_send = 1'd1;
    49. end
    50. end
    51. state_Read:
    52. begin
    53. state <= state_Read;
    54. sclk_cnt <= 1'd0;
    55. oEn_conv = 1'd1;
    56. oEn_send = 1'd0;
    57. end
    58. endcase
    59. end
    60. end
    61. endmodule

    (2)写命令程序部分

    1. module adc_in_send(
    2. input iClk_200M, //200M
    3. input iRst_n,
    4. input iDcLK, //最小T>60ns
    5. input iEn_send,
    6. output oSDATA,
    7. output oSend_down
    8. );
    9. //==================使能接收标志位en==================//
    10. //一旦启动不会突然停止除非复位信号到来
    11. reg en;
    12. reg [5:0] sclk_cnt;
    13. always @(posedge iDcLK or negedge iRst_n ) begin
    14. if (!iRst_n) begin
    15. en <= 1'd0;
    16. sclk_cnt <= 6'd0;
    17. end else if ( iEn_send == 1'd1 && sclk_cnt == 6'd0 ) begin
    18. en <= 1'd1;
    19. sclk_cnt <= 6'd32;
    20. end else if ( sclk_cnt > 6'd1 ) begin
    21. en <= en;
    22. sclk_cnt <= sclk_cnt - 1'd1;
    23. end else if (oSend_down == 1'd1 && sclk_cnt == 6'd1 ) begin
    24. en <= 1'd0;
    25. sclk_cnt <= sclk_cnt - 1'd1;
    26. end else begin
    27. en <= en;
    28. sclk_cnt <= sclk_cnt;
    29. end
    30. end
    31. //==================使能接收标志位en==================//
    32. //==================SDATA输出操作=========================//
    33. reg [15:0]CFR_16bit_data = 16'h8840; //需要写入寄存器中的数据
    34. assign oSDATA = (en > 1'd0) ? ((sclk_cnt > 6'd17) ? CFR_16bit_data[sclk_cnt-6'd17] : 0 ): 0;
    35. //==================SDATA操作=========================//
    36. //==================oSend_down操作======================//
    37. assign oSend_down = (sclk_cnt > 6'd1) ? 0 : 1;
    38. //==================oSend_down操作======================//
    39. endmodule

    (3)读数据程序部分

    1. module adc_out_conv(
    2. input iClk_200M, //200M
    3. input iRst_n,
    4. input iData_a_in,
    5. input iData_b_in,
    6. input iDcLK, //最小T=60ns
    7. input iEn_conv,
    8. output reg [11:0] oData_a,
    9. output reg [11:0] oData_b,
    10. output oConv_down //T>70ns
    11. );
    12. //下降沿接收
    13. //==================使能接收标志位en==================//
    14. //一旦启动不会突然停止除非复位信号到来
    15. reg en;//接收使能标志位
    16. reg [5:0] sclk_cnt;
    17. always @(posedge iDcLK or negedge iRst_n ) begin
    18. if (!iRst_n) begin
    19. en <= 1'd0;
    20. sclk_cnt <= 5'd0;
    21. end else if (iEn_conv == 1'd1 && sclk_cnt == 4'd0) begin
    22. en <= 1'd1;
    23. sclk_cnt <= 6'd17;
    24. end else if (sclk_cnt > 4'd1) begin
    25. en <= en;
    26. sclk_cnt <= sclk_cnt - 1'd1;
    27. end else if (oConv_down == 1'd1 && sclk_cnt == 4'd1)begin
    28. en <= 1'd0;
    29. sclk_cnt <= sclk_cnt - 1'd1;
    30. end else begin
    31. en <= en;
    32. sclk_cnt <= sclk_cnt;
    33. end
    34. end
    35. //==================使能接收标志位en==================//
    36. //==================dclk时钟采样==================//
    37. reg [6:0] dclk;
    38. always@(posedge iClk_200M or negedge iRst_n) begin
    39. if(!iRst_n) begin
    40. dclk <= 7'd0;
    41. end else if(!en) begin
    42. dclk <= 7'd0;
    43. end else begin
    44. dclk <= {dclk[5:0],iDcLK};
    45. end
    46. end
    47. //==================dclk时钟采样==================//
    48. //==================状态切换==================//
    49. reg [1:0] state;
    50. parameter state_IDLE = 2'd0;
    51. parameter state_Read = 2'd1;
    52. parameter state_Write = 2'd2;
    53. always@(posedge iClk_200M or negedge iRst_n) begin
    54. if(!iRst_n ) begin
    55. state <= state_IDLE;
    56. end else if(!en) begin
    57. state <= state_IDLE;
    58. end else if(dclk[1] == 1 & dclk[2] == 0) begin
    59. state <= state_Read;
    60. end else if (dclk[1] == 0 & dclk[2] == 1) begin
    61. state <= state_Write;
    62. end else begin
    63. state <=state;
    64. end
    65. end
    66. //==================状态切换==================//
    67. //==================data串行转并行==================//
    68. reg [2:0] Data_a_in_temp,Data_b_in_temp;//保证7次采样有4次为1
    69. reg [11:0] Data_a_temp,Data_b_temp;
    70. always@(posedge iClk_200M or negedge iRst_n)
    71. begin
    72. if(!iRst_n ) begin
    73. Data_a_temp <= 12'd0;
    74. Data_b_temp <= 12'd0;
    75. Data_a_in_temp <= 3'd0;
    76. Data_b_in_temp <= 3'd0;
    77. end else if(sclk_cnt > 6'd16)begin
    78. Data_a_in_temp <= 3'd0;
    79. Data_b_in_temp <= 3'd0;
    80. Data_a_temp <= 12'd0;
    81. Data_b_temp <= 12'd0;
    82. end else if(sclk_cnt > 6'd3 ) begin
    83. if(state == state_Read && dclk[6] == 0 ) begin
    84. Data_a_in_temp <= Data_a_in_temp + iData_a_in;
    85. Data_b_in_temp <= Data_b_in_temp + iData_b_in;
    86. Data_a_temp <= Data_a_temp;
    87. Data_b_temp <= Data_b_temp;
    88. end else if(state == state_Write && dclk[0]!=dclk[1])begin
    89. Data_a_in_temp <= 3'd0;
    90. Data_b_in_temp <= 3'd0;
    91. Data_a_temp <= {Data_a_temp[10:0],Data_a_in_temp[2]};
    92. Data_b_temp <= {Data_b_temp[10:0],Data_b_in_temp[2]};
    93. end else begin
    94. Data_a_in_temp <= Data_a_in_temp;
    95. Data_b_in_temp <= Data_b_in_temp;
    96. Data_a_temp <= Data_a_temp;
    97. Data_b_temp <= Data_b_temp;
    98. end
    99. end else begin
    100. Data_a_in_temp <= Data_a_in_temp;
    101. Data_b_in_temp <= Data_b_in_temp;
    102. Data_a_temp <= Data_a_temp;
    103. Data_b_temp <= Data_b_temp;
    104. end
    105. end
    106. //==================data串行转并行==================//
    107. //==================oConv_down操作======================//
    108. assign oConv_down = (sclk_cnt > 6'd1) ? 0 : 1;
    109. //==================oConv_down操作======================//
    110. //==================数据按帧输出==================//
    111. always@(posedge iClk_200M or negedge iRst_n)
    112. begin
    113. if(!iRst_n )
    114. begin
    115. oData_a <= 12'd0;
    116. oData_b <= 12'd0;
    117. end
    118. else if( oConv_down == 1'd1)
    119. begin
    120. oData_a <= Data_a_temp;
    121. oData_b <= Data_b_temp;
    122. end
    123. else
    124. begin
    125. oData_a <= oData_a;
    126. oData_b <= oData_b;
    127. end
    128. end
    129. //==================数据按帧输出==================//
    130. endmodule

  • 相关阅读:
    1452. 收藏清单-排序+交叠比较-力扣双百代码
    Redis如何查看KEY的数据类型
    MySQL入门第三天——数据表的约束
    HTML5期末大作业:美妆网页主题网站设计——清新的手工肥皂网站展示(4页)HTML+CSS+JavaScript
    网络编程、广播、组播、数据库sqlite3
    Vue-DPlayer详细使用(包含遇到坑)
    Codeforces Round #620 (Div. 2)ABC
    Docker的基础命令
    【DPDK】谈谈DPDK如何实现bypass内核的原理 其二 DPDK部分的实现
    小程序全局配置文件以及常用配置项
  • 原文地址:https://blog.csdn.net/qq_21835111/article/details/132577229