【原创】zynq-7010下运用I2C总线完成对LSM303D传感器的数据读取

来源:互联网 发布:网络银行的优势 编辑:程序博客网 时间:2024/06/05 11:45

介绍

这是本人第一次写博客,我的毕设在用FPGA去读取LSM303D传感器的中的三轴的磁场强度数据,这也是我第一次用zynq-7010板子,第一次接触Vivado,我用了将近两个月的时间摸索,中间经历了很多失败的尝试,还好最近有了突破,因为目前网上基本没有关于FPGA读取LSM303D的资料,所以这也是我写这篇博文的出发点。

废话不多说,让我来一步步介绍如何通过I2C总线完成对LSM303D传感器数据的读取。本篇博文所用到的软件是Vivado 2014.4和Xilinx SDK 2014.4,用到的开发板是Zybo-7010.
这里写图片描述 这里写图片描述
这里写图片描述

一、在Vivado里建立工程

首先,我们打开Vivado软件(我用的是2014.4版本),主界面如图1所示。
图1  打开vivado软件

点击“Create New Project”,在弹出的新建工程向导中点击“Next”,弹出设置工程名和工程路径的对话框,如图2所示。在“Project name”项中输入工程名LSM303D,在“Project location”项中输入或选择工程的路径,而“Create project subdirectory”如果勾选,则会在所选的工程路径中创建一个名字与工程名一样的用于存放工程的新文件,否则直接在所选工程路径下创建工程。

图2  设置工程名和工程路径

点击“Next”,弹出选择工程类型的对话框,如图3所示。选择RTL类型,请注意RTL类型下有“Do not specify sources at this time”选项,意思是在新建工程过程中不指定源文件。

图3  选择工程类型

点击“Next”,弹出选择器件型号的对话框,我们在“Search”栏里输入xc7z010clg400,选择xc7z010clg400-1,如图4所示。

图4 选择器件型号

点击“Next”,在弹出的对话框中点击“Finish”完成工程的创建。创建工程后的主界面如图5所示,其中左侧面板是设计流程的管理,从源文件的添加到综合、仿真、布局布线、到最后板级调试,都可以通过点击相应的按键来完成;中间上面的面板是工程文件的管理;右侧面板是工程信息总结,包括工程的基本信息、综合实现所消耗的资源信息等;底部面板是各种信息的输出,包括编译信息、报告等。

图5 Vivado工程主界面

在主界面左侧的“IP Integrator”下点击“Create Block Design”,在弹出的“Design name”对话框中输入LSM303D,如图6所示。

图6 输入Design name

点击“OK”,出现如图7所示界面,此时的Block Design里还没有任何的IP核,因此我们要添加IP来完成我们的Block Design。

图7 新建立的空的Block Design

点击右侧Diagram中高亮的“Add IP”来添加IP核,首先我们在输入框内输入ZYNQ,在筛选出的结果下选择第一个“ZYNQ7 Processing System”,Diagram中便会出现ZYNQ7 Processing System IP,如图8、图9所示。

图8 添加ZYNQ7 Processing System IP

图9 ZYNQ7 Processing System IP添加完成

点击“Run Block Automation”,在弹出的对话框中点击“OK”,系统会自动连线,如图10所示。

图10 Run Block Automation

接着双击ZYNQ7 Processing System IP进行配置,在弹出的对话框中点击上方的“Import XPS Settings”,导入ZYBO_zynq_def.xml 文件(可自行百度下载),如图11所示。

图11 导入ZYBO_zynq_def.xml 文件

导入完成后如图12所示。

图12 导入ZYBO_zynq_def.xml 文件完成

点击“DDR Configuration”,在“DDR Controller Configuration”中对“Memory Part”选择“MT41K256M16 HA-125”,如图13所示。

图13 DDR Configuration下的配置

配置完成后点击“OK”,退出对ZYNQ7 Proccessing System IP的配置。系统会如图14所示。

图14 配置好的ZYNQ7 Proccessing System IP

接着,我们在Diagram中空白处右键然后点击“Add IP”,在“Search”栏中搜索IIC,在搜索结果中点击“AXI IIC”,结果如图15所示。

图15 添加AXI IIC IP

点击“Run Connection Automation”,在弹出的对话框中给“All Automation”选项打钩,然后点击“OK”,系统便会将两个IP自动连线,系统就设计完成了,结果如图16所示。

图16 Block Design 完成

我们可以双击AXI IIC IP查看内部配置,如图17所示,我们可以知道建立的IIC总线的SCL时钟是100KHz,也就是标准传输模式,地址模式使用的是7位地址寻址模式。

图17 AXI IIC IP 配置

