\qquad 下面是HD-GR GNSS导航软件的实时数据备份和实时时钟功能实现代码:
// rtc.c -- Real time data backup and RTC functions.
/*
* Copyright (C) 2005 Andrew Greenberg
* Distributed under the GNU GENERAL PUBLIC LICENSE (GPL) Version 2 (June 1991).
* See the "COPYING" file distributed with this software for more information.
*/
/*
* HD-GR GNSS receiver project
* Modes : None
* version : V1.0
* date : xx/xx/2015
*/
#include <io.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "includes.h"
#include "system.h"
#include "altera_avalon_pio_regs.h"
#include "alt_types.h"
#include "sys/alt_flash.h"
#include "sys/alt_sys_wrappers.h"
#include "rtc.h"
#define FLASH_BACKUP_REG 0
#define FLASH_BACKUP_OFS 0x200000
// DS32X35 RTC slave address
#define DS32X35_RTC_SLAVE_ADDRESS 0xd0
int m_rtc_inited = 0;
static int m_ic_ack = 0;
int flash_read_backup(int offset,void* dest_addr,int length)
{
int ret_code = -1;
alt_flash_fd* fd = alt_flash_open_dev(EPCS_FLASH_CONTROLLER_0_NAME);
if (fd) {
flash_region* regions;
int number_of_regions;
ret_code = alt_get_flash_info(fd, ®ions, &number_of_regions);
if ((ret_code == 0) && (number_of_regions > FLASH_BACKUP_REG)) {
offset += FLASH_BACKUP_OFS;
ret_code = alt_read_flash(fd,
regions[FLASH_BACKUP_REG].offset+offset,
dest_addr,length);
}
alt_flash_close_dev(fd);
}
return ret_code;
}
int flash_write_backup(int offset,void* dest_addr,int length)
{
int ret_code = -1;
alt_flash_fd* fd = alt_flash_open_dev(EPCS_FLASH_CONTROLLER_0_NAME);
if (fd) {
flash_region* regions;
int number_of_regions;
ret_code = alt_get_flash_info(fd, ®ions, &number_of_regions);
if ((ret_code == 0) && (number_of_regions > FLASH_BACKUP_REG)) {
offset += FLASH_BACKUP_OFS;
ret_code = alt_write_flash_block(fd,
regions[FLASH_BACKUP_REG].offset,
regions[FLASH_BACKUP_REG].offset+offset,
dest_addr,length);
}
alt_flash_close_dev(fd);
}
return ret_code;
}
int cycgps_init_backup(void)
{
int ret_code = -1;
flash_backup_t *pfb = (flash_backup_t *)malloc(sizeof(flash_backup_t));
memset(m_gps_alm, 0, sizeof(m_gps_alm));
if (pfb) {
if (flash_read_backup(0, pfb, sizeof(flash_backup_t)) == 0) {
if (pfb->header.signature == BACKUP_HEADER_SIGNATURE &&
pfb->header.data_size == sizeof(flash_backup_t)) {
m_current_pvt = pfb->body.rec_pvt;
m_current_neu = pfb->body.rec_neu;
memcpy(m_gps_alm, pfb->body.gps_alm, sizeof(m_gps_alm));
ret_code = 0;
}
}
free(pfb);
}
return ret_code;
}
int cycgps_save_backup(void)
{
int ret_code = -1;
flash_backup_t *pfb = (flash_backup_t *)malloc(sizeof(flash_backup_t));
if (pfb) {
pfb->header.signature = BACKUP_HEADER_SIGNATURE;
pfb->header.data_size = sizeof(flash_backup_t);
pfb->header.data_time = get_standard_time();
pfb->body.rec_pvt = m_current_pvt;
pfb->body.rec_neu = m_current_neu;
memcpy(pfb->body.gps_alm, m_gps_alm, sizeof(m_gps_alm));
ret_code = flash_write_backup(0, pfb, sizeof(flash_backup_t));
free(pfb);
}
return ret_code;
}
/*
* Name: iic_start
* Description: IIC启动
*/
void iic_start(void)
{
// 发送启动条件的数据信号
IOWR_ALTERA_AVALON_PIO_DIRECTION(RTC_SDA_BASE, 1);
IOWR_ALTERA_AVALON_PIO_DATA(RTC_SDA_BASE, 1);
// 发送启动条件的时钟信号
IOWR_ALTERA_AVALON_PIO_DATA(RTC_SCL_BASE, 1);
// 启动条件建立时间大于4.7us延时
ALT_USLEEP(10);
// 发送启动信号
IOWR_ALTERA_AVALON_PIO_DATA(RTC_SDA_BASE, 0);
// 启动条件保持时间大于4us
ALT_USLEEP(5);
// 钳住IIC总线,准备发送或接收数据
IOWR_ALTERA_AVALON_PIO_DATA(RTC_SCL_BASE, 0);
ALT_USLEEP(5);
}
/*
* Name: iic_stop
* Description: IIC停止
*/
void iic_stop(void)
{
// 发送停止条件的数据信号
IOWR_ALTERA_AVALON_PIO_DIRECTION(RTC_SDA_BASE, 1);
IOWR_ALTERA_AVALON_PIO_DATA(RTC_SDA_BASE, 0);
// 发送停止条件的时钟信号
IOWR_ALTERA_AVALON_PIO_DATA(RTC_SCL_BASE, 0);
ALT_USLEEP(10);
IOWR_ALTERA_AVALON_PIO_DATA(RTC_SCL_BASE, 1);
// 停止条件建立时间大于4us
ALT_USLEEP(5);
// 发送停止信号
IOWR_ALTERA_AVALON_PIO_DATA(RTC_SDA_BASE, 1);
ALT_USLEEP(10);
}
/*
* Name: iic_write
* Description: IIC写一个字节
*/
void iic_write(alt_u8 dat)
{
alt_u8 i, tmp;
IOWR_ALTERA_AVALON_PIO_DIRECTION(RTC_SDA_BASE, 1);
for(i=0; i<8; i++) {
// 发送数据位
tmp = (dat & 0x80) ? 1 : 0;
dat <<= 1;
IOWR_ALTERA_AVALON_PIO_DATA(RTC_SDA_BASE, tmp);
ALT_USLEEP(5);
// 置时钟线为高,通知受控器开始接收数据位
IOWR_ALTERA_AVALON_PIO_DATA(RTC_SCL_BASE, 1);
// 保证时钟高电平周期大于4us
ALT_USLEEP(10);
IOWR_ALTERA_AVALON_PIO_DATA(RTC_SCL_BASE, 0);
ALT_USLEEP(5);
}
// 8位发送完后释放数据线,准备接收应答位
IOWR_ALTERA_AVALON_PIO_DATA(RTC_SDA_BASE, 1);
ALT_USLEEP(5);
IOWR_ALTERA_AVALON_PIO_DIRECTION(RTC_SDA_BASE, 0);
IOWR_ALTERA_AVALON_PIO_DATA(RTC_SCL_BASE, 1);
ALT_USLEEP(5);
// 接收应答位
tmp = IORD_ALTERA_AVALON_PIO_DATA(RTC_SDA_BASE);
m_ic_ack = (tmp == 1) ? 0:1;
IOWR_ALTERA_AVALON_PIO_DATA(RTC_SCL_BASE, 0);
ALT_USLEEP(5);
}
/*
* Name: iic_read
* Description: IIC读一个字节
*/
alt_u8 iic_read(void)
{
alt_u8 i, dat = 0;
IOWR_ALTERA_AVALON_PIO_DIRECTION(RTC_SDA_BASE, 0);
for(i=0; i<8; i++) {
// 置时钟线为低,准备接收数据位
IOWR_ALTERA_AVALON_PIO_DATA(RTC_SCL_BASE, 0);
// 时钟低电平周期大于4.7us
ALT_USLEEP(10);
// 置时钟线为高,使数据线上数据有效
IOWR_ALTERA_AVALON_PIO_DATA(RTC_SCL_BASE, 1);
ALT_USLEEP(5);
// 读数据位
dat <<= 1;
dat |= IORD_ALTERA_AVALON_PIO_DATA(RTC_SDA_BASE);
ALT_USLEEP(5);
}
IOWR_ALTERA_AVALON_PIO_DATA(RTC_SCL_BASE, 0);
ALT_USLEEP(5);
return dat;
}
/*
* Name: iic_ack
* Description: 发出IIC应答或非应答信号
*/
void iic_ack(int a)
{
// 发出应答或非应答信号
IOWR_ALTERA_AVALON_PIO_DIRECTION(RTC_SDA_BASE, 1);
IOWR_ALTERA_AVALON_PIO_DATA(RTC_SDA_BASE, (a == 0)? 0:1);
ALT_USLEEP(5);
// 时钟高电平周期大于4us
IOWR_ALTERA_AVALON_PIO_DATA(RTC_SCL_BASE, 1);
ALT_USLEEP(5);
// 清时钟线,钳住IIC总线以便继续接收
IOWR_ALTERA_AVALON_PIO_DATA(RTC_SCL_BASE, 0);
ALT_USLEEP(5);
}
/*
* Name: rtc_write_byte
* Description: 向RTC写一个字节
* Return: 1表示成功
*/
int rtc_write_byte(alt_u8 addr, alt_u8 dat)
{
// 启动总线
iic_start();
// 发送器件地址
iic_write(addr);
if (m_ic_ack == 0) {
return 0;
}
// 发送数据
iic_write(dat);
if (m_ic_ack == 0) {
return 0;
}
// 结束总线
iic_stop();
return 1;
}
/*
* Name: rtc_write_multibytes
* Description: 向RTC写多个字节
* Return: 1表示成功
*/
int rtc_write_multibytes(alt_u8 addr, alt_u8 suba, alt_u8 *dat, int no)
{
int i;
// 启动总线
iic_start();
// 发送器件地址
iic_write(addr);
if (m_ic_ack == 0) {
return 0;
}
// 发送器件子地址
iic_write(suba);
if (m_ic_ack == 0) {
return 0;
}
// 发送数据
for (i = 0; i < no; i ++) {
iic_write(dat[i]);
if (m_ic_ack == 0) {
return 0;
}
}
// 结束总线
iic_stop();
return 1;
}
/*
* Name: rtc_read_byte
* Description: 从RTC读一个字节
* Return: 1表示成功
*/
int rtc_read_byte(alt_u8 addr, alt_u8 *c)
{
// 启动总线
iic_start();
// 发送器件地址
iic_write(addr+1);
if (m_ic_ack == 0) {
return 0;
}
// 读取数据
*c = iic_read();
// 发送非应答位
iic_ack(1);
iic_stop();
return 1;
}
/*
* Name: rtc_read_multibytes
* Description: 从RTC读多个字节
* Return: 1表示成功
*/
int rtc_read_multibytes(alt_u8 addr, alt_u8 suba, alt_u8 *dat, int no)
{
int i;
// 启动总线
iic_start();
// 发送器件地址
iic_write(addr);
if (m_ic_ack == 0) {
return 0;
}
// 发送器件子地址
iic_write(suba);
if (m_ic_ack == 0) {
return 0;
}
iic_start();
iic_write(addr+1);
if (m_ic_ack == 0) {
return 0;
}
// 接收数据
for (i = 0; i < no-1; i ++) {
// 接收字节
dat[i]= iic_read();
// 发送应答位
iic_ack(0);
}
dat[i]= iic_read();
// 发送非应答位
iic_ack(1);
iic_stop();
return 1;
}
/*
* Description: 设置时间信息
* Return: 1表示成功
*/
int ds32x35_set_time(stdtime_t st, double gsts)
{
alt_u8 val, ti[7];
val = (alt_u8)st.seconds;
ti[0] = ((val/16) << 4) + val%16;
ti[1] = (alt_u8)(((st.minutes/16) << 4) + st.minutes%16);
ti[2] = (alt_u8)(((st.hours/16) << 4) + st.hours%16);
ti[3] = (alt_u8)((int)gsts/86400) + 1;
ti[4] = (alt_u8)(((st.days/16) << 4) + st.days%16);
ti[5] = (alt_u8)(((st.months/16) << 4) + st.months%16);
val = (alt_u8)(st.years - 2000);
ti[6] = ((val/16) << 4) + val%16;
return rtc_write_multibytes(DS32X35_RTC_SLAVE_ADDRESS, 0, ti, 7);
}
/*
* Description: 获取时间信息
* Return: 1表示成功
*/
int ds32x35_get_time(stdtime_t *pst)
{
int result;
alt_u8 ti[7];
result = rtc_read_multibytes(DS32X35_RTC_SLAVE_ADDRESS, 0, ti, 7);
if (result != 0) {
if (ti[6] == 0) {
result = 0;
}
else if (pst) {
pst->seconds= (ti[0] >> 4)*10 + ti[0]%16;
pst->minutes= (ti[1] >> 4)*10 + ti[1]%16;
pst->hours = (ti[2] >> 4)*10 + ti[2]%16;
pst->days = (ti[4] >> 4)*10 + ti[4]%16;
pst->months = (ti[5] >> 4)*10 + ti[5]%16;
pst->years = (ti[6] >> 4)*10 + ti[6]%16 + 2000;
}
}
return result;
}
/*
* Description: 检查时间设置情况,如果未设置,可能时进行设置
* Return: 1表示进行了设置, 0表示保持现有设置,-1表示错误
*/
int ds32x35_check_set_time(void)
{
if (m_rtc_inited == 0 && get_clock_state() >= SF1_CLOCK) {
int result = ds32x35_set_time(
get_standard_time(),
get_time_in_seconds());
m_rtc_inited = (result > 0) ? 1:-1;
}
return m_rtc_inited;
}