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的设计
注意,只能用一个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文件中的内容,并贴上我们自己的程序。
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程序,可见都可以工作。
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
}
}