Zynq AXI总线

2024-06-21 13:18
文章标签 总线 zynq axi

本文主要是介绍Zynq AXI总线,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

S02_CH12_ AXI_Lite 总线详解 - 米联客 - 博客园

12.1前言

ZYNQ拥有ARM+FPGA这个神奇的架构,那么ARM和FPGA究竟是如何进行通信的呢?本章通过剖析AXI总线源码,来一探其中的秘密。

12.2 AXI总线与ZYNQ的关系

AXI(Advanced eXtensible Interface)本是由ARM公司提出的一种总线协议,Xilinx从6系列的FPGA开始对AXI总线提供支持,此时AXI已经发展到了AXI4这个版本,所以当你用到Xilinx的软件的时候看到的都是“AIX4”的IP,如Vivado打包一个AXI IP的时候,看到的都是Create a new AXI4 peripheral。

到了ZYNQ就更不必说了,AXI总线更是应用广泛,双击查看ZYNQ的IP核的内部配置,随处可见AXI的身影。

12.3 AXI总线和AXI接口以及AXI协议

总线、接口和协议,这三个词常常被联系在一起,但是我们心里要明白他们的区别。

总线是一组传输通道,是各种逻辑器件构成的传输数据的通道,一般由由数据线、地址线、控制线等构成。接口是一种连接标准,又常常被称之为物理接口。

协议就是传输数据的规则。

12.3.1 AXI总线概述

在ZYNQ中有支持三种AXI总线,拥有三种AXI接口,当然用的都是AXI协议。其中三种AXI总线分别为:

AXI4:(For high-performance memory-mapped requirements.)主要面向高性能地址映射通信的需求,是面向地址映射的接口,允许最大256轮的数据突发传输;

AXI4-Lite:(For simple, low-throughput memory-mapped communication )是一个轻量级的地址映射单次传输接口,占用很少的逻辑单元。

AXI4-Stream:(For high-speed streaming data.)面向高速流数据传输;去掉了地址项,允许无限制的数据突发传输规模。

首先说AXI4总线和AXI4-Lite总线具有相同的组成部分:

(1)读地址通道,包含ARVALID, ARADDR, ARREADY信号;

(2)读数据通道,包含RVALID, RDATA, RREADY, RRESP信号;

(3)写地址通道,包含AWVALID,AWADDR, AWREADY信号;

(4)写数据通道,包含WVALID, WDATA,WSTRB, WREADY信号;

(5)写应答通道,包含BVALID, BRESP, BREADY信号;

(6)系统通道,包含:ACLK,ARESETN信号。

AXI4总线和AXI4-Lite总线的信号也有他的命名特点:

读地址信号都是以AR开头(A:address;R:read)

写地址信号都是以AW开头(A:address;W:write)

读数据信号都是以R开头(R:read)

写数据信号都是以W开头(W:write)

应答型号都是以B开头(B:back(answer back))

了解到总线的组成部分以及命名特点,那么在后续的实验中您将逐渐看到他们的身影。每个信号的作用暂停不表,放在后面一一介绍。

而AXI4-Stream总线的组成有:

(1)ACLK信号:总线时钟,上升沿有效;

(2)ARESETN信号:总线复位,低电平有效

(3)TREADY信号:从机告诉主机做好传输准备;

(4)TDATA信号:数据,可选宽度32,64,128,256bit

(5)TSTRB信号:每一bit对应TDATA的一个有效字节,宽度为TDATA/8

(6)TLAST信号:主机告诉从机该次传输为突发传输的结尾;

(7)TVALID信号:主机告诉从机数据本次传输有效;

(8)TUSER信号 :用户定义信号,宽度为128bit。

对于AXI4-Stream总线命名而言,除了总线时钟和总线复位,其他的信号线都是以T字母开头,后面跟上一个有意义的单词,看清这一点后,能帮助读者记忆每个信号线的意义。如TVALID = T+单词Valid(有效),那么读者就应该立刻反应该信号的作用。每个信号的具体作用,在后面分析源码时再做分析

