请选择 进入手机版 | 继续访问电脑版
[X]关闭

[米联客-XILINX-H3_CZ08_7100] FPGA_SDK入门篇连载-12 PS IIC-RTC实验

文档创建者:FPGA课程
浏览次数:120
最后更新:2024-09-25
文档课程分类-AMD-ZYNQ
AMD-ZYNQ: ZYNQ-SOC » 1_SDK应用方案(仅旗舰型号) » 1-SDK基础入门方案
​ 软件版本:VIVADO2021.1
操作系统:WIN10 64bit
硬件平台:适用 XILINX A7/K7/Z7/ZU/KU 系列 FPGA
实验平台:米联客-MLK-H3-CZ08-7100开发板
板卡获取平台:https://milianke.tmall.com/
登录“米联客”FPGA社区 http://www.uisrc.com 视频课程、答疑解惑!



1概述
趁热打铁,我们刚刚在上一节课掌握了I2C利用ZYNQ I2C总线控制器读写EEPROM,本节课继续利用I2C总线控制器实现对RTC时钟芯片,DS1307的读写访问。有了前面的基础,这节课内容学习起来很轻松。
本文实验目的:
1:了解DS1307/1337的寄存器,以及通过I2C读写DS1307/1337的时序
2:掌握vitis-sdk下对DS1307/1337的编程,设置时间和读取时间
2系统框图
be798f1fbe3145b2b15f016fd5c5df99.jpg
3RTC时钟DS1307/1337介绍
DS1307/1337是低功耗、两线制串行读写接口、日历和时钟数据按BCD码存取的时钟/日历芯片。它提供秒、分、小时、星期、日期、月和年等时钟日历数据。另外它还集成了如下几点功能:
(1)56 字节掉电时电池保持的NV SRAM 数据存储器
(2)可编程的方波信号输出
(3)掉电检测和自动切换电池供电模式
b4171890e09a49e8a8c6ef7db4d58c50.jpg
S1307/1337的寄存器地址空间如下,我们的代码也就是读写一下地址空间。
36f316e6da964468bf4e7beddf281726.jpg
地址空间中详细的参数定义如下表
68a67081810f423ab652cf4cf432bbc4.jpg
写时序如下:
33439d350c824145bca590096609d885.jpg
写时序很容易理解,和我们前面写EEPROM一样,先发送器件地址为1101000,再发送寄存器的地址,之后是连续写数据。
读时序如下:
e837090d6144430babade744cf6a60a1.jpg
这里读的时序有点没描述清楚,读时序前首先还要进行一次写寄存器起始地址的设置。比如代码,首先是写器件地址,并且指定标记读寄存器的其实寄存器地址为0x00,然后从标记的0x00读7个字节的数据。后面时序分析的时候再配合以上读写时序图介绍。
4硬件原理图
e1f6c7790ab74f41a2b9695f9f78bb40.jpg
如上图所示,I2C总线上挂了2个外设,分别是EEPROM 24LC02以及RTC S1337
5搭建SOC系统工程
详细的搭建过程这里不再重复,对于初学读者如果还不清楚如何创建SOC工程的,请学习“01Vitis Soc开发入门”这篇文章。
5.1SOC系统工程
5e6238f7e4df48c1816c2b84b12caebc.jpg
ZYNQ IP中设置I2C0
6aeafbcf712f4ff8a9e8a32e468cba4f.jpg
5.2编译并导出平台文件
以下步骤简写,有不清楚的看第一篇文章。
1:单击Block文件à右键àGenerate the Output ProductsàGlobalàGenerate。
2:单击Block文件à右键à Create a HDL wrapper(生成HDL顶层文件)àLet vivado manager wrapper and auto-update(自动更新)。
3:添加配套工程路径下uisrc/04_pin/fpga_pin.xdc约束文件
4:生成Bit文件。
5:导出到硬件: FileàExport HardwareàInclude bitstream
6:导出完成后,对应工程路径的soc_hw路径下有硬件平台文件:system_wrapper.xsa的文件。根据硬件平台文件system_wrapper.xsa来创建需要Platform平台。
9a6ae226acac4c86903a184ce45e70b0.jpg
6搭建Vitis-sdk工程
创建soc_base sdk platform和APP工程的过程不再重复,如果不清楚请参考本章节第一个demo。
6.1创建SDK Platform工程
e6600a16c32843a2b7fb8972f4a60de4.jpg
右击soc_base编译,编译的时间可能会有点长
6.2创建APP工程
bfa35858e41144c6bcc91f3440b63933.jpg
7程序分析
上一实验中中我们详细介绍过I2C的读写以及I2C的中断,本文中不再重复描述。以下分析只针对DS1337本身。
7.1ds1337.c程序
  1. #include "ds1337.h"

  2. u8 DS1337_decToBcd(u8 val)
  3. {
  4.         return ( (val/10*16) + (val%10) );
  5. }

  6. //Convert binary coded decimal to normal decimal numbers
  7. u8 DS1337_bcdToDec(u8 val)
  8. {
  9.         return ( (val/16*10) + (val%16) );
  10. }

  11. void DS1337_startClock(void)        // set the ClockHalt bit low to start the rtc
  12. {
  13.   //point to register
  14.         DS1337_RBUF.reg_addr[0]=0x00;// Register 0x00 holds the oscillator start/stop bit
  15.         i2cps_rd8(&I2cInst0,&DS1337_RBUF,1,DS1337_I2C_ADDRESS);
  16.         rtc.second =DS1337_RBUF.reg_buf[0] & 0x7f;// save actual seconds and AND sec with bit 7 (sart/stop bit) = clock started

  17.   //write register
  18.         DS1337_WBUF.reg_addr[0]=0x00;
  19.         DS1337_WBUF.reg_buf[0]=rtc.second;
  20.         i2cps_wr8(&I2cInst0,&DS1337_WBUF,1,DS1337_I2C_ADDRESS);// write seconds back and start the clock
  21. }

  22. void DS1337_stopClock(void)         // set the ClockHalt bit high to stop the rtc
  23. {

  24. //read register
  25.         DS1337_RBUF.reg_addr[0]=0x00;// Register 0x00 holds the oscillator start/stop bit
  26.         i2cps_rd8(&I2cInst0,&DS1337_RBUF,1,DS1337_I2C_ADDRESS);
  27.         rtc.second =DS1337_RBUF.reg_buf[0] | 0x80;// save actual seconds and AND sec with bit 7 (sart/stop bit) = clock started

  28. //write register
  29.         DS1337_WBUF.reg_addr[0]=0x00;
  30.         DS1337_WBUF.reg_buf[0]=rtc.second;
  31.         i2cps_wr8(&I2cInst0,&DS1337_WBUF,1,DS1337_I2C_ADDRESS);// write seconds back and stop the clock
  32. }

  33. /****************************************************************/
  34. /*Function: Read time and date from RTC        */
  35. void DS1337_getTime()
  36. {
  37. //point to register
  38.         DS1337_RBUF.reg_addr[0]=0x00;// Register 0x00 holds the oscillator start/stop bit
  39.         i2cps_rd8(&I2cInst0,&DS1337_RBUF,7,DS1337_I2C_ADDRESS);
  40.         // A few of these need masks because certain bits are control bits

  41.         rtc.second           = DS1337_bcdToDec(DS1337_RBUF.reg_buf[0] & 0x7f);
  42.         rtc.minute           = DS1337_bcdToDec(DS1337_RBUF.reg_buf[1]);
  43.         rtc.hour           = DS1337_bcdToDec(DS1337_RBUF.reg_buf[2] & 0x3f);// Need to change this if 12 hour am/pm
  44.         rtc.dayOfWeek  = DS1337_bcdToDec(DS1337_RBUF.reg_buf[3]);
  45.         rtc.dayOfMonth = DS1337_bcdToDec(DS1337_RBUF.reg_buf[4]);
  46.         rtc.month      = DS1337_bcdToDec(DS1337_RBUF.reg_buf[5]);
  47.         rtc.year           = DS1337_bcdToDec(DS1337_RBUF.reg_buf[6]);
  48. }

  49. /*******************************************************************/
  50. /*Function: Write the time that includes the date to the RTC chip */
  51. void DS1337_setTime()
  52. {
  53.         DS1337_WBUF.reg_addr[0]=0x00;
  54.         DS1337_WBUF.reg_buf[0]=DS1337_decToBcd(rtc.second);// 0 to bit 7 starts the clock
  55.         DS1337_WBUF.reg_buf[1]=DS1337_decToBcd(rtc.minute);
  56.         DS1337_WBUF.reg_buf[2]=DS1337_decToBcd(rtc.hour);// If you want 12 hour am/pm you need to set bit 6
  57.         DS1337_WBUF.reg_buf[3]=DS1337_decToBcd(rtc.dayOfWeek);
  58.         DS1337_WBUF.reg_buf[4]=DS1337_decToBcd(rtc.dayOfMonth);
  59.         DS1337_WBUF.reg_buf[5]=DS1337_decToBcd(rtc.month);
  60.         DS1337_WBUF.reg_buf[6]=DS1337_decToBcd(rtc.year);
  61.         i2cps_wr8(&I2cInst0,&DS1337_WBUF,7,DS1337_I2C_ADDRESS);
  62. }

  63. void DS1337_fillByHMS(u8 _hour, u8 _minute, u8 _second)
  64. {
  65.         // assign variables
  66.         rtc.hour = _hour;
  67.         rtc.minute = _minute;
  68.         rtc.second = _second;
  69. }
  70. void DS1337_fillByYMD(u16 _year, u8 _month, u8 _day)
  71. {

  72.         rtc.year = _year-2000;
  73.         rtc.month = _month;
  74.         rtc.dayOfMonth = _day;
  75. }
  76. void DS1337_fillDayOfWeek(u8 _dow)
  77. {
  78.         rtc.dayOfWeek = _dow;
  79. }
