查看: 5878|回复: 3

领航者ZYNQ开发板试用3:PS I2C外设读写RTC模块

[复制链接]
  • TA的每日心情
    开心
    2022-8-6 16:18
  • 签到天数: 72 天

    连续签到: 1 天

    [LV.6]常住居民II

    发表于 2020-2-19 09:59:02 | 显示全部楼层 |阅读模式
    分享到:
    领航者ZYNQ开发板的底板上带有一个RTC实时时钟芯片和后备电池,实时时钟芯片型号是NXP的PCF8563, 该芯片还提供可编程时钟输出、一个定时器、一个报警器和一个掉电检测器,定时器和报警器都可以通过中断脚进行输出,但领航者ZYNQ开发板没有连接中断信号和时钟输出到Zynq芯片,只有连接I2C总线到Zynq芯片实现对实时时钟芯片的读写控制,原理图如下所示:
    301.jpg

    注意这里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输出:
    302.jpg

    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包要勾选上裸机库,如下图所示:
    303.jpg

    最后大家可以先下载到开发板验证下是否可以在串口上打印出hello world。

    6、修改软件工程下helloworld.c为如下所示代码,使用PS的I2C驱动读写RTC芯片:
    1. <div align="left"></div>
    2. <div align="left">#include <stdio.h></div>
    3. <div align="left">#include "platform.h"</div>
    4. <div align="left">#include "xil_printf.h"</div>
    5. <div align="left">#include "xiicps.h"</div>
    6. <div align="left">#include "sleep.h"</div>
    7. <div align="left"> </div>
    8. <div align="left">#define IIC_DEVICE_ID         XPAR_XIICPS_0_DEVICE_ID</div>
    9. <div align="left">#define IIC_SLAVE_ADDR           0x51</div>
    10. <div align="left">#define IIC_SCLK_RATE       100000</div>
    11. <div align="left">#define TEST_BUFFER_SIZE 10</div>
    12. <div align="left">u8 SendBuffer[TEST_BUFFER_SIZE];</div>
    13. <div align="left">u8 RecvBuffer[TEST_BUFFER_SIZE];</div>
    14. <div align="left">XIicPs Iic;       /**<Instance of the IIC Device */</div>
    15. <div align="left"> </div>
    16. <div align="left">typedef struct RtcTime</div>
    17. <div align="left">{</div>
    18. <div align="left">  u8 sec;</div>
    19. <div align="left">  u8 min;</div>
    20. <div align="left">  u8 hour;</div>
    21. <div align="left">  u8 day;</div>
    22. <div align="left">  u8 mon;</div>
    23. <div align="left">  u8 year;</div>
    24. <div align="left">}RtcTime;</div>
    25. <div align="left"> </div>
    26. <div align="left">int IicPsInitSetTime(RtcTime *Time)</div>
    27. <div align="left">{</div>
    28. <div align="left">       int Status;</div>
    29. <div align="left">       XIicPs_Config*Config;</div>
    30. <div align="left"> </div>
    31. <div align="left">       /*</div>
    32. <div align="left">        * Initialize the IIC driver so that it's readyto use</div>
    33. <div align="left">        * Look up the configuration in the configtable,</div>
    34. <div align="left">        * then initialize it.</div>
    35. <div align="left">        */</div>
    36. <div align="left">       Config =XIicPs_LookupConfig(IIC_DEVICE_ID);</div>
    37. <div align="left">       if (NULL == Config){</div>
    38. <div align="left">              returnXST_FAILURE;</div>
    39. <div align="left">       }</div>
    40. <div align="left"> </div>
    41. <div align="left">       Status =XIicPs_CfgInitialize(&Iic, Config, Config->BaseAddress);</div>
    42. <div align="left">       if (Status !=XST_SUCCESS) {</div>
    43. <div align="left">              returnXST_FAILURE;</div>
    44. <div align="left">       }</div>
    45. <div align="left"> </div>
    46. <div align="left">       /*</div>
    47. <div align="left">        * Perform a self-test to ensure that thehardware was built correctly.</div>
    48. <div align="left">        */</div>
    49. <div align="left">       Status =XIicPs_SelfTest(&Iic);</div>
    50. <div align="left">       if (Status !=XST_SUCCESS) {</div>
    51. <div align="left">              returnXST_FAILURE;</div>
    52. <div align="left">       }</div>
    53. <div align="left"> </div>
    54. <div align="left">       /*</div>
    55. <div align="left">        * Set the IIC serial clock rate.</div>
    56. <div align="left">        */</div>
    57. <div align="left">       XIicPs_SetSClk(&Iic,IIC_SCLK_RATE);</div>
    58. <div align="left">       /*</div>
    59. <div align="left">        * Initialize the send buffer bytes with apattern to send.</div>
    60. <div align="left">        */</div>
    61. <div align="left">       SendBuffer[0] = 2;//address</div>
    62. <div align="left">       SendBuffer[1] =Time->sec;</div>
    63. <div align="left">       SendBuffer[2] =Time->min;</div>
    64. <div align="left">       SendBuffer[3] =Time->hour;</div>
    65. <div align="left">       SendBuffer[4] = 0;</div>
    66. <div align="left">       SendBuffer[5] =Time->day;</div>
    67. <div align="left">       SendBuffer[6] =Time->mon;</div>
    68. <div align="left">       SendBuffer[7] =Time->year;</div>
    69. <div align="left">       /*</div>
    70. <div align="left">        * Send the buffer using the IIC and ignore thenumber of bytes sent</div>
    71. <div align="left">        * as the return value since we are using it ininterrupt mode.</div>
    72. <div align="left">        */</div>
    73. <div align="left">       Status =XIicPs_MasterSendPolled(&Iic, SendBuffer, 8, IIC_SLAVE_ADDR);</div>
    74. <div align="left">       if (Status !=XST_SUCCESS) {</div>
    75. <div align="left">              returnXST_FAILURE;</div>
    76. <div align="left">       }</div>
    77. <div align="left"> </div>
    78. <div align="left">       /*</div>
    79. <div align="left">        * Wait until bus is idle to start anothertransfer.</div>
    80. <div align="left">        */</div>
    81. <div align="left">       while(XIicPs_BusIsBusy(&Iic)) {</div>
    82. <div align="left">              /* NOP */</div>
    83. <div align="left">       }</div>
    84. <div align="left"> </div>
    85. <div align="left">       return XST_SUCCESS;</div>
    86. <div align="left">}</div>
    87. <div align="left">int IicPsGetTime(RtcTime *Time)</div>
    88. <div align="left">{</div>
    89. <div align="left">       int Status;</div>
    90. <div align="left"> </div>
    91. <div align="left">       Status =XIicPs_MasterSendPolled(&Iic, SendBuffer, 1, IIC_SLAVE_ADDR);</div>
    92. <div align="left">       if (Status !=XST_SUCCESS) {</div>
    93. <div align="left">              returnXST_FAILURE;</div>
    94. <div align="left">       }</div>
    95. <div align="left"> </div>
    96. <div align="left">       Status =XIicPs_MasterRecvPolled(&Iic, RecvBuffer,</div>
    97. <div align="left">                       7, IIC_SLAVE_ADDR);</div>
    98. <div align="left">       if (Status !=XST_SUCCESS) {</div>
    99. <div align="left">              returnXST_FAILURE;</div>
    100. <div align="left">       }</div>
    101. <div align="left">       else{</div>
    102. <div align="left">              Time->sec  = RecvBuffer[0];</div>
    103. <div align="left">              Time->min  = RecvBuffer[1];</div>
    104. <div align="left">              Time->hour= RecvBuffer[2] & 0x3f;</div>
    105. <div align="left">              Time->day  = RecvBuffer[4];</div>
    106. <div align="left">              Time->mon  = RecvBuffer[5];</div>
    107. <div align="left">              Time->year= RecvBuffer[6];</div>
    108. <div align="left">              returnXST_SUCCESS;</div>
    109. <div align="left">       }</div>
    110. <div align="left">}</div>
    111. <div align="left"> </div>
    112. <div align="left">int main()</div>
    113. <div align="left">{</div>
    114. <div align="left">       int Status;</div>
    115. <div align="left">       RtcTime Time;</div>
    116. <div align="left"> </div>
    117. <div align="left">       init_platform();</div>
    118. <div align="left">    printf("Test Rtcmodule use ps i2c peripheral.\n\r");</div>
    119. <div align="left"> </div>
    120. <div align="left">    Time.sec  = 0x30;</div>
    121. <div align="left">    Time.min  = 0x59;</div>
    122. <div align="left">    Time.hour = 0x09;</div>
    123. <div align="left">    Time.day  = 0x31;</div>
    124. <div align="left">    Time.mon  = 0x01;</div>
    125. <div align="left">    Time.year = 0x20;</div>
    126. <div align="left">       Status =IicPsInitSetTime(&Time);</div>
    127. <div align="left">       if (Status !=XST_SUCCESS) {</div>
    128. <div align="left">              printf("IicPsInitSetTimeFail!\n\r");</div>
    129. <div align="left">       }</div>
    130. <div align="left">       else while(1)</div>
    131. <div align="left">       {</div>
    132. <div align="left">              Status =IicPsGetTime(&Time);</div>
    133. <div align="left">              if (Status !=XST_SUCCESS) {</div>
    134. <div align="left">             printf("IicPsGetTimeFail!\n\r");</div>
    135. <div align="left">              }</div>
    136. <div align="left">              else</div>
    137. <div align="left">              {</div>
    138. <div align="left">                printf("Rtc time:  %x : %x: %x\n\r", Time.hour, Time.min,Time.sec);</div>
    139. <div align="left">              }</div>
    140. <div align="left">              //delay 5s</div>
    141. <div align="left">              sleep(5);</div>
    142. <div align="left">       }</div>
    143. <div align="left"> </div>
    144. <div align="left">    cleanup_platform();</div>
    145. <div align="left">    return 0;</div>
    146. <div align="left">}</div>
    复制代码

    编译下载后可以看到每5秒在串口上打印一次时间,测试过程和结果如下视频所示:


    最后提下,底板上有个8K字节的EEPROM芯片AT24C64也是通过同一个I2C总线连接,可以直接通过软件修改从机地址为0x50后用相同驱动来访问(已验证过)。


    回复

    使用道具 举报

    该用户从未签到

    发表于 2020-9-2 23:48:02 | 显示全部楼层
    你好,我调试这段代码的时候,程序每次进入XIicPs_MasterSendPolled都没有应答信号,总是停在Check for completion of transfer.
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    2014-12-6 15:29
  • 签到天数: 1 天

    连续签到: 1 天

    [LV.1]初来乍到

    发表于 2020-12-1 11:52:04 | 显示全部楼层
    megamind 发表于 2020-9-2 23:48
    你好,我调试这段代码的时候,程序每次进入XIicPs_MasterSendPolled都没有应答信号,总是停在Check for com ...

    我也遇到同样的问题,不知道您解决了没,能否指点一下
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    发表于 2023-9-6 19:59:34 来自手机 | 显示全部楼层
    1号哨兵 发表于 2020-12-1 11:52
    我也遇到同样的问题,不知道您解决了没,能否指点一下

    2023年了,依然还是这个问题
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /2 下一条



    手机版|小黑屋|与非网

    GMT+8, 2024-4-20 18:53 , Processed in 0.156918 second(s), 21 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2020, Tencent Cloud.