毕业论文开发语言企业开发JAVA技术.NET技术WEB开发Linux/Unix数据库技术Windows平台移动平台嵌入式论文范文英语论文
您现在的位置: 毕业论文 >> 嵌入式 >> 正文

Linux GPIO模拟I2C做RTC驱动

更新时间:2016-6-8:  来源:毕业论文

用爱普生的RX8010芯片做rtc驱动,发现每次在经过零点的时候,读出来的日期寄存器的值都会乘以2,求问各位有没有遇见过啊?或者能给提下意见吗?不胜感激~~~
描述一下细节问题:
当没有经过零点的时候,每次写入多少,断电一段时间后读出来的都很准。但是如果我写入2014-01-05 23:59,断电后过一会读出来的却是2014-01-10 00:01,只有日期寄存器的值变了,而且每次都是乘以2,也就是日期该加1,但却x2。
驱动程序里面只是简单的写入和读取,根本没有对是否经过零点做处理啊!求各位帮忙解答啦。
驱动代码如下:
#define RX8010_REG_SC        0x10 /* datetime */
#define RX8010_REG_MN        0x11
#define RX8010_REG_HR        0x12
#define RX8010_REG_DM        0x13
#define RX8010_REG_DW        0x14
#define RX8010_REG_MO        0x15
#define RX8010_REG_YR        0x16
#define RX8010_MO_C        0x80 /* century */
 
#define RTC_DEV_ADDR    0x32
#define GPIO_0_BASE 0x201A0000    //need change
 
 
void __iomem *reg_gpio0_base_va;
#define IO_ADDRESS_VERIFY(x) (reg_gpio0_base_va + ((x)-(GPIO_0_BASE)))
 
//define direction!
#define GPIO_0_DIR IO_ADDRESS_VERIFY(GPIO_0_BASE + 0x400)
 
#define SCL                 (1 << 4)    /* GPIO 5_4 */
#define SDA                 (1 << 3)    /* GPIO 5_3 */
#define GPIO_I2C_SDA_REG    IO_ADDRESS_VERIFY(GPIO_0_BASE + 0x20)
#define GPIO_I2C_SCL_REG    IO_ADDRESS_VERIFY(GPIO_0_BASE + 0x40)
 
#define GPIO_I2C_SCLSDA_REG IO_ADDRESS_VERIFY(GPIO_0_BASE + 0x60)
 
//read register value!
#define HW_REG(reg)         *((volatile unsigned int *)(reg))
#define DELAY(us)           time_delay_us(us)
 
static int s_c_polarity = 0;    /* 0: MO_C=1 means 19xx, otherwise MO_C=1 means 20xx */
 
/*
 * I2C by GPIO simulated  read data routine.
 *
 * @return value: a bit for read
 *
 */
 
static unsigned char i2c_data_read(void)
{
    unsigned char regvalue;
 
    regvalue = HW_REG(GPIO_0_DIR);
    regvalue &= (~SDA);
    HW_REG(GPIO_0_DIR) = regvalue;
    DELAY(1);
    
    regvalue = HW_REG(GPIO_I2C_SDA_REG);
    if((regvalue&SDA) != 0)
        return 1;
    else
        return 0;
}
 
 
 
/*
 * sends a start bit via I2C rountine.
 *
 */
static void i2c_start_bit(void)
{
    DELAY(1);
    i2c_set(SDA | SCL);
    DELAY(1);
    i2c_clr(SDA);
    DELAY(1);
}
 
/*
 * sends a stop bit via I2C rountine.
 *
 */
static void i2c_stop_bit(void)
{
    /*clock the ack*/
    DELAY(1);
    i2c_set(SCL);
    DELAY(1);
    i2c_clr(SCL);
 
    /* actual stop bit */
    DELAY(1);
    i2c_clr(SDA);
    DELAY(1);
    i2c_set(SCL);
    DELAY(1);
    i2c_set(SDA);
    DELAY(1);
}
 
/*
 * sends a character over I2C rountine.
 *
 * @param  c: character to send
 *
 */
static void i2c_send_byte(unsigned char c)
{
    int i;
    local_irq_disable();
    for (i=0; i<8; i++)
    {
        DELAY(1);
        i2c_clr(SCL);
        DELAY(1);
 
        if (c & (1<<(7-i)))
            i2c_set(SDA);
        else
            i2c_clr(SDA);
 
        DELAY(1);
        i2c_set(SCL);
        DELAY(1);
        i2c_clr(SCL);
    }
    DELAY(1);
 
    local_irq_enable();
}
 
/*  receives a character from I2C rountine.
 *
 *  @return value: character received
 *
 */