复制代码

DS1307_startClock
函数启动RTC时钟芯片运行
DS1307_stopClock
函数启动RTC停止芯片运行
DS1307_getTime
函数读取RTC时钟芯片时间
DS1307_setTime
函数设置RTC时钟芯片时间
DS1307_fillByHMS
初始化年时分秒时间变量
DS1307_fillByYMD
初始化年月日时间变量
DS1307_fillDayOfWeek
初始化周几时间变量
DS1307_decToBcd
十进制转BCD码
DS1307_bcdToDec
BCD码转10进制
写时序很容易理解,和我们前面写EEPROM一样,先发送器件地址为1101000,再发送寄存器的地址,之后是连续写数据。
写时序如下:

设置时间的函数如下:
  1. /*******************************************************************/
  2. /*Function: Write the time that includes the date to the RTC chip */
  3. void DS1337_setTime()
  4. {
  5.         DS1337_WBUF.reg_addr[0]=0x00;
  6.         DS1337_WBUF.reg_buf[0]=DS1337_decToBcd(rtc.second);// 0 to bit 7 starts the clock
  7.         DS1337_WBUF.reg_buf[1]=DS1337_decToBcd(rtc.minute);
  8.         DS1337_WBUF.reg_buf[2]=DS1337_decToBcd(rtc.hour);// If you want 12 hour am/pm you need to set bit 6
  9.         DS1337_WBUF.reg_buf[3]=DS1337_decToBcd(rtc.dayOfWeek);
  10.         DS1337_WBUF.reg_buf[4]=DS1337_decToBcd(rtc.dayOfMonth);
  11.         DS1337_WBUF.reg_buf[5]=DS1337_decToBcd(rtc.month);
  12.         DS1337_WBUF.reg_buf[6]=DS1337_decToBcd(rtc.year);
  13.         i2cps_wr8(&I2cInst0,&DS1337_WBUF,7,DS1337_I2C_ADDRESS);
  14. }<img width="15" _height="15" src="data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==" border="0" alt="">
