ZYNQ-实现外设驱动开发-iic接口的光强度传感器GY-30
学习内容
使用SDK和提供的API进行初始化IIC,并驱动iic接口的光强度传感器GY-30。
开发环境
vivado 18.3 && SDK
开发板 pynq-z2
(由于这里的pynq的开发板没有相应的MIO可以供直接使用ARM端进行开发,所以本次内容仅仅用于模拟流程开发)
已经更新,使用EMIO驱动完成光强传感器的读取
IIC知识部分
嵌入式-iic通信的一些概念
网上自行查找,不再赘述。
硬件平台搭建
首先我们需要打开我们的vivado进行block design的建立,方法同前文helloworld
添加zynq ip
对ip进行相应的配置,这里没有用到ps-pl部分,仅仅实现的是zynq的arm端的配置,所以这里的config勾选全部去掉。
设置选中sd,uart,iic,并根据自己的开发板进行合适的配置,由于zynq没有MIO对应空闲的引脚,(看了半天原理图只有一个,所以就随便配置下吧,MIO的位置)
配置完成后,点击auto,生成下图
如果没啥问题,就进行生成HDL Wrapper,生成顶层文件。
然后综合生成bit流文件
生成bit流文件后选中导出hardware,
并包含bit流文件
运行sdk
SDK软件部分
新建project
生成默认的helloworld后可以对相应的helloworld.c进行改名,(通常使用main.c,和keil的习惯相同),然后我们就要找到,官方给出的API,进行iic的开发。在bsp的目录下,我们可以很容易的找到各种头文件方便我们调用,和stm32的库相类似
如果我们想查看我们已经定义的功能区的所要用的函数,可以在system.mss中查看
打开后,可以看到我们之前在bd中配置的东西这里都会有相应的使用api的文件
点击打开iicps的文件,我们就可以查看相应的api的使用方法。
初始化外设需要的函数
XIicPs_LookupConfig();//查找外设的配置结构体
XIicPs_CfgInitialize();//初始化外设
XIicPs_SetSClk();//设置IIC速度
XIicPs_LookupConfig()
根据唯一的设备ID查找设备配置。
表格包含系统中每个设备的配置信息。
参数DeviceId包含要为其查找配置的设备的ID。 返回指向找到的配置的指针;如果未找到指定的设备ID,则返回NULL。 有关XIicPs_Config的定义,请参见xiicps.h。
XIicPs_CfgInitialize()
初始化特定的XIicPs实例,以便驱动程序可以使用。
初始化后设备的状态为:禁用设备从模式参数InstancePtr是指向XIicPs实例的指针。 ConfigPtr是对包含有关特定IIC设备信息的结构的引用。 此函数为Config的内容指定的特定设备初始化InstancePtr对象。
EffectiveAddr是虚拟内存地址空间中的设备基地址。
一旦调用此函数,调用方负责保持从EffectiveAddr到设备物理基址的地址映射不变。
如果在调用此函数后地址映射发生更改,可能会发生意外错误。 如果不使用地址转换,请对该参数使用ConfigPtr->
BaseAddress,而是传递物理地址。 返回值如果成功,则返回值为XST_SUCCESS。
XIicPs_SetSClk();//设置IIC速度
该功能设置IIC设备的串行时钟速率。
在设置这些设备选项之前,设备必须处于空闲状态而不是忙于传输数据。
数据速率由控制寄存器中的值设置。 确定正确寄存器值的公式为:Fscl = Fpclk /(22 x(divisor_a + 1)x(divisor_b + 1))有关设置串行时钟速率的完整说明,请参见硬件数据手册。
参数InstancePtr是指向XIicPs实例的指针。 FsclHz是以Hz为单位的时钟频率。 两种最常见的时钟频率是100KHz和400KHz。 如果成功设置了选项,则返回XST_SUCCESS。
XST_DEVICE_IS_STARTED(如果设备当前正在传输数据)。 设置选项之前,传输必须完成或中止。
如果无法设置Fscl频率,则为XST_FAILURE。
DEVICE_ID的查找办法:
在bsp文件夹中的lib中找到xparameters.h的文件然后进行ctrl+f查找输入iic,快速定位到相对应的文件。
初始化函数
首先初始化对应的结构体指针:
XIicPs *iicps;
XIicPs_Config * iicpscfgtr;
编写初始化函数
int InitIic(XIicPs *iips,XIicPs_Config * iiccfg){
int status;
iiccfg = XIicPs_LookupConfig(I2C_0_DEVICE_ID);
status = XIicPs_CfgInitialize(iips,iiccfg,iiccfg->BaseAddress);
if(status !=XST_SUCCESS){
return XST_FAILURE;
}
status = XIicPs_SetSClk(iips,I2C_0_CLK);
if(status !=XST_SUCCESS){
return XST_FAILURE;
}
return 0;
}
最后根据gy-30的手册进行编写读取光强的数据,完整main如下:
#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xiicps.h"
#include "xparameters.h"
#include "sleep.h"
#define I2C_0_DEVICE_ID XPAR_PS7_I2C_0_DEVICE_ID
#define I2C_0_CLK 100000
#define IIC_0_SALV_ADDR 0x23 //定义器件在IIC总线中的从地址,根据ALT ADDRESS地址引脚不同修改
//ALT ADDRESS引脚接地时地址为0x46,接电源时地址为0xB8
// XIicPs* iicps;
XIicPs iicps;
XIicPs_Config * iicpscfgtr;
//初始化 iic
int InitIic(XIicPs *iips,XIicPs_Config *iiccfg);
int main()
{
int status;
double out=0;
unsigned short tmp;
unsigned char Cmdon = 0x01;
unsigned char Cmdlight = 0x10;
char temp[2];
init_platform();
status=InitIic(&iicps,iicpscfgtr);
if(status !=XST_SUCCESS){
return XST_FAILURE;
}
//初始化
status = XIicPs_MasterSendPolled(&iicps,&Cmdon,1,IIC_0_SALV_ADDR);
if(status !=XST_SUCCESS){
return XST_FAILURE;
}
usleep(10000);//延时10ms
printf("init iic successful!\n");
while(1){
status = XIicPs_MasterSendPolled(&iicps,&Cmdon,1,IIC_0_SALV_ADDR);
if(status !=XST_SUCCESS){
return XST_FAILURE;
}
status = XIicPs_MasterSendPolled(&iicps,&Cmdlight,1,IIC_0_SALV_ADDR);
if(status !=XST_SUCCESS){
return XST_FAILURE;
}
usleep(180000);//延时180ms
status = XIicPs_MasterRecvPolled(&iicps,&temp,2,IIC_0_SALV_ADDR);
//串口检测结果
tmp = (temp[0]<<8)| temp[1];
out = tmp/1.2;
printf("light intensity : %.1f lx\n",out);
usleep(1000000);
}
cleanup_platform();
return 0;
}
int InitIic(XIicPs *iips,XIicPs_Config * iiccfg){
int status;
iiccfg = XIicPs_LookupConfig(I2C_0_DEVICE_ID);
status = XIicPs_CfgInitialize(iips,iiccfg,iiccfg->BaseAddress);
if(status !=XST_SUCCESS){
return XST_FAILURE;
}
status = XIicPs_SelfTest(iips);
if (status != XST_SUCCESS) {
return XST_FAILURE;
}
status = XIicPs_SetSClk(iips,I2C_0_CLK);
if(status !=XST_SUCCESS){
return XST_FAILURE;
}
return 0;
}
summary
在使用sdk时候,有个小细节要注意,我用的是18.3版本的sdk,在每次编写代码完成后要点一下保存才会将之前的内容覆盖,也就是该版本的SDK,编译前不会自动保存刚刚写好的代码,这一点需要注意。
因为本次只是进行模拟实验,所以没有实验效果的反馈图,也不知道具体在启用读iic数据的正确性,往后再学习一些后,我将会使用ps和pl交互的管脚进行重跑本次实验。
更新配置EMIO后成功进行了传感器数据的读取。
相关文章
- 幻灯片04-剔除“伪创新” 的领域驱动设计-领域建模结构部分Part3
- MOS管驱动电路设计,如何让MOS管快速开启和关闭?
- python+requests+excel+unittest+ddt接口自动化数据驱动并生成html报告(优化版)
- LED外置MOS降压恒流驱动IC 12-36V 9V 1A驱动方案
- FPGA零基础学习之Vivado-数码管驱动设计实验
- 深入认识Linux阵列驱动程序.(linux阵列驱动)
- VB6驱动MySQL实现数据库连接(vb6mysql驱动)
- Linus Torvalds呼吁Paragon尽快提交NTFS读写驱动到内核
- Linux驱动:开启新世界(linux驱动启动)
- Linux驱动之接口技术简介(linux驱动接口)
- Oracle 11g驱动:开启新的数据库之旅(oracle11g驱动)
- 掌握MySQL数据库,创建驱动创新(创建数据库mysql)
- kernelEC20芯片驱动安装在Linux内核上(ec20linux)
- AMD Radeon 图形驱动占到了 Linux 内核的 10.5%
- Linux Hub驱动即插即用,高效稳定的电脑设备管理利器(linuxhub驱动)
- 理解Linux驱动高效编程技巧:流程解析(linux驱动流程)
- Oracle数据库驱动让您的数据丰富多彩(10oracle驱动)