12.3.2 AXI接口介绍

三种AXI接口分别是:

AXI-GP接口(4个):是通用的AXI接口,包括两个32位主设备接口和两个32位从设备接口,用过改接口可以访问PS中的片内外设。

AXI-HP接口(4个):是高性能/带宽的标准的接口,PL模块作为主设备连接(从下图中箭头可以看出)。主要用于PL访问PS上的存储器(DDR和On-Chip RAM)

AXI-ACP接口(1个):是ARM多核架构下定义的一种接口,中文翻译为加速器一致性端口,用来管理DMA之类的不带缓存的AXI外设,PS端是Slave接口。

我们可以双击查看ZYNQ的IP核的内部配置,就能发现上述的三种接口,图中已用红色方框标记出来,我们可以清楚的看出接口连接与总线的走向:

wps63CB.tmp

12.3.3 AXI协议概述

讲到协议不可能说是撇开总线单讲协议,因为协议的制定也是要建立在总线构成之上的。虽然说AXI4,AXI4-Lite,AXI4-Stream都是AXI4协议,但是各自细节上还是不同的。

总的来说,AXI总线协议的两端可以分为分为主(master)、从(slave)两端,他们之间一般需要通过一个AXI Interconnect相连接,作用是提供将一个或多个AXI主设备连接到一个或多个AXI从设备的一种交换机制。当我们添加了zynq以及带AXI的IP后再进行自动连线时vivado会自动帮我们添加上这个IP,大家应该是不陌生了。

AXI Interconnect的主要作用是,当存在多个主机以及从机器时,AXI Interconnect负责将它们联系并管理起来。由于AXI支持乱序发送,乱序发送需要主机的ID信号支撑,而不同的主机发送的ID可能相同,而AXI Interconnect解决了这一问题,他会对不同主机的ID信号进行处理让ID变得唯一。

wps63CC.tmp

AXI协议将读地址通道,读数据通道,写地址通道,写数据通道,写响应通道分开,各自通道都有自己的握手协议。每个通道互不干扰却又彼此依赖。这也是AXI高效的原因之一。

12.3.4  AXI协议之握手协议

AXI4所采用的是一种READY,VALID握手通信机制,简单来说主从双方进行数据通信前,有一个握手的过程。传输源产生VLAID信号来指明何时数据或控制信息有效。而目地源产生READY信号来指明已经准备好接受数据或控制信息。传输发生在VALID和READY信号同时为高的时候。VALID和READY信号的出现有三种关系。

(1) VALID先变高READY后变高。时序图如下:

wps63CD.tmp

在箭头处信息传输发生。

(2) READY先变高VALID后变高。时序图如下:

wps63CE.tmp

同样在箭头处信息传输发生。

(3) VALID和READY信号同时变高。时序图如下:

wps63DF.tmp

在这种情况下,信息传输立马发生,如图箭头处指明信息传输发生。

需要强调的是,AXI的五个通道,每个通道都有握手机制,接下来我们就来分析一下AXI-Lite的源码来更深入的了解AXI机制。

12.3.5 突发式读写

1、突发式读的时序图如下:

wps63E0.tmp

当地址出现在地址总线后,传输的数据将出现在读数据通道上。设备保持VALID为低直到读数据有效。为了表明一次突发式读写的完成,设备用RLAST信号来表示最后一个被传输的数据。

2、 突发式写时序图如下:

wps63E1.tmp

这一过程的开始时,主机发送地址和控制信息到写地址通道中,然后主机发送每一个写数据到写数据通道中。当主机发送最后一个数据时,WLAST信号就变为高。当设备接收完所有数据之后他将一个写响应发送回主机来表明写事务完成。

12.4 AXI4-Lite详解

12.4.1 AXI4-Lite源码查看

Step1:要看到AXI-Lite的源码,我们先要自定义一个AXI-Lite的IP,新建工程之后,选择,菜单栏->Tools->Creat and Package IP:

wps63F2.tmp

Step2:选择Next

wps63F3.tmp

Step3:选择Create AXI4 Peripheral,然后Next:

wps6403.tmp

Step4:默认,选择Next

wps6404.tmp

Step5:注意这里接口类型选择Lite,选择Next:

wps6405.tmp

Step6:选择Edit IP,点击Finish:

wps6416.tmp

Step7:此后,Vivado会新建一个工程,专门编辑该IP,通过该工程,我们就可以看到Vivado为我们生成的AXI-Lite的操作源码:

wps6417.tmp

12.4.2 AXI-Lite 源码分析

当打开顶层文件的时,映入眼帘的是一堆AXI的信号,这些信号是否似曾相识?

input wire  s00_axi_aclk,

input wire  s00_axi_aresetn,

input wire [C_S00_AXI_ADDR_WIDTH-1 : 0] s00_axi_awaddr,

input wire [2 : 0] s00_axi_awprot,

input wire  s00_axi_awvalid,

output wire  s00_axi_awready,

input wire [C_S00_AXI_DATA_WIDTH-1 : 0] s00_axi_wdata,

input wire [(C_S00_AXI_DATA_WIDTH/8)-1 : 0] s00_axi_wstrb,

input wire  s00_axi_wvalid,

output wire  s00_axi_wready,

output wire [1 : 0] s00_axi_bresp,

output wire  s00_axi_bvalid,

input wire  s00_axi_bready,

input wire [C_S00_AXI_ADDR_WIDTH-1 : 0] s00_axi_araddr,

input wire [2 : 0] s00_axi_arprot,

input wire  s00_axi_arvalid,

output wire  s00_axi_arready,

output wire [C_S00_AXI_DATA_WIDTH-1 : 0] s00_axi_rdata,

output wire [1 : 0] s00_axi_rresp,

output wire  s00_axi_rvalid,

input wire  s00_axi_rready

没错笔者曾在《AXI总线概述》这节中提到了他们,这次通过源码分析再次隆重介绍它们。

地址通道

数据通道

ARVALID

读地址有效。此信号表明该信道此时能有效读出地址和控制信息

RVALID

读数据有效。此信号表明该信道此时能有效读出数据

ARADDR

读地址

RDATA

读数据

ARREADY

读地址准备好了。该信号指示从器件准备好接受一个地址和相关联的控制信号

RREADY

读数据准备好了。该信号指示从器件准备好接收数据

ARPROT

保护类型。这个信号表示该事务的特权和安全级别,并确定是否该事务是一个数据存取或指令的访问

RRESP

读取响应。这个信号表明读事务处理的状态。

地址通道

数据通道

应答通道

AWVALID

写地址有效。这个信号表示该主信令有效的写地址和控制信息。

WVALID

写有效。这个信号表示有效的写数据和选通信号都可用。

BVALID

写响应有效。此信号表明写命令的有效写入响应。

AWADDR

写地址

WDATA

写数据

BREADY

响应准备。该信号指示在主主机可以接受一个响应信号

AWREADY

写地址准备好了。该信号指示从器件准备好接受一个地址和相关联的控制信号

WSTRB

写选通。这个信号表明该字节通道持有效数据。每一bit对应WDATA一个字节

BRESP

写响应。这个信号表示写事务处理的状态。

AWPROT

写通道保护类型。这个信号表示该事务的特权和安全级别,并确定是否该事务是一个数据存取或指令的访问

WREADY

写准备好了。该信号指示从器件可以接受写数据。


我们先来看一段WDATA相关的代码:Vivado为我们生成的AXI-Lite的操作源码,是一个例子,我只需要读懂他,然后稍加修改,就可以为我们所用。

always @( posedge S_AXI_ACLK )