static unsigned char i2c_receive_byte(void)
{
    int j=0;
    int i;
    unsigned char regvalue;
 
    local_irq_disable();
    for (i=0; i<8; i++)
    {
        DELAY(1);
        i2c_clr(SCL);
        DELAY(1);
        i2c_set(SCL);
 
        regvalue = HW_REG(GPIO_0_DIR);
        regvalue &= (~SDA);
        HW_REG(GPIO_0_DIR) = regvalue;
        DELAY(1);
        if (i2c_data_read())
            j+=(1<<(7-i));
 
        DELAY(1);
        i2c_clr(SCL);
    }
    local_irq_enable();
    DELAY(1);
 
    return j;
}
 
/*  receives an acknowledge from I2C rountine.
 *
 *  @return value: 0--Ack received; 1--Nack received
 *
 */
static int i2c_receive_ack(void)
{
    int nack;
    unsigned char regvalue;
 
    DELAY(1);
 
    regvalue = HW_REG(GPIO_0_DIR);
    regvalue &= (~SDA);
    HW_REG(GPIO_0_DIR) = regvalue;
 
    DELAY(1);
    i2c_clr(SCL);
    DELAY(1);
    i2c_set(SCL);
    DELAY(1);
 
 
 
    nack = i2c_data_read();
 
    DELAY(1);
    i2c_clr(SCL);
    DELAY(1);
 
    if (nack == 0)
        return 1;
 
    return 0;
}
 
#if 0
static void i2c_send_ack(void)
{
    DELAY(1);
    i2c_clr(SCL);
    DELAY(1);
    i2c_set(SDA);
    DELAY(1);
    i2c_set(SCL);
    DELAY(1);
    i2c_clr(SCL);
    DELAY(1);
    i2c_clr(SDA);
    DELAY(1);
}
#endif
 
static unsigned char gpio_i2c_read(unsigned char devaddress, unsigned char address)
{
    int rxdata;
 
    i2c_start_bit();
    i2c_send_byte((unsigned char)(devaddress));
    i2c_receive_ack();
    i2c_send_byte(address); 
    i2c_receive_ack();      
    i2c_start_bit(); 
    i2c_send_byte((unsigned char)(devaddress) | 1); 
    i2c_receive_ack();
    rxdata = i2c_receive_byte();
    
    //i2c_send_ack();
    //--------change --------
    //i2c_send_ack();
    i2c_stop_bit();
 
    return rxdata;
}
//EXPORT_SYMBOL(gpio_i2c_read);
 
static void gpio_i2c_write(unsigned char devaddress, unsigned char address, unsigned char data)
{
    //PRINTK("device_addr:0x%2x; reg_addr:0x%2x; reg_value:0x%2x.\n", devaddress, address, data);
    i2c_start_bit();
    i2c_send_byte((unsigned char)(devaddress));
    i2c_receive_ack();
    i2c_send_byte(address); 
    i2c_receive_ack();
    i2c_send_byte(data);
    i2c_stop_bit();
}
//EXPORT_SYMBOL(gpio_i2c_write);
static void gpio_i2c_init()
{
    gpio_i2c_write(0x64,0x17,0xd8);
    DELAY(20);
    gpio_i2c_write(0x64,0x30,0x00);
    DELAY(20);
    gpio_i2c_write(0x64,0x31,0x08);
    DELAY(20);
    gpio_i2c_write(0x64,0x32,0x00);
    DELAY(20);
    gpio_i2c_write(0x64,0x1d,0x04);
    DELAY(20);
    gpio_i2c_write(0x64,0x1e,0x00);
    DELAY(20);
    gpio_i2c_write(0x64,0x1f,0x00);
    DELAY(20);
}
EXPORT_SYMBOL(rx8010_read_datetime);
int rx8010_read_datetime(struct rtc_time *rdtm)
{
    unsigned char device_addr = (RTC_DEV_ADDR << 1) & (~(1 << 0));
    unsigned char cur_addr;
    unsigned char buf[25] = {0};
 
    for (cur_addr = RX8010_REG_SC; cur_addr < RX8010_REG_YR + 1; cur_addr ++)
    {
        buf[cur_addr] = gpio_i2c_read(device_addr, cur_addr);
        PRINTK("0x%x 0x%x\n", cur_addr, buf[cur_addr]);
    }
    rdtm->tm_sec = bcd2bin(buf[RX8010_REG_SC] & 0x7F);
    rdtm->tm_min = bcd2bin(buf[RX8010_REG_MN] & 0x7F);
    rdtm->tm_hour = bcd2bin(buf[RX8010_REG_HR] & 0x3F); /* rtc hr 0-23 */
    rdtm->tm_mday = bcd2bin(buf[RX8010_REG_DM] & 0x3F);
    rdtm->tm_wday = buf[RX8010_REG_DW] & 0x07;
    rdtm->tm_mon = bcd2bin(buf[RX8010_REG_MO] & 0x1F) - 1; /* rtc mn 1-12 */
    rdtm->tm_year = bcd2bin(buf[RX8010_REG_YR]);
    if (rdtm->tm_year < 70)
        rdtm->tm_year += 100;    /* assume we are in 1970...2069 */
    /* detect the polarity heuristically. see note above. */
    s_c_polarity = (buf[RX8010_REG_MO] & RX8010_MO_C) ?
        (rdtm->tm_year >= 100) : (rdtm->tm_year < 100);
 
    rdtm->tm_isdst = 0;
    rdtm->tm_yday = rtc_year_days(rdtm->tm_mday, rdtm->tm_mon, rdtm->tm_year + 1900);
 
    PRINTK("tm is secs=%d, mins=%d, hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
        rdtm->tm_sec, rdtm->tm_min, rdtm->tm_hour, rdtm->tm_mday, rdtm->tm_mon, rdtm->tm_year, rdtm->tm_wday);
 
    /* the clock can give out invalid datetime, but we cannot return
     * -EINVAL otherwise hwclock will refuse to set the time on bootup.
     */
    if (rtc_valid_tm(rdtm) < 0)
    {
        PRINTK("retrieved date/time is not valid.\n");
        return -1;
    }
 
 
    return 0;
}
 
