學(xué)習(xí)內(nèi)容
使用SDK和提供的API進(jìn)行初始化IIC,并驅(qū)動(dòng)iic接口的光強(qiáng)度傳感器GY-30。
開(kāi)發(fā)環(huán)境
vivado 18.3 && SDK
開(kāi)發(fā)板 pynq-z2 (由于這里的pynq的開(kāi)發(fā)板沒(méi)有相應(yīng)的MIO可以供直接使用ARM端進(jìn)行開(kāi)發(fā),所以本次內(nèi)容僅僅用于模擬流程開(kāi)發(fā)) 已經(jīng)更新,使用EMIO驅(qū)動(dòng)完成光強(qiáng)傳感器的讀取。
IIC知識(shí)部分
嵌入式-iic通信的一些概念
https://vuko-wxh.blog.csdn.net/article/details/87028608
網(wǎng)上自行查找,不再贅述。
硬件平臺(tái)搭建
首先我們需要打開(kāi)我們的vivado進(jìn)行block design的建立,方法同前文helloworld
添加zynq ip
對(duì)ip進(jìn)行相應(yīng)的配置,這里沒(méi)有用到ps-pl部分,僅僅實(shí)現(xiàn)的是zynq的arm端的配置,所以這里的config勾選全部去掉。
設(shè)置選中sd,uart,iic,并根據(jù)自己的開(kāi)發(fā)板進(jìn)行合適的配置,由于zynq沒(méi)有MIO對(duì)應(yīng)空閑的引腳,(看了半天原理圖只有一個(gè),所以就隨便配置下吧,MIO的位置)
配置完成后,點(diǎn)擊auto,生成下圖
如果沒(méi)啥問(wèn)題,就進(jìn)行生成HDL Wrapper,生成頂層文件。
然后綜合生成bit流文件
生成bit流文件后選中導(dǎo)出hardware,
并包含bit流文件
運(yùn)行sdk
SDK軟件部分
新建project
生成默認(rèn)的helloworld后可以對(duì)相應(yīng)的helloworld.c進(jìn)行改名,(通常使用main.c,和keil的習(xí)慣相同),然后我們就要找到,官方給出的API,進(jìn)行iic的開(kāi)發(fā)。在bsp的目錄下,我們可以很容易的找到各種頭文件方便我們調(diào)用,和stm32的庫(kù)相類似
如果我們想查看我們已經(jīng)定義的功能區(qū)的所要用的函數(shù),可以在system.mss中查看
打開(kāi)后,可以看到我們之前在bd中配置的東西這里都會(huì)有相應(yīng)的使用api的文件
點(diǎn)擊打開(kāi)iicps的文件,我們就可以查看相應(yīng)的api的使用方法。
初始化外設(shè)需要的函數(shù)
XIicPs_LookupConfig();//查找外設(shè)的配置結(jié)構(gòu)體
XIicPs_CfgInitialize();//初始化外設(shè)
XIicPs_SetSClk();//設(shè)置IIC速度
XIicPs_LookupConfig()
在這里插入圖片描述
根據(jù)唯一的設(shè)備ID查找設(shè)備配置。表格包含系統(tǒng)中每個(gè)設(shè)備的配置信息。參數(shù)DeviceId包含要為其查找配置的設(shè)備的ID。 返回指向找到的配置的指針;如果未找到指定的設(shè)備ID,則返回NULL。有關(guān)XIicPs_Config的定義,請(qǐng)參見(jiàn)xiicps.h。
XIicPs_CfgInitialize()
在這里插入圖片描述
初始化特定的XIicPs實(shí)例,以便驅(qū)動(dòng)程序可以使用。初始化后設(shè)備的狀態(tài)為:禁用設(shè)備從模式參數(shù)InstancePtr是指向XIicPs實(shí)例的指針。 ConfigPtr是對(duì)包含有關(guān)特定IIC設(shè)備信息的結(jié)構(gòu)的引用。此函數(shù)為Config的內(nèi)容指定的特定設(shè)備初始化InstancePtr對(duì)象。EffectiveAddr是虛擬內(nèi)存地址空間中的設(shè)備基地址。一旦調(diào)用此函數(shù),調(diào)用方負(fù)責(zé)保持從EffectiveAddr到設(shè)備物理基址的地址映射不變。如果在調(diào)用此函數(shù)后地址映射發(fā)生更改,可能會(huì)發(fā)生意外錯(cuò)誤。如果不使用地址轉(zhuǎn)換,請(qǐng)對(duì)該參數(shù)使用ConfigPtr-> BaseAddress,而是傳遞物理地址。 返回值如果成功,則返回值為XST_SUCCESS。
XIicPs_SetSClk();//設(shè)置IIC速度
在這里插入圖片描述
該功能設(shè)置IIC設(shè)備的串行時(shí)鐘速率。在設(shè)置這些設(shè)備選項(xiàng)之前,設(shè)備必須處于空閑狀態(tài)而不是忙于傳輸數(shù)據(jù)。數(shù)據(jù)速率由控制寄存器中的值設(shè)置。確定正確寄存器值的公式為:Fscl = Fpclk /(22 x(divisor_a + 1)x(divisor_b + 1))有關(guān)設(shè)置串行時(shí)鐘速率的完整說(shuō)明,請(qǐng)參見(jiàn)硬件數(shù)據(jù)手冊(cè)。參數(shù)InstancePtr是指向XIicPs實(shí)例的指針。 FsclHz是以Hz為單位的時(shí)鐘頻率。兩種最常見(jiàn)的時(shí)鐘頻率是100KHz和400KHz。 如果成功設(shè)置了選項(xiàng),則返回XST_SUCCESS。XST_DEVICE_IS_STARTED(如果設(shè)備當(dāng)前正在傳輸數(shù)據(jù))。設(shè)置選項(xiàng)之前,傳輸必須完成或中止。如果無(wú)法設(shè)置Fscl頻率,則為XST_FAILURE。
DEVICE_ID的查找辦法:
在bsp文件夾中的lib中找到xparameters.h的文件然后進(jìn)行ctrl+f查找輸入iic,快速定位到相對(duì)應(yīng)的文件。
初始化函數(shù)
首先初始化對(duì)應(yīng)的結(jié)構(gòu)體指針:
XIicPs *iicps;
XIicPs_Config * iicpscfgtr;
編寫初始化函數(shù)
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;
}
return0;
}
最后根據(jù)gy-30的手冊(cè)進(jìn)行編寫讀取光強(qiáng)的數(shù)據(jù),完整main如下:
#include
#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總線中的從地址,根據(jù)ALT ADDRESS地址引腳不同修改
//ALT ADDRESS引腳接地時(shí)地址為0x46,接電源時(shí)地址為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;
unsignedchar Cmdon = 0x01;
unsignedchar 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);//延時(shí)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);//延時(shí)180ms
status = XIicPs_MasterRecvPolled(&iicps,&temp,2,IIC_0_SALV_ADDR);
//串口檢測(cè)結(jié)果
tmp = (temp[0]<<8)| temp[1];
out = tmp/1.2;
printf("light intensity : %.1f lx\n",out);
usleep(1000000);
}
cleanup_platform();
return0;
}
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;
}
return0;
}
summary
在使用sdk時(shí)候,有個(gè)小細(xì)節(jié)要注意,我用的是18.3版本的sdk,在每次編寫代碼完成后要點(diǎn)一下保存才會(huì)將之前的內(nèi)容覆蓋,也就是該版本的SDK,編譯前不會(huì)自動(dòng)保存剛剛寫好的代碼,這一點(diǎn)需要注意。
因?yàn)楸敬沃皇沁M(jìn)行模擬實(shí)驗(yàn),所以沒(méi)有實(shí)驗(yàn)效果的反饋圖,也不知道具體在啟用讀iic數(shù)據(jù)的正確性,往后再學(xué)習(xí)一些后,我將會(huì)使用ps和pl交互的管腳進(jìn)行重跑本次實(shí)驗(yàn)。
更新配置EMIO后成功進(jìn)行了傳感器數(shù)據(jù)的讀取。