begin

  if ( S_AXI_ARESETN == 1'b0 )

    begin

      slv_reg0 <= 0;

      slv_reg1 <= 0;

      slv_reg2 <= 0;

      slv_reg3 <= 0;

    end

  else begin

    if (slv_reg_wren)

      begin

        case ( axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] )

          2'h0:

            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )

              if ( S_AXI_WSTRB[byte_index] == 1 ) begin

                // Respective byte enables are asserted as per write strobes

                // Slave register 0

                slv_reg0[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];

              end  

          2'h1:

            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )

              if ( S_AXI_WSTRB[byte_index] == 1 ) begin

                // Respective byte enables are asserted as per write strobes

                // Slave register 1

                slv_reg1[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];

              end  

          2'h2:

            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )

              if ( S_AXI_WSTRB[byte_index] == 1 ) begin

                // Respective byte enables are asserted as per write strobes

                // Slave register 2

                slv_reg2[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];

              end  

          2'h3:

            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )

              if ( S_AXI_WSTRB[byte_index] == 1 ) begin

                // Respective byte enables are asserted as per write strobes

                // Slave register 3

                slv_reg3[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];

              end  

          default : begin

                      slv_reg0 <= slv_reg0;

                      slv_reg1 <= slv_reg1;

                      slv_reg2 <= slv_reg2;

                      slv_reg3 <= slv_reg3;

                    end

        endcase

      end

  end

end   

这段程序的作用是,当PS那边向AXI4-Lite总线写数据时,PS这边负责将数据接收到寄存器slv_reg。而slv_reg寄存器有0~3共4个。至于赋值给哪一个由

axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB]决定,根据宏定义其实就是由axi_awaddr[3:2] (写地址中不仅包含地址,而且包含了控制位,这里的[3:2]就是控制位)决定赋值给哪个slv_reg。

PS调用写函数时,如果不做地址偏移的话,axi_awaddr[3:2]的值默认是为0的,举个例子,如果我们自定义的IP的地址被映射为0x43C00000,那么我们Xil_Out32(0x43C00000,Value)写的就是slv_reg0的值。如果地址偏移4位,如

Xil_Out32(0x43C00000 + 4,Value) 写的就是slv_reg1的值,依次类推。

分析时只关注slv_reg0(其他结构上也是一模一样的):

for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )

  if ( S_AXI_WSTRB[byte_index] == 1 ) begin

slv_reg0[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];

  end

其中,C_S_AXI_DATA_WIDTH的宏定义的值为32,也就是数据位宽,S_AXI_WSTRB就是写选通信号,S_AXI_WDATA就是写数据信号。

存在于for循环中的最关键的一句:

slv_reg0[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];

当byte_index = 0的时候这句话就等价于:

slv_reg0[7:0] <= S_AXI_WDATA[7:0];

当byte_index = 1的时候这句话就等价于:

slv_reg0[15:8] <= S_AXI_WDATA[15:8];

当byte_index = 2的时候这句话就等价于:

slv_reg0[23:16] <= S_AXI_WDATA[23:16];

当byte_index = 3的时候这句话就等价于:

slv_reg0[31:24] <= S_AXI_WDATA[31:24];

也就是说,只有当写选通信号为1时,它所对应S_AXI_WDATA的字节才会被读取。

读懂了这段话之后,我们就知道了,如果我们想得到PS写到总线上的数据,我们只需要读取slv_reg0的值即可。

那如果,我们想写数据到总线让PS读取该数据,我们该怎么做呢?我们继续来看有关RADTA读数据代码:

// Output register or memory read data

always @( posedge S_AXI_ACLK )

begin

  if ( S_AXI_ARESETN == 1'b0 )

    begin

      axi_rdata  <= 0;

    end

  else

    begin    

      // When there is a valid read address (S_AXI_ARVALID) with

      // acceptance of read address by the slave (axi_arready),

      // output the read dada

      if (slv_reg_rden)

        begin

          axi_rdata <= reg_data_out;     // register read data

        end   

    end

end

观察可知,当PS读取数据时,程序会把reg_data_out复制给axi_rdata(RADTA读数据)。我们继续追踪reg_data_out:

always @(*)

begin

      // Address decoding for reading registers

      case ( axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] )

        2'h0   : reg_data_out <= slv_reg0;

        2'h1   : reg_data_out <= slv_reg1;

        2'h2   : reg_data_out <= slv_reg2;

        2'h3   : reg_data_out <= slv_reg3;

        default : reg_data_out <= 0;

      endcase

