Chinaunix首页 | 论坛 | 博客
  • 博客访问: 816582
  • 博文数量: 124
  • 博客积分: 1927
  • 博客等级: 上尉
  • 技术积分: 932
  • 用 户 组: 普通用户
  • 注册时间: 2010-08-31 14:06
文章分类

全部博文(124)

文章存档

2018年(5)

2017年(2)

2016年(6)

2015年(4)

2014年(24)

2013年(7)

2012年(11)

2011年(13)

2010年(52)

我的朋友

分类: LINUX

2010-09-17 16:33:44

    由于工作原因,最近开始做Linux下的驱动程序,刚接触驱动,确实有很多东西都是新鲜名词,以前在学校的时候,基本没有摸过linux,更别说写驱动了,废话不扯了,直接讲讲我最近做RTC驱动的过程,由于是新手,上手比较慢,搞了两个礼拜左右吧。
    我用的操作系统是Linux 2.4.19 ,开发板是自己单位的交换机,用的是AT91RM9200,RTC芯片是PCF8563,之前在网上有许多大侠已经写了好多这方面的文章,作为新手的我,还是愿把自己的经历分享一把。
    刚接到老大的通知,要干这个活的时候,一头雾水,linux也没有玩过,驱动也没有写过,带操作系统的驱动,也基本扯淡,还好,这边的开发环境都是现成的,花了两天的时间,把如何烧flash,如何建立NFS文件,还有一些Linux的简单命令熟悉了一下,当然uboot的一些命令也顺带看了一下,我想对新人最大的困难就是不知道,如何运用一些命令,和这些命令的含义。同时向同事借了本宋宝华老师的《设备驱动开发详解》,2.6内核的,开始看的云里雾里的,不知所云。
    开始看书,都是想编个小程序,自己试验一下,想在开发板上看看效果,那hello world的程序,所处可见。光这个程序我开始都调了半天,由于是闭门造车,自己摸索,说实话,当时跑通了,别提多高兴了,之间还闹出,用gcc编辑的程序下载到开发板上,半天不认,找不出原因的笑话,现在回想,确实对新人来说还可以接受。 
     跑通了第一个程序,信心倍增,接着我就抱着书看关于RTC的程序,由于一开始之间的逻辑关系不是很清楚,关于操作系统也不是很了解,只以为要自己动手写个完整的驱动,看的都是内核的一些封装好的模块。实在理解不了,去网上搜了许多关于RTC方面的资料,2.6的内核确实简单,里面直接由PCF8563的驱动,只需要,写个应用程序,测试一下。这就给了我启发,看了一下我的这个内核,惊奇的发现。里面的各种驱动也是很齐全的,I2C-dev,I2C-CORE,at91-i2c都有,那我做的就是如何控制I2c去读写了。关于I2C和at91rm2000中TWI之间的控制,说实话,看的一只半解,写好应用程序,开始漫长的调程序过程。
     看程序间的调用关系,在调的过程中,惊奇的发现,写不进去一个字节,在I2C和TWI之间的驱动有问题,没有办法,在调用的程序里面,一直打着printk,通过一遍遍地努力,终于给调通了。当时真的是欣喜若狂啊,不容易啊,后来就是调应用程序,发现调起来也不容易,开始时,时钟设置和输出的时钟不对,改了一下读写的寄存器地址,就更正了过来,这时候,能get到时间而且秒能跑了,心情大好,知道成功了大半,就是日历星期的时间有问题,这些参考了下网上的程序,很容易的搞定了,终于告一段落,回首过来的路,确实不容易。。
    好了直接贴我的应用程序 吧:希望对大家有用:
#include
#include
#include
#include
#include
#include
#include
#define I2C_DEV "/dev/i2c"
#define START_ADDR 0x0
#define END_ADDR 0x9
#define IIC_SIZE (END_ADDR-START_ADDR+1)
#define CHIP_ADDR 0x51//slave address
//#define CHIP_ADDR_W 0xA2 //写地址
//#define CHIP_ADDR_R 0xA3//读地址
//#define CHIP_ADDR 0x68