接着我们点击中间的“Source”,可以在“Design Source”文件夹下看到“LSM303D”的Block Design工程,此时还没有生成v文件,我们需要右键“LSM303D”,点击“Generate Output Products”,在弹出的对话框中点击“Generate”,如图18所示。

图18 Generate Output Products

再次右键“LSM303D”,点击“Create HDL Wrapper”,在弹出的对话框中选择“Let Vivado manage wrapper and auto-update”然后点击“OK”,便会自动生成v文件,结果如图19所示。

图19 生成v文件

然后在左侧的“Flow Navigator”下的“Implementation”中点击“Run Implementation”,在弹出的对话框中点击“OK”,然后点击“Save”,系统就开始按流程跑综合、跑实例了,现在我们能做的就是等它跑完。跑完且不报错会弹出如图20所示对话框,点击“Open Implementation Design”开始进行管脚约束。

图20 完成Run Implementation

在打开的界面中,我们点击下方的“I/O Ports”,对iic_rtl_scl_io和iic_rtl_sda_io进行管脚约束配置,“I/O Std” 选择LVCMOS33, iic_rtl_scl_io管脚选择H15、iic_rtl_sda_io 管脚选择J15,两者的“Pull Type”均选择PULLUP,如图21所示。

图21 进行管脚约束

然后我们按“Ctrl + S”进行文件保存,在弹出对话框中点击“OK”之后,在“File name”中输入LSM303D_Constraints后点击“OK”,便生成了约束文件,如图22所示。

图22 生成约束文件

然后在左侧的“Flow Navigator”下的“Program and debug”中点击“Generate Bitstream”,在弹出的对话框中点击“Yes”系统便开始生成bit文件,这时我们开始等待系统完成bit文件的生成。完成且没有报错后,在弹出的对话框中点击“OK”,接着我们点击左上角的“File”,选择“Export”,点击“Export Hardware”,在弹出的对话框中选中“Include bitstream”后,点击“OK”,如图23所示。

图23 Export Hardware

接着再次点击“File”,选择“Launch SDK”,点击“OK”,将自动打开SDK软件。如图24所示。

图24 打开SDK软件

二、在SDK软件里建立工程

进入SDK后,点击左上角的“File”,选择“New”,点击“Application Project”,在弹出的对话框的“Project name”中输入LSM303D,如图25所示,然后点击“Next”,选择“Hello World”模板,如图26所示,点击“Finish”完成工程建立。

图25 编辑工程名

图26 选择Hello World模板

在左侧LSM303D文件夹下打开“src”文件夹,右键“Rename”helloworld.c文件的文件名,修改成main.c,结果如图27所示。

图27 修改helloworld.c文件名

然后我们将main.c中的代码修改成如下代码:

#include <stdio.h>#include <stdlib.h>#include "platform.h"#include <xiic.h>#include <xiic_l.h>#include  <math.h>#define BaseAddr 0x41600000#define Slaveaddress 0x1E/* * ------------------------------------------------ * Slave Registers Configuration:                  OUT_X_L_M_Reg = 0x08                  OUT_Y_L_M_Reg = 0x0A                  OUT_Z_L_M_Reg = 0x0C                  CTRL7_Reg     = 0x26 //(Data: 0x00) => Continuious Data    **Other registers are default** * ------------------------------------------------*/#define OUT_X_L_M_Reg  0x08#define OUT_Y_L_M_Reg  0x0A#define OUT_Z_L_M_Reg  0x0C#define CTRL7_Reg      0x26    int t;    int i;    u8 H1,L1;    s16 mdata;    float mdatax,mdatay,mdataz;void LSM303D_Config(u32 BaseAddress,u8 Slvaddr, u8 Address, u8 Data);u8 Read(u32 BaseAddress, u8 Slvaddr,u8 Address);int main(){    init_platform();    printf("Hello World\n\r");    LSM303D_Config( BaseAddr,Slaveaddress, CTRL7_Reg, 0x00);//Continuous Conversion Mode.    while(1)    {            printf("Magnetic Data: \r\n");            //Read X-axis Magnetic Data.            L1 = Read( BaseAddr,Slaveaddress, OUT_X_L_M_Reg);            H1 = Read( BaseAddr,Slaveaddress, OUT_X_L_M_Reg + 0x01);            mdata = (H1 << 8) + L1;            mdatax = mdata * 0.16;            printf("X_M= %f \r ",mdatax );            //Read Y-axis Magnetic Data.            L1 = Read( BaseAddr,Slaveaddress, OUT_Y_L_M_Reg);            H1 = Read( BaseAddr,Slaveaddress, OUT_Y_L_M_Reg + 0x01);            mdata = (H1 << 8) + L1;            mdatay = mdata *0.16;            printf("Y_M= %f \r ",mdatay );            //Read Z-axis Magnetic Data.            L1 = Read( BaseAddr,Slaveaddress, OUT_Z_L_M_Reg);            H1 = Read( BaseAddr,Slaveaddress, OUT_Z_L_M_Reg + 0x01);            mdata = (H1 << 8) + L1;            mdataz = mdata * 0.16;            printf("Z_M= %f \r ",mdataz );            printf("\r\n");            for(t=0;t<50000000;t++);//Delay    }    cleanup_platform();    return 0;}void LSM303D_Config(u32 BaseAddress, u8 Slvaddr, u8 Address, u8 Data){    unsigned Result;    u8 A[2] = {Address,Data};    u8 *Ptr = A;    Result = XIic_Send(BaseAddress, Slvaddr, Ptr, 2, XIIC_STOP);}u8 Read(u32 BaseAddress,u8 Slvaddr, u8 Address){    unsigned Result;    u8 A[1] = {Address};    u8 *Ptr = A;    u8 Buffer[1];    Result = XIic_Send(BaseAddress, Slvaddr, Ptr, 1, XIIC_STOP);    Result = XIic_Recv( BaseAddress,  Slvaddr, Buffer, 1, XIIC_STOP);    return Buffer[0];}
  • 代码中的Baseaddr是系统自动分配的首地址,可以在Vivado中的“Block Design”下点击“Address Editor” 查看,如图28所示。

