microblaze其它例程 - minichao9901/TangNano-20k-Zynq-7020 GitHub Wiki

1. microblaze,开启Cache后,可以在AXI总线上挂一个Block RAM。是可以work的。

2. 去掉ILMB/DLMB,利用AXI blockram,似乎是可以工作的。需要注意:

1) Microblaze的M_AXI_IP要引出来,否则无法取指令

2) AXI Blockram的Size要取的足够大,要能容纳下elf文件内容

3) 需要设置ld文件的Memory地址。如果嫌麻烦,可以删掉工程后,重新生成工程,这样它会自动寻找AXI总线上的RAM地址,并将其设置为ld文件memory的地址。

4) 编译,运行,可以work。但是运行效果存在问题:1)printf不能工作;2)速度非常慢,本来LED灯应该按照500ms间隔进行闪烁,实际的效果感觉有3-4s的样子。

3. zynq与mb一起工作,其中zynq给mb提供100MHz时钟和复位

a. 整个block的设计

image

image

注意,只能用一个AXI Interconnect,地址分配才能正确。最初考虑将microblaze的I/D Cache用一个单独的AXI SmartConnect连接到BlockRam,发现地址不能自动分配,于是放弃了。 实际操作中,只需要把zynq,microblaze,uartlite, axi_gpio拿出来,让vivado自动连线即可。vivado会提示,microblaze使用什么时钟?选择来自zynq即可。

b. 创建工程

  • 注意选择Processer。我们分别对mb和zynq各自创建了一个工程,都测试uart和gpio功能。
  • 创建工程的时候,可以选择hello world例程模板。之后,删除helloworld.c文件中的内容,并贴上我们自己的程序。 image

image

c. 修改

  • 对于mb,直接运行,即可打印,并LED灯轮流闪烁。
  • 对于zynq,它的串口retarget默认是使用的ps端的串口,而不是uartlite。为了使用uartlite作为串口的retarget,通过按F3追溯xil_printf函数,我们发现,需要修改outbyte函数,这个函数位于outbyte.c文件中。修改方法如下: 原始outbyte.c,可见它用的是coresight的东西
#include "xparameters.h"
#include "xcoresightpsdcc.h"

#ifdef __cplusplus
extern "C" {
#endif
void outbyte(char c); 

#ifdef __cplusplus
}
#endif 

void outbyte(char c) {
	 XCoresightPs_DccSendByte(STDOUT_BASEADDRESS, c);
}

修改后outbyte.c

#include "xparameters.h"
#include "xuartlite_l.h"

#ifdef __cplusplus
extern "C" {
#endif
void outbyte(char c); 

#ifdef __cplusplus
}
#endif 

void outbyte(char c) {
	 XUartLite_SendByte(XPAR_AXI_UARTLITE_0_BASEADDR, c);  //注意,这里必须手动指定XPAR_AXI_UARTLITE_0_BASEADDR
}

d. 运行效果

分别运行mb程序和zynq程序,可见都可以工作。 image

e. 也可以让2个处理器同时运行,各自运行各自的

  • microblaze闪烁LED1/2,并打印
  • zynq闪烁LED3/4,并打印
  • mb与zynq通过AXI BlockRam交互数据(前4个字节),其中mb是生产者,zynq是消费者。同时,我们把AXI BlockRam的第10个字节用作锁变量,用来创造临界区
  • 效果非常棒!

microblaze的loop

    int v=0;
    while (1) {
    	xil_printf("Microblaze Print Now!\r\n");

        // 依次翻转四个GPIO引脚
        XGpio_DiscreteWrite(&gpio, LED_CHANNEL, 0b0001);
        usleep(500000); // 等待500毫秒

        XGpio_DiscreteWrite(&gpio, LED_CHANNEL, 0b0010);
        usleep(500000);

        //produce process
        if(Xil_In8(XPAR_MB_CACHE_AXI_BRAM_CTRL_0_S_AXI_BASEADDR+10)==0){  //if lock=0
            Xil_Out8(XPAR_MB_CACHE_AXI_BRAM_CTRL_0_S_AXI_BASEADDR+10, 1); //set lock=1

            Xil_Out8(XPAR_MB_CACHE_AXI_BRAM_CTRL_0_S_AXI_BASEADDR, v);
            Xil_Out8(XPAR_MB_CACHE_AXI_BRAM_CTRL_0_S_AXI_BASEADDR+1, v+1);
            Xil_Out8(XPAR_MB_CACHE_AXI_BRAM_CTRL_0_S_AXI_BASEADDR+2, v+2);
            Xil_Out8(XPAR_MB_CACHE_AXI_BRAM_CTRL_0_S_AXI_BASEADDR+3, v+3);
        }
        v++;


//        XGpio_DiscreteWrite(&gpio, LED_CHANNEL, 0b0100);
//        usleep(500000);
//
//        XGpio_DiscreteWrite(&gpio, LED_CHANNEL, 0b1000);
//        usleep(500000);
    }

zynq的loop

    while (1) {
//        // 依次翻转四个GPIO引脚
//        XGpio_DiscreteWrite(&gpio, LED_CHANNEL, 0b0001);
//        usleep(500000); // 等待500毫秒
//
//        XGpio_DiscreteWrite(&gpio, LED_CHANNEL, 0b0010);
//        usleep(500000);

    	xil_printf("Zynq Print Now!\r\n");

        XGpio_DiscreteWrite(&gpio, LED_CHANNEL, 0b0100);
        usleep(500000);

        XGpio_DiscreteWrite(&gpio, LED_CHANNEL, 0b1000);
        usleep(500000);

        //consume process
        if(Xil_In8(XPAR_MB_CACHE_AXI_BRAM_CTRL_0_S_AXI_BASEADDR+10)==1){  //if lock=1
            xil_printf("%d\r\n", Xil_In8(XPAR_MB_CACHE_AXI_BRAM_CTRL_0_S_AXI_BASEADDR));
            xil_printf("%d\r\n", Xil_In8(XPAR_MB_CACHE_AXI_BRAM_CTRL_0_S_AXI_BASEADDR+1));
            xil_printf("%d\r\n", Xil_In8(XPAR_MB_CACHE_AXI_BRAM_CTRL_0_S_AXI_BASEADDR+2));
            xil_printf("%d\r\n", Xil_In8(XPAR_MB_CACHE_AXI_BRAM_CTRL_0_S_AXI_BASEADDR+3));

            Xil_Out8(XPAR_MB_CACHE_AXI_BRAM_CTRL_0_S_AXI_BASEADDR+10, 0); //set lock=0
        }


    }

image image

f. 请参考Code部分上传的system.tcl和pin_local.xdc文件,可以重现整个设计。