• FPGA实现Avalon-MM接口通信


            在Avalon总线协议(一)Avalon总线协议(二)中大概了解Avalon总线的几种类型,目前比较常用到的就是Avalon-MM接口了,虽然在概念中有那么多的属性,但是具体使用起来还是非常简单的。

    一、Avalon-MM

            前面提到过Avalon总线常用于 用户自定义的逻辑 与 NIOS Ⅱ处理器 之间进行通信,再通俗一点的理解就是硬件(Verilog代码)和软件(Nios Ⅱ处理器)进行数据交互。Nios Ⅱ作为主端口(Master),而Verilog代码模块实现了从端口(Slave),比如在Verilog代码中写了一个计数器,而Nios想要知道这个计数器的值,那么就可以在Verilog代码中定义一个寄存器,该寄存器具有与之相对应的地址,Nios Ⅱ可以根据地址对这个寄存器的值进行读取或者写入,这就是Avalon-MM协议。

    如图,Verilog代码中定义了三个寄存器,分别是REG1、REG2、REG3,偏移量分别是OFFSET1、OFFSET2、OFFSET3;

    当这一部分Verilog代码作为自定义组件加入到NIOS中并进行编译后,会自动产生BASE;

    这时候寄存器的地址和偏移量就都有了,那么NIOS就可以对寄存器中的数据进行读写,从而实现通信!

    二、NIOS常用函数

    在NIOS中有一些已经定义好的函数方便去对数据进行操作

    最常用的肯定是IORD()、IOWR()以及对PIO操作的IORD_ALTERA_AVALON_PIO_DATA()、IOWR_ALTERA_AVALON_PIO_DATA()

    其实都一样>-<,IORD_ALTERA_AVALON_PIO_DATA()还是调用的IORD()

    1. IORD(BASE, OFFSET)
    2. //BASE为寄存器的基地址,OFFSET为寄存器的偏移量
    3. //从基地址为BASE的设备中读取寄存器中偏移量为OFFSET的单元里面的值
    4. IOWR(BASE, OFFSET, DATA)
    5. //BASE为寄存器的基地址,OFFSET为寄存器的偏移量,DATA为要写入的数据
    6. //向基地址为BASE的设备偏移量为OFFSET寄存器中写入数据DATA
    7. IORD_ALTERA_AVALON_PIO_DATA(BASE)
    8. //BASE为寄存器的基地址
    9. //向基地址为BASE的设备中读取数
    10. IOWR_ALTERA_AVALON_PIO_DATA(BASE, DATA)
    11. //BASE为寄存器的基地址,DATA为要写入的数据
    12. //向基地址为BASE的设备中写入数据DATA

    其他NIOS函数可以参考:NIOS常用函数详解-CSDN博客

    三、Avalon-MM实现

    其实已经在前面的文章中实现过了,只不过没有较为详细的解释:

    SOPC之NIOS Ⅱ实现电机转速PID控制_STATEABC的博客-CSDN博客

    就用其中的电机PWM控制模块作为例子

    3.1 硬件部分

    1. module MOTOR_PWM(
    2. input clk,
    3. input reset_n,
    4. //Avalon-MM输入输出
    5. input avalon_cs, // 片选信号,进行数据操作时自动置为1
    6. input [2:0] avalon_address, // 基地址,位宽根据要定义的寄存器个数
    7. input avalon_write, // 写入信号
    8. input [31:0] avalon_writedata, // 写入数据
    9. input avalon_read, // 读取信号
    10. output reg [31:0] avalon_readdata, // 读取数据
    11. input signed [31:0] Speed,
    12. output reg PWM,
    13. output reg IN1,
    14. output reg IN2
    15. );
    16. reg pwm_tem;
    17. reg [31:0] total; // 总时间
    18. reg [31:0] high; // 高位时间
    19. reg [31:0] count; // 计数器
    20. /
    21. // 定义寄存器的偏移量,两种写法都可以
    22. localparam REGISTER_TOTAL_DUR = 0;
    23. `define REGISTER_HIGH_DUR 2'd1
    24. /
    25. // Avalon-MM通信
    26. always @(posedge clock or negedge reset_n)
    27. begin
    28. if (~reset_n)
    29. begin
    30. high <= 0;
    31. total <= 0;
    32. end
    33. // 当片选信号和写入信号有效,反映在软件上就是执行了IOWR()
    34. else if (avalon_cs & avalon_write)
    35. begin
    36. if (avalon_address == REGISTER_TOTAL_DUR) // 当地址等于0,即REGISTER_TOTAL_DUR
    37. total <= avalon_writedata; // avalon_writedata为IOWR()写入的DATA值
    38. else if (avalon_address == `REGISTER_HIGH_DUR)
    39. high <= avalon_writedata;
    40. end
    41. // 当片选信号和读取信号有效,反映在软件上就是执行了IORD()
    42. else if (select_cs & select_read)
    43. begin
    44. if (avalon_address == `REGISTER_TOTAL_DUR) // 当地址等于0,即REGISTER_TOTAL_DUR
    45. select_readdata <= total; // avalon_writedata为IORD()的返回值
    46. else if (avalon_address == `REGISTER_HIGH_DUR)
    47. select_readdata <= high;
    48. end
    49. end
    50. /
    51. // 进行PWM输出
    52. always @(*)
    53. begin
    54. if (Speed>0) begin
    55. {IN1, IN2, PWM} <= {1'b1, 1'b0, pwm_tem};
    56. end
    57. else begin
    58. {IN1, IN2, PWM} <= {1'b1, 1'b0, pwm_tem};
    59. end
    60. end
    61. always @(posedge clock or negedge reset_n)
    62. begin
    63. if (~reset_n)
    64. begin
    65. count <= 1;
    66. end
    67. else if (count >= total)
    68. begin
    69. count <= 1;
    70. end
    71. else
    72. count <= count + 1;
    73. end
    74. always @(posedge clock)
    75. begin
    76. pwm_tem <= (count <= high) ? 1'b1 : 1'b0;
    77. end
    78. endmodule

    将其作为自定义组件加入NIOS系统中并进行编译

    3.2 软件部分

    硬件部分进行全编译后,生成的systm.h文件中会包含其BASE信息

    然后就可以根据BASE和OFFSET进行数据的读取

    1. #include
    2. #include
    3. #include "system.h"
    4. #include "altera_avalon_pio_regs.h" //IOWR_ALTERA_AVALON_PIO_DATA
    5. int main()
    6. {
    7. int high,total;
    8. //写入数据
    9. IOWR(MOTOR_PWM_BASE,0,2000);
    10. IOWR(MOTOR_PWM_BASE,1,1000);
    11. //读取数据
    12. total = IORD(MOTOR_PWM_BASE,0);
    13. high = IORD(MOTOR_PWM_BASE,1);
    14. printf("total= %d\r\n", total);
    15. printf("high = %d\r\n", hight);
    16. return 0;
    17. }

  • 相关阅读:
    [SLAM] 数学基础
    LeetCode111. Minimum Depth of Binary Tree
    $attrs 和 $listeners (vue2&&vue3)
    AdaptFormer学习笔记
    Unity URP入门实战
    【C++进阶】多态
    SocketIo的使用和基于SocketIO的聊天室
    简单的ajax任务:get和post方式提交前端用户输入信息给服务器
    软件测试/测试开发/人工智能丨视觉与图像识别自动化测试
    汽车租贷管理系统简单实现
  • 原文地址:https://blog.csdn.net/STATEABC/article/details/134050656