复制代码

这里读的时序有点没描述清楚,读时序前首先还要进行一次写寄存器起始地址的设置。比如代码,首先是写器件地址,并且指定标记读寄存器的其实寄存器地址为0x00,然后从标记的0x00读7个字节的数据。
读时序如下:
2d62aaec061a4b2c89f1a2dfb390ea90.jpg
获取实现的函数,如下:
  1. /*Function: Read time and date from RTC        */
  2. void DS1337_getTime()
  3. {
  4. //point to register
  5.         DS1337_RBUF.reg_addr[0]=0x00;// Register 0x00 holds the oscillator start/stop bit
  6.         i2cps_rd8(&I2cInst0,&DS1337_RBUF,7,DS1337_I2C_ADDRESS);
  7.         // A few of these need masks because certain bits are control bits

  8.         rtc.second           = DS1337_bcdToDec(DS1337_RBUF.reg_buf[0] & 0x7f);
  9.         rtc.minute           = DS1337_bcdToDec(DS1337_RBUF.reg_buf[1]);
  10.         rtc.hour           = DS1337_bcdToDec(DS1337_RBUF.reg_buf[2] & 0x3f);// Need to change this if 12 hour am/pm
  11.         rtc.dayOfWeek  = DS1337_bcdToDec(DS1337_RBUF.reg_buf[3]);
  12.         rtc.dayOfMonth = DS1337_bcdToDec(DS1337_RBUF.reg_buf[4]);
  13.         rtc.month      = DS1337_bcdToDec(DS1337_RBUF.reg_buf[5]);
  14.         rtc.year           = DS1337_bcdToDec(DS1337_RBUF.reg_buf[6]);
  15. }