#define BCD_TO_BIN(val) (((val)&15) + ((val)>>4)*10)
#define BIN_TO_BCD(val) ((((val)/10)<<4) + (val)%10)
#define TWELVE_HOUR_MODE(n) (((n)>>6)&1)
#define HOURS_AP(n)  (((n)>>5)&1)
#define HOURS_12(n)  BCD_TO_BIN((n)&0x1F)
#define HOURS_24(n)  BCD_TO_BIN((n)&0x3F)
#define date_time(n)            BCD_TO_BIN((n)&0x3f)
#define day_time(n)             BCD_TO_BIN((n)&0x7)                                                                              
struct rtc8563_time
{
        unsigned char Sec;
        unsigned char Min;
        unsigned char Hrs;
        unsigned char Day;
        unsigned char Date;
        unsigned char Mon;
        unsigned char Year;
                                                                                        
        unsigned char alarm1_Sec;
        unsigned char alarm1_Min;
        unsigned char alarm1_Hrs;
        unsigned char alarm1_Date;
                                                                                        
        unsigned char alarm2_Min;
        unsigned char alarm2_Hrs;
        unsigned char alarm2_Date;
                                                                                        
        unsigned char ctrl;
        unsigned char status;
        unsigned char trik_charger;
                                                                                        
};

struct rtc_time {
 int tm_sec;
 int tm_min;
 int tm_hour;
 int tm_mday;
 int tm_mdate; 
 int tm_mon;
 int tm_year;
};
static int read_rtc(int fd, unsigned char buff[], int addr, int count)
{
 int res;
///*
// res=write(fd, &addr, 1);
//       printf("return=%d \n", res);
 
 if(write(fd, &addr, 1)!=1)  //write address error
 {
  printf("write address error \n");
  return -1;
 }
//*/
 printf("write over!\n");  
 res = read(fd, buff, count);
//        res=i2cdev_read(fd,buff,count);
 printf("read %d byte at 0x%x \n", res, addr);
 
 return res;
}
static int write_rtc(int fd,unsigned char buff[], int addr, int count)
{
 //int i;
 int res;
 static char sendbuffer[9];
      printf("count %d\n\n",count);
 memcpy(sendbuffer+1, buff, count);
 sendbuffer[0]=addr;
 res=write(fd, sendbuffer, count+1);
//        res=i2cdev_write(fs,sendbuffer,count+1);
 printf("write %d byte at 0x%x\n", res, addr);
 return res;
}
static void
ds8563_convert_to_time( struct rtc_time *dt, char *buf)
{
 dt->tm_sec = BCD_TO_BIN(buf[0]);
 dt->tm_min = BCD_TO_BIN(buf[1]);
 if ( TWELVE_HOUR_MODE(buf[2]) )
 {
  dt->tm_hour = HOURS_12(buf[2]);
  if (HOURS_AP(buf[2])) /* PM */
  {
   dt->tm_hour += 12;
  }
 }
 else /* 24-hour-mode */
 {
  dt->tm_hour = HOURS_24(buf[2]);
 }
// dt->tm_mday=buf[4];
 dt->tm_mdate= date_time(buf[3]);
        dt->tm_mday=day_time(buf[4]);

 
 /* dt->tm_mon is zero-based */
 dt->tm_mon = (buf[5]&0x0f)+((buf[5]&0x10)>>4)*10;
 /* year is 1900 + dt->tm_year */
 dt->tm_year = BCD_TO_BIN(buf[6]) + 100*((buf[5]&0x80)?1:0);
 if(1)
 {
  printf("ds8563_get_datetime: year = %d\n", dt->tm_year);//year
  printf("ds8563_get_datetime: mon  = %d\n", dt->tm_mon);//months
  printf("ds8563_get_datetime:mdate=%d\n",   dt->tm_mdate);//date
                printf("ds8563_get_datetime: mday = %d\n", dt->tm_mday);//day
  printf("ds8563_get_datetime: hour = %d\n", dt->tm_hour);//hour
  printf("ds8563_get_datetime: min  = %d\n", dt->tm_min);//min
  printf("ds8563_get_datetime: sec  = %d\n", dt->tm_sec);//sec
 }
}

