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()

IORD(BASE, OFFSET)
//BASE为寄存器的基地址,OFFSET为寄存器的偏移量
//从基地址为BASE的设备中读取寄存器中偏移量为OFFSET的单元里面的值

IOWR(BASE, OFFSET, DATA)
//BASE为寄存器的基地址,OFFSET为寄存器的偏移量,DATA为要写入的数据
//向基地址为BASE的设备偏移量为OFFSET寄存器中写入数据DATA

IORD_ALTERA_AVALON_PIO_DATA(BASE)
//BASE为寄存器的基地址
//向基地址为BASE的设备中读取数

IOWR_ALTERA_AVALON_PIO_DATA(BASE, DATA)
//BASE为寄存器的基地址,DATA为要写入的数据
//向基地址为BASE的设备中写入数据DATA

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

三、Avalon-MM实现

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

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

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

3.1 硬件部分

module MOTOR_PWM(
	input						clk,
	input						reset_n,
	//Avalon-MM输入输出
	input						avalon_cs,			// 片选信号,进行数据操作时自动置为1
	input		[2:0]			avalon_address,		// 基地址,位宽根据要定义的寄存器个数
	input						avalon_write,		// 写入信号
	input		[31:0]			avalon_writedata,	// 写入数据
	input						avalon_read,		// 读取信号
	output  reg	[31:0]			avalon_readdata,	// 读取数据
	
	input	signed [31:0]		Speed,
	output	reg					PWM,
	output	reg					IN1,
	output	reg					IN2
);

reg            pwm_tem;
reg     [31:0] total;       // 总时间
reg     [31:0] high;        // 高位时间
reg     [31:0] count;            // 计数器

/
// 定义寄存器的偏移量,两种写法都可以
localparam REGISTER_TOTAL_DUR	= 0;

`define REGISTER_HIGH_DUR      2'd1


/
// Avalon-MM通信
always @(posedge clock or negedge reset_n)
begin
    if (~reset_n)
    begin
        high <= 0;
        total <= 0;
    end
    // 当片选信号和写入信号有效,反映在软件上就是执行了IOWR()
    else if (avalon_cs & avalon_write)
    begin
        if (avalon_address == REGISTER_TOTAL_DUR)			// 当地址等于0,即REGISTER_TOTAL_DUR
            total <= avalon_writedata;						// avalon_writedata为IOWR()写入的DATA值
        else if (avalon_address == `REGISTER_HIGH_DUR)
            high <= avalon_writedata;
    end
    // 当片选信号和读取信号有效,反映在软件上就是执行了IORD()
    else if (select_cs & select_read)
    begin
        if (avalon_address == `REGISTER_TOTAL_DUR)			// 当地址等于0,即REGISTER_TOTAL_DUR
            select_readdata <= total;						// avalon_writedata为IORD()的返回值
        else if (avalon_address == `REGISTER_HIGH_DUR)
            select_readdata <= high;
    end    
end
 
/
// 进行PWM输出
always @(*)
begin
    if (Speed>0) begin
    	{IN1, IN2, PWM} <= {1'b1, 1'b0, pwm_tem};
    end
    else begin
    	{IN1, IN2, PWM} <= {1'b1, 1'b0, pwm_tem};
    end
end
 
always @(posedge clock or negedge reset_n)
begin
    if (~reset_n)
    begin
        count <= 1;
    end
    else if (count >= total)
    begin
        count <= 1;
    end
    else
        count <= count + 1;
end
 
always @(posedge clock)
begin
    pwm_tem <= (count <= high) ? 1'b1 : 1'b0;
end
 
endmodule

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

3.2 软件部分

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

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

#include <stdio.h>
#include <stdlib.h>
#include "system.h"
#include "altera_avalon_pio_regs.h" //IOWR_ALTERA_AVALON_PIO_DATA

int main()
{    
    int high,total;
    //写入数据
    IOWR(MOTOR_PWM_BASE,0,2000);
    IOWR(MOTOR_PWM_BASE,1,1000);
    //读取数据
    total = IORD(MOTOR_PWM_BASE,0);
    high  = IORD(MOTOR_PWM_BASE,1);

    printf("total= %d\r\n", total);
    printf("high = %d\r\n", hight);
   
    return 0;
}

  • 7
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Avalon总线例程是指使用Avalon总线协议进行开发的一套示例代码。Avalon总线是由英特尔(Intel)提出的一种用于硬件模块之间通信的标准接口协议,可以实现模块之间的数据和控制信号传输。Avalon总线例程是基于这个协议而编写的示例程序,用于展示如何在系统中使用Avalon总线进行模块的设计和通信。 Avalon总线例程通常包含了几个关键部分。首先是Avalon总线的初始化和配置。这部分代码会对Avalon总线的参数进行设置,如数据宽度、时钟频率等,以确保各个模块之间的通信正常进行。其次是模块之间的通信代码。通过Avalon总线,模块可以进行数据读写、状态传输等操作。这部分代码会展示如何使用Avalon总线提供的接口函数来实现数据的传递和控制。最后是系统的测试和验证代码。这部分代码会对各个模块的功能进行测试,以确保系统的正常运行。 使用Avalon总线例程可以帮助开发者更容易地理解和掌握Avalon总线协议的使用。通过阅读和运行这些例程,开发者可以学习到Avalon总线的相关知识,了解模块之间通信的基本原理和方法。同时,开发者还可以根据实际需求对这些例程进行修改和扩展,以满足自己的应用要求。 总之,Avalon总线例程是一种有助于理解和应用Avalon总线协议的示例程序。通过学习和运行这些例程,开发者可以更好地掌握Avalon总线的使用方法,从而设计和开发出高效可靠的硬件系统。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值