复制代码

7.2ds1337_test.c
  1. /********************MILIANKE**************************

  2. *Company:Liyang Milian Electronic Technology Co., Ltd
  3. *Technical forum:www.uisrc.com
  4. *Taobao: https://milianke.taobao.com
  5. *Create Date: 2020/12/01
  6. *Module Name:iic_rtc_test
  7. *Copyright: Copyright (c) milianke
  8. *Revision: 1.1
  9. *Description:

  10. ****************************************************/

  11. #include "I2cPs_Polled.h"
  12. #include "ds1337.h"

  13. void setup()
  14. {
  15.         DS1337_startClock();
  16.         DS1337_fillByYMD(2019,5,10);//Jan 19,2013
  17.         DS1337_fillByHMS(11,20,30);//15:28 30"
  18.         DS1337_fillDayOfWeek(FRI);//Saturday
  19.         DS1337_setTime();//write time to the RTC chip

  20. }

  21. int main(void)
  22. {

  23.         I2cPs_init(&Iic,IIC_DEVICE_ID);
  24.         setup();
  25.         while(1)
  26.         {

  27.         DS1337_getTime();
  28.         xil_printf("%d:%d:%d-%d-%d-%d-",rtc.hour,rtc.minute,rtc.second,rtc.month,rtc.dayOfMonth,rtc.year+2000);

  29.         switch (rtc.dayOfWeek)// Friendly printout the weekday
  30.         {
  31.                 case MON:
  32.                         xil_printf("MON");
  33.                   break;
  34.                 case TUE:
  35.                         xil_printf("TUE");
  36.                   break;
  37.                 case WED:
  38.                         xil_printf("WED");
  39.                   break;
  40.                 case THU:
  41.                         xil_printf("THU");
  42.                   break;
  43.                 case FRI:
  44.                         xil_printf("FRI");
  45.                   break;
  46.                 case SAT:
  47.                         xil_printf("SAT");
  48.                   break;
  49.                 case SUN:
  50.                         xil_printf("SUN");
  51.                   break;
  52.         }

  53.         xil_printf("\r\n");

  54.         sleep(1);
  55.         }
  56.     return 0;
  57. }
复制代码

在ds1337_test.c文件中,初始化I2C控制器,设置RTC时钟芯片的时间,之后每间隔1S读取一次时间值,并且通过串口打印。
8方案演示
8.1硬件准备
实验需要用到 JTAG 下载器、USB 转串口外设,另外需要把核心板上的 2P 模式开关设置到 JTAG 模式,即ON ON(注意新版本的 MLK_H3_CZ08-7100-MZ7100FC),支持 JTAG 模式,对于老版本的核心板,JTAG 调试的时候 一定要拔掉 TF 卡,并且设置模式开关为 OFF OFF)
a1baa1577e2545f59ca1e9ccfd074ff1.jpg
8.2实验结果
对于DS1337的测试采用了I2C Polled模式
63197bca9490469eabcb39832f5b4011.jpg








您需要登录后才可以回帖 登录 | 立即注册

本版积分规则