TA的每日心情 | 开心 2022-8-6 16:18 |
---|
签到天数: 72 天 连续签到: 1 天 [LV.6]常住居民II
|
领航者ZYNQ开发板的底板上带有一个RTC实时时钟芯片和后备电池,实时时钟芯片型号是NXP的PCF8563, 该芯片还提供可编程时钟输出、一个定时器、一个报警器和一个掉电检测器,定时器和报警器都可以通过中断脚进行输出,但领航者ZYNQ开发板没有连接中断信号和时钟输出到Zynq芯片,只有连接I2C总线到Zynq芯片实现对实时时钟芯片的读写控制,原理图如下所示:
注意这里I2C总线是3.3V,并且是连接到Zynq芯片的PL侧,具体的实时时钟芯片功能请参考正点原子提供的【正点原子】领航者 ZYNQ开发板光盘资料\领航者ZYNQ开发板资料盘(A盘)\7_硬件资料\2_芯片资料目录下PCF8563.pdf数据手册,另外《领航者ZYNQ之FPGA开发指南_V1.1.pdf》文档的第21章RTC实时时钟LCD显示实验(第407页~428页)需要先学习下,配套的实验源码工程可以在【正点原子】领航者 ZYNQ开发板光盘资料\领航者ZYNQ开发板资料盘(A盘)\4_SourceCode\ZYNQ_7010目录下的1_FPGA_Design.rar压缩包内找到,压缩包的16_rtc_lcd文件夹就是,该工程完全是用PL逻辑实现,解压后编译下载得到验证结果应该不难,具体步骤就不再描述了,我们知道Zynq芯片的PS侧是ARM Cortex-A9内核,并且带有两个I2C外设,使用ARM编程的方法较PL要灵活,故接下我设计的实验任务是用PS(ARM)的I2C外设来访问RTC模块,并通过串口打印出时间日期,具体实验步骤如下:
1、我们解压【正点原子】领航者 ZYNQ开发板光盘资料\领航者ZYNQ开发板资料盘(A盘)\4_SourceCode\ZYNQ_7010\2_Embedded_System.rar压缩包内的1_hello_world文件夹,我们将在这个工程基础上修改。 2、用vavido2018.3工具打开hello_world.xpr工程,然后点工程左侧Flow Navigator内的Open Block Design, 双击Zynq7 Processing System出现IP配置界面,按下图使能I2C_0外设,这里是通过EMIO输出:
3、点击IIC_0信号后按CRTL+T建立外部连接,然后Create HDL Wrapper和Generate Output Product, 因为是通过EMIO输出I2C信号,所以还需要编译PL下载比特流,并要添加约束文件按原理图指定正确的脚位,用下面的管脚约束语句:
set_property -dict {PACKAGE_PIN M17 IOSTANDARD LVCMOS33}[get_ports IIC_0_0_scl_io]
set_property -dict {PACKAGE_PIN M18 IOSTANDARD LVCMOS33}[get_ports IIC_0_0_sda_io]
4、工程主界面选择File—Export—Export Hardware..., 这里要勾选上Includebitstream。 5、工程主界面选择File—Launch SDK,然后在SDK软件先删除原来的工程,重新新建一个hello world工程,注意在BSP包要勾选上裸机库,如下图所示:
最后大家可以先下载到开发板验证下是否可以在串口上打印出hello world。
6、修改软件工程下helloworld.c为如下所示代码,使用PS的I2C驱动读写RTC芯片:
- <div align="left"></div>
- <div align="left">#include <stdio.h></div>
- <div align="left">#include "platform.h"</div>
- <div align="left">#include "xil_printf.h"</div>
- <div align="left">#include "xiicps.h"</div>
- <div align="left">#include "sleep.h"</div>
- <div align="left"> </div>
- <div align="left">#define IIC_DEVICE_ID XPAR_XIICPS_0_DEVICE_ID</div>
- <div align="left">#define IIC_SLAVE_ADDR 0x51</div>
- <div align="left">#define IIC_SCLK_RATE 100000</div>
- <div align="left">#define TEST_BUFFER_SIZE 10</div>
- <div align="left">u8 SendBuffer[TEST_BUFFER_SIZE];</div>
- <div align="left">u8 RecvBuffer[TEST_BUFFER_SIZE];</div>
- <div align="left">XIicPs Iic; /**<Instance of the IIC Device */</div>
- <div align="left"> </div>
- <div align="left">typedef struct RtcTime</div>
- <div align="left">{</div>
- <div align="left"> u8 sec;</div>
- <div align="left"> u8 min;</div>
- <div align="left"> u8 hour;</div>
- <div align="left"> u8 day;</div>
- <div align="left"> u8 mon;</div>
- <div align="left"> u8 year;</div>
- <div align="left">}RtcTime;</div>
- <div align="left"> </div>
- <div align="left">int IicPsInitSetTime(RtcTime *Time)</div>
- <div align="left">{</div>
- <div align="left"> int Status;</div>
- <div align="left"> XIicPs_Config*Config;</div>
- <div align="left"> </div>
- <div align="left"> /*</div>
- <div align="left"> * Initialize the IIC driver so that it's readyto use</div>
- <div align="left"> * Look up the configuration in the configtable,</div>
- <div align="left"> * then initialize it.</div>
- <div align="left"> */</div>
- <div align="left"> Config =XIicPs_LookupConfig(IIC_DEVICE_ID);</div>
- <div align="left"> if (NULL == Config){</div>
- <div align="left"> returnXST_FAILURE;</div>
- <div align="left"> }</div>
- <div align="left"> </div>
- <div align="left"> Status =XIicPs_CfgInitialize(&Iic, Config, Config->BaseAddress);</div>
- <div align="left"> if (Status !=XST_SUCCESS) {</div>
- <div align="left"> returnXST_FAILURE;</div>
- <div align="left"> }</div>
- <div align="left"> </div>
- <div align="left"> /*</div>
- <div align="left"> * Perform a self-test to ensure that thehardware was built correctly.</div>
- <div align="left"> */</div>
- <div align="left"> Status =XIicPs_SelfTest(&Iic);</div>
- <div align="left"> if (Status !=XST_SUCCESS) {</div>
- <div align="left"> returnXST_FAILURE;</div>
- <div align="left"> }</div>
- <div align="left"> </div>
- <div align="left"> /*</div>
- <div align="left"> * Set the IIC serial clock rate.</div>
- <div align="left"> */</div>
- <div align="left"> XIicPs_SetSClk(&Iic,IIC_SCLK_RATE);</div>
- <div align="left"> /*</div>
- <div align="left"> * Initialize the send buffer bytes with apattern to send.</div>
- <div align="left"> */</div>
- <div align="left"> SendBuffer[0] = 2;//address</div>
- <div align="left"> SendBuffer[1] =Time->sec;</div>
- <div align="left"> SendBuffer[2] =Time->min;</div>
- <div align="left"> SendBuffer[3] =Time->hour;</div>
- <div align="left"> SendBuffer[4] = 0;</div>
- <div align="left"> SendBuffer[5] =Time->day;</div>
- <div align="left"> SendBuffer[6] =Time->mon;</div>
- <div align="left"> SendBuffer[7] =Time->year;</div>
- <div align="left"> /*</div>
- <div align="left"> * Send the buffer using the IIC and ignore thenumber of bytes sent</div>
- <div align="left"> * as the return value since we are using it ininterrupt mode.</div>
- <div align="left"> */</div>
- <div align="left"> Status =XIicPs_MasterSendPolled(&Iic, SendBuffer, 8, IIC_SLAVE_ADDR);</div>
- <div align="left"> if (Status !=XST_SUCCESS) {</div>
- <div align="left"> returnXST_FAILURE;</div>
- <div align="left"> }</div>
- <div align="left"> </div>
- <div align="left"> /*</div>
- <div align="left"> * Wait until bus is idle to start anothertransfer.</div>
- <div align="left"> */</div>
- <div align="left"> while(XIicPs_BusIsBusy(&Iic)) {</div>
- <div align="left"> /* NOP */</div>
- <div align="left"> }</div>
- <div align="left"> </div>
- <div align="left"> return XST_SUCCESS;</div>
- <div align="left">}</div>
- <div align="left">int IicPsGetTime(RtcTime *Time)</div>
- <div align="left">{</div>
- <div align="left"> int Status;</div>
- <div align="left"> </div>
- <div align="left"> Status =XIicPs_MasterSendPolled(&Iic, SendBuffer, 1, IIC_SLAVE_ADDR);</div>
- <div align="left"> if (Status !=XST_SUCCESS) {</div>
- <div align="left"> returnXST_FAILURE;</div>
- <div align="left"> }</div>
- <div align="left"> </div>
- <div align="left"> Status =XIicPs_MasterRecvPolled(&Iic, RecvBuffer,</div>
- <div align="left"> 7, IIC_SLAVE_ADDR);</div>
- <div align="left"> if (Status !=XST_SUCCESS) {</div>
- <div align="left"> returnXST_FAILURE;</div>
- <div align="left"> }</div>
- <div align="left"> else{</div>
- <div align="left"> Time->sec = RecvBuffer[0];</div>
- <div align="left"> Time->min = RecvBuffer[1];</div>
- <div align="left"> Time->hour= RecvBuffer[2] & 0x3f;</div>
- <div align="left"> Time->day = RecvBuffer[4];</div>
- <div align="left"> Time->mon = RecvBuffer[5];</div>
- <div align="left"> Time->year= RecvBuffer[6];</div>
- <div align="left"> returnXST_SUCCESS;</div>
- <div align="left"> }</div>
- <div align="left">}</div>
- <div align="left"> </div>
- <div align="left">int main()</div>
- <div align="left">{</div>
- <div align="left"> int Status;</div>
- <div align="left"> RtcTime Time;</div>
- <div align="left"> </div>
- <div align="left"> init_platform();</div>
- <div align="left"> printf("Test Rtcmodule use ps i2c peripheral.\n\r");</div>
- <div align="left"> </div>
- <div align="left"> Time.sec = 0x30;</div>
- <div align="left"> Time.min = 0x59;</div>
- <div align="left"> Time.hour = 0x09;</div>
- <div align="left"> Time.day = 0x31;</div>
- <div align="left"> Time.mon = 0x01;</div>
- <div align="left"> Time.year = 0x20;</div>
- <div align="left"> Status =IicPsInitSetTime(&Time);</div>
- <div align="left"> if (Status !=XST_SUCCESS) {</div>
- <div align="left"> printf("IicPsInitSetTimeFail!\n\r");</div>
- <div align="left"> }</div>
- <div align="left"> else while(1)</div>
- <div align="left"> {</div>
- <div align="left"> Status =IicPsGetTime(&Time);</div>
- <div align="left"> if (Status !=XST_SUCCESS) {</div>
- <div align="left"> printf("IicPsGetTimeFail!\n\r");</div>
- <div align="left"> }</div>
- <div align="left"> else</div>
- <div align="left"> {</div>
- <div align="left"> printf("Rtc time: %x : %x: %x\n\r", Time.hour, Time.min,Time.sec);</div>
- <div align="left"> }</div>
- <div align="left"> //delay 5s</div>
- <div align="left"> sleep(5);</div>
- <div align="left"> }</div>
- <div align="left"> </div>
- <div align="left"> cleanup_platform();</div>
- <div align="left"> return 0;</div>
- <div align="left">}</div>
复制代码
编译下载后可以看到每5秒在串口上打印一次时间,测试过程和结果如下视频所示:
最后提下,底板上有个8K字节的EEPROM芯片AT24C64也是通过同一个I2C总线连接,可以直接通过软件修改从机地址为0x50后用相同驱动来访问(已验证过)。
|
|