end

和前面分析的一样此时通过判断axi_awaddr[3:2]的值来判断将那个值给reg_data_out上,同样当PS调用读取函数时,这里axi_awaddr[3:2]默认是0,所以我们只需要把slv_reg0替换成我们自己数据,就可以让PS通过总线读到我们提供的数据。

这里可能有的读者会问了,slv_reg0不是总线写过来的数据吗?因为笔者说过这个程序是Vivado为我们提供的例子,它这么做无非是想验证我写出去的值和我读进入的值相等。但是他怎么写确实会对初看代码的人造成困扰。

最后笔者提出一个问题,为什么写通道要比读通道多了一列应答通道,这是为什么呢?

首先,你要知道这个应答信号是干什么用的?

               

wps6427.tmp

写应答,主要是回复主机你这个写过程是没有问题的,那读为什么不需要这个过程呢?

               

wps6428.tmp

这时因为主机在读取数据时,从机可以直接通过读数据通道给主机反馈信息,因此就没有必要再来开辟一个单独的应答通道了。

小结:

如果我们想读AXI4_Lite总线上的数据时,只需关注slv_reg的数据,我们可自行添加一段代码,如:

reg [11:0]rlcd_rgb;

    always @( posedge S_AXI_ACLK )

            begin

              if ( S_AXI_ARESETN == 1'b0 )

                begin

                    rlcd_rgb  <= 12'd0;

                end

              else

                begin

                    rlcd_rgb <= slv_reg0[11:0];

                end

            end  

    assign lcd_rgb = rlcd_rgb;

如果我们想对AXI4_Lite信号写数据时,我们只需修改对reg_data_out的赋值,如:

//写总线测试修改!!!!!!!!!

        wire[31:0]wlcd_xy;// = {10'd0,lcd_xy};

        assign wlcd_xy = {10'd0,lcd_xy};

        assign slv_reg_rden = axi_arready & S_AXI_ARVALID & ~axi_rvalid;

        always @(*)

        begin

              // Address decoding for reading registers

              case ( axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] )

                2'h0   : reg_data_out <= wlcd_xy;//slv_reg0;   

                2'h1   : reg_data_out <= slv_reg1;

                2'h2   : reg_data_out <= slv_reg2;

                2'h3   : reg_data_out <= slv_reg3;

                default : reg_data_out <= 0;

              endcase

        end

最后强调下如果我们自定义的IP的地址被映射为0x43C00000,那么我们Xil_Out32(0x43C00000,Value)写的就是slv_reg0的值。如果地址偏移4位,如

Xil_Out32(0x43C00000 + 4,Value) 写的就是slv_reg1的值,依次类推。

目前这里只有4个寄存器,那是因为之前选择的是4个,其实我们可以定义的更多:

                              

wps6439.tmp

在ps的头文件里可以看到我们自定义的IP的地址是有个范围的

#define XPAR_MYIPFREQUENCY_0_S00_AXI_BASEADDR 0x43C00000

#define XPAR_MYIPFREQUENCY_0_S00_AXI_HIGHADDR 0x43C0FFFF

理论上只要基地址 + 偏移量不要超过HIGHADDR即可。

12.5 观察AXI4-Lite总线信号

在第十章,我们封装了一个AXI_Lite的GPIO,通过本章的分析,我们在第十章工程的基础上通过添加一个ila核的方式,来具体看看AXI_Lite总线的信号。

Step1:做好第十章工程的备份,然后直接打开第十章的工程。

Step2:单击IP icon 

wps643A.tmp

 添加 ila CORE

                                   

wps643B.tmp

Step3:双击打开ILA CORE

                              

wps644C.tmp

Step4:双击打开ILA CORE

General Options设置如下

               

wps644D.tmp

Probe_Ports设置如下,之后单击OK

               

wps644E.tmp

Step5:连接Probe0到GPIO_LED。

Step6:连接CLK接口到FCLK_CLK0接口

Step7:选中Processing_System7_0_axi_periph和GPIO_LITE_ML_0之间的S_AXI总线。

Step8:右击选择Mark Debug

               

wps645E.tmp

Step9:接下来依然是,右键单击Block文件,文件选择Generate the Output Products。

Step10:继续右键单击Block文件,选择Create a HDL wrapper,根据Block文件内容产生一个HDL 的顶层文件,并选择让vivado自动完成。

Setp11:单击Run Synthesis,如果有 Save 对话框弹出选择保存。

Setp12:综合结束后选择Synthesized Design option单击 OK。

Step13:在如下对话框中找到Unassigned debug nets(如果对话框没有出现选择 菜单->Window > Debug)

                              

wps645F.tmp

Step14:右击 Unassigned Debug Nets 选择Set up Debug… 之后单击 Next

Step15:删除红色错误的信号然后单击Next 到结束

               

wps6460.tmp

Step16:生成Bit文件。

12.6 加载到SDK

Step1:导出硬件。

Step2:右击工程,选择Debug as ->Debug configuration。

Step3:选中system Debugger,双击创建一个系统调试。

               

wps6471.tmp

Step4:设置系统调试。

               

wps6472.tmp

Step5:回到VIVADO单击Open Target->Auto Connect

                                             

wps6473.tmp

Step6:加载完成后的界面

               

wps6483.tmp

Step7:选择菜单->window->Debugprobes 选择AXI_WVALID和AXI_AWVALID做为触发信号

               

wps6484.tmp

Step8:设置触发条件为1

               

wps6485.tmp

Step9:设置触发位置为512

                                             

wps6496.tmp

Step10:单击箭头所指向启动触发

                                        

wps6497.tmp

Step11:进入等待触发状态

               

wps6498.tmp

Step12:单击运行

wps64A9.tmp

后VIVADO  HW_ILA2 窗口采集到波形输出,可以看到AXI总线的工作时序。

               

wps64AA.tmp

Step13:HW_ILA1 窗口采集到的数据是GPIO_LED的值为0x02,同时可观察到开发板上的LED2亮起。

               

wps64AB.tmp

12.7 本章小结

通过本章的学习,我们首先得认识到总线和接口以及协议的区别,其次通过分析AXI4-Lite,AXI4-Stream,AXI4总线的从机代码,对AXI协议有一定的认识,那么在后面学习AXI的一些IP时就不会有恐惧的心理。

最后,我们再理一理AXI总线和AXI接口的关系。在ZYNQ中,支持AXI4-Lite,AXI4和AXI4-Stream三种总线协议,这前面已经说过了,要注意的是PS与PL之间的接口(AXI-GP接口,AXI-HP接口以及AXI-ACP接口)却只支持AXI-Lite和AXI协议这两种总线协议。也就是说PL这边的AXI-Stream的接口是不能直接与PS对接的,需要经过AXI4或者AXI4-Lite的转换。比如后面将用到的VDMA IP ,它就实现了在PL内部AXI4到AXI-Stream的转换,VDMA利用的接口就是AXI-HP接口。

这篇关于Zynq AXI总线的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1081328

相关文章

电子电气架构---私有总线通信和诊断规则

电子电气架构—私有总线通信和诊断规则 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明自己,无利益不试图说服别人,是精神上的节能减排。 无人问津也好,技不如人也罢,你都要试着安静下来,去做自己该做的事.而不是让内心的烦躁、

I2C总线协议(AT24C02C)

本文章是基于TQ2440开发板上的AT24C02C 一, I2C简介       IIC即Inter-Integrated Circut(集成电路总线),有飞利浦在八十年代实际出来. I2C是一种多向控制总线,就是同一个总线下可以连接多个芯片,同时每个芯片都可以作为实时数据传输的控制源. 二. 硬件结构       I2C串行总线一般有两根信号线,一根是双向的数据总线SDA, 一根是

【STM32】CAN总线基础入门

CAN总线基础入门 一、CAN简介二、主流通信协议对比三、CAN物理层1、CAN硬件电路2、CAN电平标准3、CAN收发器 – TJA1050(高速CAN)4、CAN物理层特性 四、帧格式1、CAN总线帧格式2、数据帧3、数据帧各部分用途简介4、数据帧的发展历史5、遥控帧6、错误帧7、过载帧8、帧间隔9、位填充10、波形实例 五、位同步1、接收方数据采样2、接收方数据采样遇到的问题3、位时序

ZYNQ LWIP (RAW API) UDP函数学习

1 RAW API接口 RAW API是基于回调函数实现的API接口,它是很底层的API接口,这需要开发者对LwIP有较深的了解才能很好使用它,RAW API的核心就是对控制块的处理,因为对于报文数据的处理、注册回调函数等都是需要开发者自己去实现,都是比较麻烦的,但是有一个优点,那就是处理数据效率高。 2 RAW API的UDP函数说明 udp_new()–新建控制块 在使用UDP协议进行通

ZYNQ MPSOC FPGA 仿真 教程

1. **FPGA与MPSOC**: FPGA (Field Programmable Gate Array) 是一种可以通过编程配置的集成电路,适用于各种应用和功能。MPSOC (Multi-Processor System on Chip) 是集成了多个处理器(通常是微处理器)的系统芯片,用于处理复杂的应用,如图像处理、网络通信等。 2. **仿真与分析**:    - **仿

V90总线伺服报800F错误

1、博途PLC工艺对象位置轴轴控功能块 博途PLC工艺对象位置轴轴控功能块(完整SCL代码)-CSDN博客文章浏览阅读423次。S7-1200PLC脉冲轴位置轴位置控制功能块S7-1200PLC脉冲轴位置轴位置控制功能块优化(完整SCL源代码)_s71200 脉冲轴-CSDN博客文章浏览阅读341次。该博客详细介绍了如何优化S7-1200 PLC的位置控制功能块,使得在轴激活限位时无需复位即可直

EventBus-Vue事件总线解析与使用指南

前言         在Vue.js中,组件通信是开发过程中非常场景的需求。根据不同的场景和需求,Vue提供了多种组件通信方式。比如父子组件通信、兄弟组件通信、跨代组件通信等。当应用程序中两个组件或者说页面之间没有引入和被引入的关系的时,或者说他们之间嵌套的结果复杂的时候,我们可以考虑如何传递数据呢?         其中适用的通信方式有 Vuex、provide 和 inject、Event

计算机总线及外部总线汇总

参考视频教程:    **编程必备基础 计算机组成原理+操作系统+计算机网络  ** 计算机总线 名称 传输速率(比特/字节) 推出年分 I²C 3.4 Mbit/s 425 kB/s 1992 Apple II series (incl. Apple IIGS) 8-bit/1 MHz 8 Mbit/s 1 MB/s[[31]](https://zh.wikip

《PCI Express体系结构导读》随记 —— 第II篇 第7章 PCIe总线的数据链路层与物理层(7)

接前一篇文章:《PCI Express体系结构导读》随记 —— 第II篇 第7章 PCIe总线的数据链路层与物理层(6) 7.1 数据链路层的组成结构 7.1.1 数据链路层的状态 3. DL_Active状态 当数据链路层处于DL_Active状态时,PCIe链路可以正常工作。此时数据链路层可以从事务层和物理层正常接收和发送TLP、并处理DLLP,此时数据链路

思考(六十九):一种基于消息总线的功能可插拔的服务器架构

架构图 +--------------------+ +----------------+ +----------------+| | | NODE 1 | | NODE 2 || TOPIC ROUTE INFO |