图28 查看Baseaddr

  • 代码中的 XIic_Send函数和 XIic_Recv函数均为板载函数库里提供的,需要了解的可以点击左侧的LSM303D_bsp文件夹,点击ps7_cortexa9_0文件夹,点击libsrc文件夹,点击iic_v_3_0文件夹,打开src文件夹即可看到所有I2C相关的函数了,如图29所示。

图29 bsp板载函数库

  • 由于本人的毕设中只需要读取三轴的磁场强度,所以只对传感器的磁场相关的寄存器做了配置,并且只读取了输出磁场强度的寄存器,如果想要读取加速度,参考LSM303D的Datasheet,并作出相应的配置和读取即可,本文不再赘述。

输入并保存好代码后,我们就可以建立嵌入式系统了,首先建立fsbl工程。点击“File”,选择“New”,点击“Application Project”,在“Project name”中输入fsbl,点击“Next”选择“Zynq FSBL”,如图30所示。

图30 建立fsbl工程

点击“Finish”,右键“fsbl”文件夹,点击“Create Boot Image”,在弹出的对话框中选择“Create Image”,如图31所示。

图31 建立fsbl Boot Image

用同样的方法,对工程文件夹“LSM303D”建立Boot Image,如图32所示。

图32 建立LSM303D  Boot Image

三、在Vivado中烧录程序

我们首先将传感器和板子连线,开发板跳线记得要接QSPI模式,LSM303D传感器上SCL脚接板子的H15口,SDA脚接板子的J15口,SD0/SA0脚接地,CS1脚接地,CS2脚接3.3V高电平,接线如图33所示。

图33 传感器与开发板连线

接着,我们打开Vivado,在左边的“Program and debug”中点击“Open Hardware Manager”,点击“Open Target”,点击“Open New Target”,点击“Next”,再次点击“Next”,弹出如图34所示对话框,点击“Next”,点击“Finish”。

图34 完成Open Target

接着我们选择需要烧录的flash型号,在“Hardware”界面中右键xc7x010_1,点击“Add Configuration Memory Device”,在弹出的对话框中的“Search”中输入s25fl128s,在结果中选择“s25fl128s-3.3v-qspi-x4-single”,如图35所示。

图35 选择烧录的flash型号

点击“OK”,再次点击“OK”,在弹出的窗口中的“Configuration file”中选择工程文件夹下的sdk文件夹,在LSM303D文件夹中打开bootimage文件夹,找到BOOT.bin文件并选中,如图36所示。

图36 选择需要烧录的BOOT.bin文件

点击“OK”,开始烧录驱动程序,等待烧录完成后,我们打开串口调试工具,我用的是SSCOM32,波特率选择1152000bps,接着按下开发板上的PGOOD键(重启键),就可以在串口调试工具中接收到传感器发来的数据了,如图37所示。

图37 接受到传感器发来的数据


以上就是用如何在zynq-7010下运用I2C总线完成对LSM303D传感器的数据读取的步骤,整个流程都是本人历时近两个月慢慢摸索出来的。希望能对需要用FPGA来读取LSM303D传感器的人有所帮助~

原创粉丝点击