int ds8563_get_datetime(int fd, unsigned char *dt_ptr)
{
 int res;
 struct rtc8563_time recvbuff;
 struct rtc_time *m_dt;
 m_dt= (struct rtc_time *)dt_ptr;
      
       
       res=read_rtc(fd, (unsigned char *)&recvbuff,01, sizeof(struct rtc8563_time));
 
 ds8563_convert_to_time(m_dt, (unsigned char *)&recvbuff);
 return res;
}

int ds8563_set_datetime(int fd, unsigned char *dt_ptr,int datetoo)
{
 int res;

 struct rtc8563_time *sendbuff;
 struct rtc_time *m_dt;
 unsigned char buf[8];//buf[8]
 int len=4;
        m_dt=(struct rtc_time *)dt_ptr;
 sendbuff=(struct rtc8563_time*)&buf[1];
 
 {
  printf("ds8563_set_datetime: tm_year = %d\n", m_dt->tm_year);
  printf("ds8563_set_datetime: tm_mon  = %d\n", m_dt->tm_mon);
         printf("ds8563_set_datetime:tm_date=%d\n",m_dt->tm_mdate);
                printf("ds8563_set_datetime: tm_mday = %d\n", m_dt->tm_mday);
         printf("ds8563_set_datetime: tm_hour = %d\n", m_dt->tm_hour);
  printf("ds8563_set_datetime: tm_min  = %d\n", m_dt->tm_min);
  printf("ds8563_set_datetime: tm_sec  = %d\n", m_dt->tm_sec);
 }

 buf[0] = 02; /* register address on DS8563 */
 buf[1] = (BIN_TO_BCD(m_dt->tm_sec));
 buf[2] = (BIN_TO_BCD(m_dt->tm_min));
 buf[3] = (BIN_TO_BCD(m_dt->tm_hour));
 
 if (datetoo) {
  len=8;
  if(m_dt->tm_year>200)
  {
   printf("error! m_dt->tm_year=%d, >200!",m_dt->tm_year);
   return -1;
  }
  
  /* we skip buf[5] as we don't use day-of-week. */
 
  buf[4] = (BIN_TO_BCD(m_dt->tm_mdate));
                buf[5]=(BIN_TO_BCD(m_dt->tm_mday));
  buf[6] = (BIN_TO_BCD(m_dt->tm_mon));
  /* The year only ranges from 0-99, we are being passed an offset from 1900,
   * and the chip calulates leap years based on 2000, thus we adjust by 100.
   */
  buf[7] = (BIN_TO_BCD((m_dt->tm_year)%100));
  if(m_dt->tm_year/100) buf[6]|=0x80;
  
 }
 
      
 res=write_rtc(fd, (unsigned char *)sendbuff,02,7);

 printf("write %d byte at 0x%x\n", res, buf[0]);
 
 return res;
}
int main(int argc,char *argv[])
{
 int fd,res;
 struct rtc_time dt;
 dt.tm_year = 10;
 dt.tm_mon  = 9;
 dt.tm_mdate = 17;
 dt.tm_mday = 5;
 dt.tm_hour = 13;
 dt.tm_min = 22;
 dt.tm_sec = 13;
 
 
 fd = open(I2C_DEV, O_RDWR);
 if(fd<0){
  printf("#####i2c test device open failed#### \n");
  return(-1);
 }
     else{
         printf("test device open\n");
         
         }
  
 res = ioctl(fd, I2C_TENBIT, 0);
//       printf("return=%d\n",res);
       res = ioctl(fd, I2C_SLAVE, CHIP_ADDR);
        printf("I2C_SLAVE return=%d\n\n\n",res);
 
 
//      ds8563_set_datetime(fd, (unsigned char *)&dt, 1);
 ds8563_get_datetime(fd, (unsigned char *)&dt);

 close(fd);
 return(0);
}
   
     
阅读(1855) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~