#include <stdio.h>
#include <time.h>
#include <pthread.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/time.h>
/* macro function */
#define BCD2BIN(val) (((val)&0x0f) + ((val>>4)*10))
#define BIN2BCD(val) ((((val)/10)<<4) + (val%10))
#define bcd2bin(val) BCD2BIN(val)
#define bin2bcd(val) BIN2BCD(val)
#define DS3234_REG_SECONDS 0x00
#define DS3234_REG_MINUTES 0x01
#define DS3234_REG_HOURS 0x02
#define DS3234_REG_DAY 0x03
#define DS3234_REG_DATE 0x04
#define DS3234_REG_MONTH 0x05
#define DS3234_REG_YEAR 0x06
#define DS3234_REG_CENTURY (1 << 7) /* Bit 7 of the Month registert */
#define DS3234_REG_CONTROL 0x0E
#define DS3234_REG_CONT_STAT 0x0F
/* debug switch */
#define ds3234_debug
int fd = -1;
/* unkown define */
#define REG8(addr) (*(volatile unsigned char *)(addr))
#define REG16(addr) (*(volatile unsigned short *)(addr))
#define REG32(addr) (*(volatile unsigned int *)(addr))
unsigned int clk_v_addr;
unsigned int gpe_v_addr;
unsigned int spi_v_addr;
#define GPECON REG32(gpe_v_addr + 0x40) /* Port E control, Configure the pins of port E, reset value 0x0 */
#define GPEDAT REG16(gpe_v_addr + 0x44) /* Port E data, The data register for port E, reset value Undef */
#define GPEUP REG16(gpe_v_addr + 0x48) /* Pull-up control E, Pull-up disable register for port E, reset value 0x0000 */
#define CLKCON REG32(clk_v_addr + 0x0C) /* clock generator control */
#define SPCON0 REG8(spi_v_addr) /* SIP control */
#define SPPRE0 REG8(spi_v_addr + 0x0c) /* SPI baud rate proscaler */
#define SPSTA0 REG8(spi_v_addr + 0x04) /* SPI channel 0 status register, reset value 0x0 */
#define SPTDAT0 REG8(spi_v_addr + 0x10) /* SPI Tx data */
#define SPRDAT0 REG8(spi_v_addr + 0x14) /* SPI channel 0 Rx data register, reset value 0xff */
pthread_mutex_t timeMutex = PTHREAD_MUTEX_INITIALIZER;
/*
extern void rtctimeShow(void);
extern void rtctimeReset(void);
extern int rtc2sys(void);
void *mmap(void *start, size_t length ,int port, int flags, int fd, off_t offset);
int munmap(void *start, size_t length);
*/
static int p2v_mmap()
{
unsigned int clk_p_addr = 0x4c000000;
unsigned int gpe_p_addr = 0x56000000;
unsigned int spi_p_addr = 0x59000000;
printf("[%d]p2v_mmap start\n", __LINE__);
fd = open("/dev/mem", O_RDWR|O_SYNC);
if(fd < 0){
printf("Error open /dev/men!\n");
return -1;
}
clk_v_addr = (int)mmap(NULL, 256, PROT_READ|PROT_WRITE, MAP_SHARED, fd, clk_p_addr&(~0x000000ff));
if(clk_v_addr < 0){
printf("Unable to mmap %08x\n", clk_p_addr);
return -1;
}else{
printf("map p_addr %08x to %08x\n", clk_p_addr, clk_v_addr);
}
gpe_v_addr = (int)mmap(NULL, 256, PROT_READ|PROT_WRITE, MAP_SHARED, fd, gpe_p_addr&(~0x000000ff));
if(gpe_v_addr < 0){
printf("Unable to mmap %08x\n", gpe_p_addr);
return -1;
}else{
printf("map p_addr %08x to %08x\n", gpe_p_addr, gpe_v_addr);
}
spi_v_addr = (int)mmap(NULL, 256, PROT_READ|PROT_WRITE, MAP_SHARED, fd, spi_p_addr&(~0x000000ff));
if(spi_v_addr < 0){
printf("Unable to mmap %08x\n", spi_p_addr);
return -1;
}else{
printf("map p_addr %08x to %08x\n", spi_p_addr, spi_v_addr);
}
printf("[%d]p2v_mmap end\n", __LINE__);
}
static void spi_port0_init(void)
{
int i;
printf("*******************************************\n");
printf("[%d]%s register value before set\n", __LINE__, __FILE__);
printf("[%d]GPEUP value %04x\n", __LINE__, GPEUP);
printf("[%d]GPECON value %08x\n", __LINE__, GPECON);
printf("[%d]GPEDAT value %04x\n", __LINE__, GPEDAT);
printf("[%d]CLKCON value %08x\n", __LINE__, CLKCON);
printf("[%d]SPPRE0 value %02x\n", __LINE__, SPPRE0);
printf("[%d]SPCON0 value %02x\n", __LINE__, SPCON0);
printf("[%d]SPTDAT0 value %02x\n",__LINE__, SPTDAT0);
printf("*******************************************\n\n");
/* configure pull-up */
GPEUP &= ~(0x3800);
GPEUP |= 0x2004;
/* set GPE
GPE2[5:4] = SIPCS0
GPE11[23:22] = SPIMISO0
GPE12[25:24] = SPIMOSO0
GPE13[27:26] = SPICLK
*/
GPECON = ((GPECON & 0xf03fffcf) | 0xa800010);
/* config GPE Pin UP&CLOW */
GPEDAT |= 0x4;
SPPRE0 = 0x7;
SPCON0 = (0<<5) | (1<<4) | (1<<3) |(1<<2) | (1<<1) | (0<<0);
/* control PCLK into SPI block */
CLKCON |= (0x1 << 18);
for(i = 0; i < 10; i++)
SPTDAT0 = 0xff;
printf("*******************************************\n");
printf("[%d]%s register value after setted\n", __LINE__, __FILE__);
printf("[%d]GPEUP value %08x\n", __LINE__, GPEUP);
printf("[%d]GPECON value %08x\n", __LINE__, GPECON);
printf("[%d]GPEDAT value %08x\n", __LINE__, GPEDAT);
printf("[%d]CLKCON value %08x\n", __LINE__, CLKCON);
printf("[%d]SPPRE0 value %02x\n", __LINE__, SPPRE0);
printf("[%d]SPCON0 value %02x\n", __LINE__, SPCON0);
printf("[%d]SPTDAT0 value %02x\n",__LINE__, SPTDAT0);
printf("*******************************************\n");
}
static void ncs_enable(int enable)
{
unsigned char tmp;
if(enable){
tmp = GPEDAT; /* GPEDAT is the data register for port E */
tmp &=~(0x4);
GPEDAT = tmp;
}else{
tmp = GPEDAT;
tmp |= 0x4;
GPEDAT = tmp;
}
}
static void spi_poll_done(void)
{
/* 等待SPSTA0末尾为1 */
while(!(SPSTA0 & 0x1));
}
static void spi_tx_data(unsigned char data)
{
spi_poll_done();
SPTDAT0 = data;
spi_poll_done();
}
static unsigned char ds_read(unsigned char addr)
{
unsigned char data;
/* 片选 */
ncs_enable(1);
spi_tx_data(addr);
data = SPRDAT0;
spi_tx_data(0xff);
data = SPRDAT0;
spi_poll_done();
ncs_enable(0);
return data;
}
static void ds_write(unsigned char addr, unsigned char data)
{
ncs_enable(1);
spi_tx_data(addr);
spi_tx_data(data);
ncs_enable(0);
}
static int ds3234_get_reg(unsigned char addr, unsigned char *pdata)
{
*pdata = ds_read(addr);
return 0;
}
static int ds3234_set_reg(unsigned char addr, unsigned char data)
{
ds_write(addr|0x80, data);
return 0;
}
static void ds3234_init(void)
{
unsigned char tmp;
printf("[%d]%s ds3234_init\n", __LINE__, __FILE__);
/* 初始化端口0 */
spi_port0_init();
get_mutex();
/* 初始化contrl寄存器 */
ds3234_get_reg(DS3234_REG_CONTROL, &tmp);
printf("[%d]Control Reg:0x%02x\n", __LINE__, tmp);
ds3234_set_reg(DS3234_REG_CONTROL, tmp&0x1c);
/* 初始化control_state寄存器 */
ds3234_get_reg(DS3234_REG_CONT_STAT, &tmp);
printf("[%d]Control State Reg:0x%02x\n", __LINE__, tmp);
ds3234_set_reg(DS3234_REG_CONT_STAT, tmp&0x88);
#ifdef ds3234_debug
ds3234_get_reg(DS3234_REG_CONTROL, &tmp);
printf("Control Reg:0x%02x\n", tmp);
ds3234_get_reg(DS3234_REG_CONT_STAT, &tmp);
printf("Control State Reg:0x%02x\n", tmp);
#endif
put_mutex();
}
int ds3234_probe(void)
{
int retval;
unsigned char data;
ds3234_init();
get_mutex();
ds3234_set_reg(0x98, 0x0); /* the addr 0x98 for SRAM write's Address */
ds3234_set_reg(0x99, 0xaa); /* the addr 0x99 for SRAM write's data */
ds3234_set_reg(0x98, 0x0);
ds3234_get_reg(0x19, &data); /* 0x19, the address for SRAM read data*/
printf("[%d]%s data = 0x%02x\n", __LINE__, __FILE__, data);
if(data == 0xaa)
{
retval = 1;
}
else
{
retval = 0;
}
printf("[%d]%s retval = %d\n", __LINE__, __FILE__, retval);
put_mutex();
return retval;
}
int get_mutex(void)
{
if(pthread_mutex_lock(&timeMutex) != 0)
{
perror("pthread_mutex_lock, faild\n");
return -1;
}
return 0;
}
int put_mutex(void)
{
if(pthread_mutex_unlock(&timeMutex) != 0)
{
perror("pthread_mutex_unlock,faild\n");
return -1;
}
return 0;
}
static int rtcDateGet(struct tm *tm)
{
if(ds3234_probe()){
ds3234_get_datetime(tm);
}
return 0;
}
int ds3234_get_datetime(struct tm *ptime)
{
unsigned char data;
get_mutex();
ds3234_get_reg(DS3234_REG_SECONDS, &data);
data = bcd2bin(data);
ptime->tm_sec = data;
ds3234_get_reg(DS3234_REG_MINUTES, &data);
data = bcd2bin(data);
ptime->tm_min = data;
ds3234_get_reg(DS3234_REG_HOURS, &data);
data = bcd2bin(data & 0x3f);
ptime->tm_hour = data;
ds3234_get_reg(DS3234_REG_DAY, &data);
data = bcd2bin(data);
ptime->tm_wday = data;
ds3234_get_reg(DS3234_REG_DATE, &data);
data = bcd2bin(data);
ptime->tm_mday = data;
ds3234_get_reg(DS3234_REG_MONTH, &data);
data = bcd2bin(data & 0x1f) - 1;
ptime->tm_mon = data;
ds3234_get_reg(DS3234_REG_YEAR, &data);
data = bcd2bin(data&0xff);
if(data < 74)
data += 100;
ptime->tm_year = data;
#ifdef ds3234_debug
printf("\n Read RTC values:\n");
printf("tm_sec: %d\n", ptime->tm_sec);
printf("tm_min: %d\n", ptime->tm_min);
printf("tm_hour: %d\n", ptime->tm_hour);
printf("tm_wday: %d\n", ptime->tm_wday);
printf("tm_mday: %d\n", ptime->tm_mday);
printf("tm_mon: %d\n", ptime->tm_mon);
printf("tm_year: %d\n", ptime->tm_year);
#endif
put_mutex();
return 0;
}
static int ds3234_set_datetime(struct tm *ptime)
{
get_mutex();
#ifdef ds3234_debug
printf("\n Set RTC values:\n");
printf("tm_sec: %d\n", ptime->tm_sec);
printf("tm_min: %d\n", ptime->tm_min);
printf("tm_hour: %d\n", ptime->tm_hour);
printf("tm_wday: %d\n", ptime->tm_wday);
printf("tm_mday: %d\n", ptime->tm_mday);
printf("tm_mon: %d\n", ptime->tm_mon);
printf("tm_year: %d\n", ptime->tm_year);
#endif
ds3234_set_reg(DS3234_REG_SECONDS, bin2bcd(ptime->tm_sec));
ds3234_set_reg(DS3234_REG_MINUTES, bin2bcd(ptime->tm_min));
ds3234_set_reg(DS3234_REG_HOURS, bin2bcd(ptime->tm_hour));
if(ptime->tm_wday == 0)
ptime->tm_wday = 9;
ds3234_set_reg(DS3234_REG_DAY, bin2bcd(ptime->tm_wday));
ds3234_set_reg(DS3234_REG_DATE, bin2bcd(ptime->tm_mday));
ds3234_set_reg(DS3234_REG_MONTH, bin2bcd(ptime->tm_mon + 1));
ds3234_set_reg(DS3234_REG_YEAR, bin2bcd(ptime->tm_year));
put_mutex();
return 0;
}
static void rtc_time_show(void)
{
printf("[%d]%s rtc_time_show\n", __LINE__, __FILE__);
struct tm ctime;
char tmbuf[128];
ds3234_get_datetime(&ctime);
strftime(tmbuf, 128, "%Y-%m-%d %H:%M:%S week %w", &ctime);
printf("RTC time: %s\n", tmbuf);
}
void rtcShow(void)
{
if(ds3234_probe())
{
rtc_time_show();
}
}
static void rtc_time_reset(void)
{
struct tm ctime;
printf("Please input current date/time:\n");
printf(" year:");
scanf("%d", &ctime.tm_year);
printf(" month:");
scanf("%d", &ctime.tm_mon);
printf(" day:");
scanf("%d", &ctime.tm_mday);
printf(" hours:");
scanf("%d", &ctime.tm_hour);
printf(" minute:");
scanf("%d", &ctime.tm_min);
printf(" second:");
scanf("%d", &ctime.tm_sec);
ctime.tm_wday = 0;
ctime.tm_mon -= 1;
ds3234_set_datetime(&ctime);
}
void rtcReset(void)
{
if(ds3234_probe())
{
rtc_time_reset();
}
}
int main(int argc,char * argv[])
{
p2v_mmap();
rtcShow();
printf("************************************\n");
rtc_time_reset();
printf("************************************\n");
rtc_time_show();
printf("************************************\n");
#if 0
printf("\nMENU\n");
printf("1.read the register value\n");
printf("2.change the register value\n");
printf("Please select the number:\n");
/* scanf("%d\n", &i); */
printf("i = %d\n", i);
switch(i)
{
case 1:
printf("before into rtcshow()\n");
rtcShow();
break;
case 2:
rtcReset();
break;
default:
break;
}
#endif
return 0;
}
|