PYNQ项目是一个支持Xilinx Zynq器件的开源软件框架,目的在于借助Python降低Zynq嵌入式系统开发门槛,有丰富的组件:
PYNQ官网http://www.pynq.io
我手上这块开发板是PYNQ-Z1,上手有一段时间了,还是没玩出什么名堂来。主要是网上关于PYNQ的资料太少,中文资料几乎没有,我手头上的资料只有官方的文档和Github上的代码,对我这种英文不好的人来说太难。我觉得PYNQ功能确实很强大(虽然我不怎么会用),Jupyter也非常友好,好东西不应该被埋没。
我也分享一些我的学习心得,跟大家共同学习。(怎么感觉给自己开了个大坑?)
话不多说,直接进入正题。
虽然PYNQ提供了直接控制IO的Python库,但是光靠Python控制IO口和其他模块通信是不现实的。如果需要一个IIC,SPI之类的接口和其他模块通信,还是需要用MicroBlaze。PYNQ提供的例程是使用MicroBlaze控制IO,然后用Python控制MicroBlaze。
比如这个控制LED灯条的例程:
# Make sure the base overlay is loaded
from pynq.overlays.base import BaseOverlay
base = BaseOverlay("base.bit")
from pynq.lib.arduino import Grove_LEDbar
from pynq.lib.arduino import ARDUINO_GROVE_G4
# Instantiate Grove LED Bar on Arduino shield G4
ledbar = Grove_LEDbar(base.ARDUINO,ARDUINO_GROVE_G4)
ledbar.reset()
ledbar.write_binary(0b1010100000)
看Python库就可以知道,它是为Microblze写好程序,调用Python库函数为mb配置程序,并且给mb发送指令。
从我节选 class Grove_LEDbar 的构造函数就能知道:
def __init__(self, mb_info, gr_pin):
if gr_pin not in [ARDUINO_GROVE_G1,
ARDUINO_GROVE_G2,
ARDUINO_GROVE_G3,
ARDUINO_GROVE_G4,
ARDUINO_GROVE_G5,
ARDUINO_GROVE_G6,
ARDUINO_GROVE_G7]:
raise ValueError("Group number can only be G1 - G7.")
self.microblaze = Arduino(mb_info, ARDUINO_GROVE_LEDBAR_PROGRAM)
self.microblaze.write_mailbox(0, gr_pin)
self.microblaze.write_blocking_command(CONFIG_IOP_SWITCH)
所以,我们可以用它的方式为mb写程序,用它提供的库控制MicroBlaze。接下来,我就用写一个温湿度传感器DHT11的驱动程序,演示这个过程。
具体步骤参见https://youtu.be/LomArt-hi4M前两分钟
编译完成后,File->Export->Export hardwave:
然后打开xlinx SDK。
打开SDK后,需要为iop_arduino建立一个板级支持包(BSP)bsp_iop_arduino。把从Github上下载下来的代码 /pynq/lib/arduino/bsp_iop_arduino目录下的文件复制到你建立的BSP路径下。
之后你就可以用BSP创建你的Application Project,我这里创建的工程是arduino_dht11,使用MB控制IO读取温湿度。
这里我只截取了一部分代码,重点是头文件和主函数。
#include "gpio.h"
#include "timer.h"
#include
#define CONFIG_IOP_SWITCH 0x1
#define READ_TEMP 0x5
#define READ_HUMI 0x7
int main()
{
uint8_t cmd;
float temdata;
while(1)
{
while((MAILBOX_CMD_ADDR & 0x01)==0);
cmd =MAILBOX_CMD_ADDR;
switch(cmd){
case CONFIG_IOP_SWITCH:
set_gpio((gpio)MAILBOX_DATA(0));
MAILBOX_CMD_ADDR = 0;
break;
case READ_TEMP:
temdata = getTemp();
MAILBOX_DATA(0) = temdata;
MAILBOX_CMD_ADDR = 0;
break;
case READ_HUMI:
temdata = getHimi();
MAILBOX_DATA(0) = temdata;
MAILBOX_CMD_ADDR = 0;
break;
default:
MAILBOX_CMD_ADDR = 0;
break;
}
}
return 0;
}
mailbox是一段固定是内存,用于PS和MicroBlaze传输数据。它的定义在circular_buffer.h中,·
#define MAILBOX_CMD_ADDR (*(volatile u32 *)(0x0000FFFC))
#define MAILBOX_DATA(x) (*(volatile u32 *)(0x0000F000 +((x)*4)))
#define MAILBOX_DATA_PTR(x) ( (volatile u32 *)(0x0000F000 +((x)*4)))
#define MAILBOX_DATA_FLOAT(x) (*(volatile float *)(0x0000F000 +((x)*4)))
#define MAILBOX_DATA_FLOAT_PTR(x) ( (volatile float *)(0x0000F000 +((x)*4)))
主函数的作用就是等待MAILBOX_CMD_ADDR被写入指令,然后执行相应的操作。PYNQ提供的Grove传感器驱动都使用这样的机制。在我的这个例子中,主函数根据指令设置io或读取数据。
编译完成之后,SDK生成的是.elf文件,需要转为.bin文件。
打开xilinx launch shell ,进入elf文件所在的目录(Debug或是Relase),输入
mb-objcopy -O binary xx.elf xx.bin
xx表示你的文件名。
python程序的作用就是加载bin文件到microblaze中,具体的写法可以参考其他传感器的python库。