EXPORT_SYMBOL(rx8010_write_datetime);
void rx8010_write_datetime(struct rtc_time *tm)
{
    unsigned char device_addr = (RTC_DEV_ADDR << 1) & (~(1 << 0));
    unsigned char cur_addr;
    unsigned char buf[25] = {0};
 
    /* hours, minutes and seconds */
    buf[RX8010_REG_SC] = bin2bcd(tm->tm_sec);
    buf[RX8010_REG_MN] = bin2bcd(tm->tm_min);
    buf[RX8010_REG_HR] = bin2bcd(tm->tm_hour);
 
    buf[RX8010_REG_DM] = bin2bcd(tm->tm_mday);
 
    /* month, 1 - 12 */
    buf[RX8010_REG_MO] = bin2bcd(tm->tm_mon + 1);
 
    /* year and century */
    buf[RX8010_REG_YR] = bin2bcd(tm->tm_year % 100);
    if (s_c_polarity ? (tm->tm_year >= 100) : (tm->tm_year < 100))
        buf[RX8010_REG_MO] |= RX8010_MO_C;
 
    buf[RX8010_REG_DW] = tm->tm_wday & 0x07;
 
 
    for (cur_addr=RX8010_REG_SC; cur_addr<RX8010_REG_YR+1; cur_addr++)
    {
        gpio_i2c_write(device_addr, cur_addr, buf[cur_addr]);
        PRINTK("0x%x 0x%x\n", cur_addr, buf[cur_addr]);
    }
}
 
static int rx8010_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
    struct rtc_time *tm = (struct rtc_time *)arg;
    gpio_i2c_init();
    switch(cmd)
    {
        case RTC8010_READ:
            if(rx8010_read_datetime(tm))
            {
                return -1;
            }
            break;
 
        case RTC8010_WRITE:
            rx8010_write_datetime(tm);
            break;
 
        default:
            return -1;
    }
    return 0;
}
 
 
int rx8010_open(struct inode * inode, struct file * file)
{
    return 0;
}
int rx8010_close(struct inode * inode, struct file * file)
{
    return 0;
}
 
static struct file_operations rx8010_fops = {
    .owner      = THIS_MODULE,
    .ioctl      = rx8010_ioctl,
    .open       = rx8010_open,
    .release    = rx8010_close
};
 
 
static struct miscdevice rtc_dev = {
   .minor        = MISC_DYNAMIC_MINOR,
   .name        = "rtcrx8010",
   .fops    = &rx8010_fops,
};
 
static int __init rtc_rx8010_init(void)
{
    int ret;
 
    reg_gpio0_base_va = ioremap_nocache(GPIO_0_BASE, 0x10000);
 
 
    ret = misc_register(&rtc_dev);
    if(0 != ret)
        return -1;
 
#if 1
    PRINTK("rx8010 init is ok!\n");
    i2c_set(SCL | SDA);
#endif
    return 0;
}
 
static void __exit rtc_rx8010_exit(void)
{
    iounmap((void*)reg_gpio0_base_va);
    misc_deregister(&rtc_dev);
}
 
 
module_init(rtc_rx8010_init);
module_exit(rtc_rx8010_exit);
 
#ifdef MODULE
//#include <linux/compile.h>
#endif
//MODULE_INFO(build, UTS_VERSION);
MODULE_LICENSE("GPL");

每次读写都执行了初始化: gpio_i2c_init(),可能是这个原因吧

设为首页 | 联系站长 | 友情链接 | 网站地图 |

copyright©youerw.com 优尔论文网 严禁转载
如果本毕业论文网损害了您的利益或者侵犯了您的权利,请及时联系,我们一定会及时改正。