一、实验平台:开发板fs2410,采用三星s3c2410的CPU,linux操作系统。
二、实现功能:设置开发板的时间,并能实时显示出时间。
三、实验原理:
采用平台设备驱动机制来编写驱动程序,通过修改或读取相应寄存器的值来修改或获取开发板的时间。
四、实验现象:
应用程序执行时,若输入./RTC_test set,则为设置当前时间,这时提示输入时间,格式为年月 日 时 分 秒(如2011 11 28 20 45 0)。若输入./RTC_test get则实时地显示当前的时间,可以看到每隔一秒钟,秒的时间+1。关掉开发板电源,等待一段时间后,再读取时间,可以看到时间是在改变的,即在掉电的状态下,时钟没有停下来,因为它有板子上的纽扣电池来供电。
五、实验总结:
实验原理很简单,主要是体会一下采用平台设备驱动机制来写驱动代码时的步骤和思路,以及与之前没使用平台设备驱动机制时的不同。
六、示例代码:
驱动部分:
/*RTC_dev.c*/
#include<linux/kernel.h>
#include<linux/module.h>
#include<linux/init.h>
#include<linux/device.h>
#include <asm/mach/map.h>
#include<linux/platform_device.h>
static struct resource rtc_resource[] = {
[0] = {
.start = S3C24XX_PA_RTC,
.end = S3C24XX_PA_RTC + 0xff,
.flags = IORESOURCE_MEM,
}
};
void rtc_release(struct device * dev)
{
}
struct platform_device rtc_device = {
.name = "myrtc",
.id = -1,
.num_resources = ARRAY_SIZE(rtc_resource),
.resource = rtc_resource,
.dev = {
.release = rtc_release,
},
};
int __init rtc_dev_init(void)
{
platform_device_register(&rtc_device);
return 0;
}
void __exit rtc_dev_exit(void)
{
platform_device_unregister(&rtc_device);
}
module_init(rtc_dev_init);
module_exit(rtc_dev_exit);
MODULE_LICENSE("GPL");
/*RTC_drv.c*/
#include<linux/kernel.h>
#include<linux/module.h>
#include<linux/init.h>
#include<linux/device.h>
#include<linux/platform_device.h>
#include <linux/rtc.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/arch/regs-rtc.h>
#include <linux/bcd.h>
#define TIME_SET 0
#define TIME_GET 1
static void __iomem *rtc_base;
static unsigned int rtc_major = 0;
static struct class *rtc_class = NULL;
static struct rtc_time rtc_time;
void set_time(struct rtc_time *rtc_time)
{
int val;
int year,mon,date,hour,min,sec;
val = readb(rtc_base +S3C2410_RTCCON);
val |=(0x1<<0);
writeb(val, rtc_base +S3C2410_RTCCON);
year = rtc_time->tm_year;
mon = rtc_time->tm_mon;
date = rtc_time->tm_mday;
hour = rtc_time->tm_hour;
min = rtc_time->tm_min;
sec = rtc_time->tm_sec;
year -= 1900;
BIN_TO_BCD(year);
BIN_TO_BCD(mon);
BIN_TO_BCD(date);
BIN_TO_BCD(hour);
BIN_TO_BCD(min );
BIN_TO_BCD(sec);
writeb(year, rtc_base+S3C2410_RTCYEAR);
writeb(mon, rtc_base+S3C2410_RTCMON);
writeb(date, rtc_base+S3C2410_RTCDATE);
writeb(hour, rtc_base+S3C2410_RTCHOUR);
writeb(min, rtc_base+S3C2410_RTCMIN);
writeb(sec,rtc_base+S3C2410_RTCSEC);
val = readb(rtc_base +S3C2410_RTCCON);
val &=~(0x1<<0);
writeb(val, rtc_base +S3C2410_RTCCON);
}
void get_time(struct rtc_time *rtc_time)
{
int year,mon,date,hour,min,sec;
year = readb(rtc_base+S3C2410_RTCYEAR);
mon = readb(rtc_base+S3C2410_RTCMON);
date = readb(rtc_base+S3C2410_RTCDATE);
hour = readb(rtc_base+S3C2410_RTCHOUR);
min = readb(rtc_base+S3C2410_RTCMIN);
sec = readb(rtc_base+S3C2410_RTCSEC);
BCD_TO_BIN(year);
BCD_TO_BIN(mon);
BCD_TO_BIN(date);
BCD_TO_BIN(hour);
BCD_TO_BIN(min);
BCD_TO_BIN(sec);
year += 1900;
rtc_time->tm_year = year;
rtc_time->tm_mon = mon;
rtc_time->tm_mday = date;
rtc_time->tm_hour = hour;
rtc_time->tm_min = min;
rtc_time->tm_sec = sec;
}
static int rtc_open(struct inode *inode, struct file *file)
{
return 0;
}
static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
int ret;
switch(cmd){
case TIME_SET:
ret = copy_from_user(&rtc_time, (struct rtc_time *)arg, sizeof(rtc_time));
set_time(&rtc_time);
break;
case TIME_GET:
get_time(&rtc_time);
ret = copy_to_user((struct rtc_time *)arg, &rtc_time, sizeof(rtc_time));
break;
}
return 0;
}
struct file_operations rtc_fops = {
.owner = THIS_MODULE,
.open = rtc_open,
.ioctl = rtc_ioctl,
};
static int __devinit rtc_probe(struct platform_device *pdev)
{
struct resource *res;
/*获得资源*/
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
/*映射*/
rtc_base = ioremap(res->start, res->end-res->start+1);
/*注册*/
rtc_major = register_chrdev(0, "rtc", &rtc_fops);
rtc_class = class_create(THIS_MODULE, "rtc_class");
class_device_create(rtc_class, NULL, MKDEV(rtc_major, 0), NULL, "rtc");
return 0;
}
static int __devexit rtc_remove(struct platform_device *dev)
{
iounmap(rtc_base);
unregister_chrdev(rtc_major, "rtc");
class_destroy(rtc_class);
class_device_destroy(rtc_class, MKDEV(rtc_major, 0));
return 0;
}
struct platform_driver rtc_driver = {
.probe = rtc_probe,
.remove = rtc_remove,
.driver ={
.owner = THIS_MODULE,
.name = "myrtc",
},
};
int __init rtc_drv_init(void)
{
platform_driver_register(&rtc_driver);
return 0;
}
void __exit rtc_drv_exit(void)
{
platform_driver_unregister(&rtc_driver);
}
module_init(rtc_drv_init);
module_exit(rtc_drv_exit);
MODULE_LICENSE("GPL");
/*测试代码RTC_test.c*/
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<errno.h>
#define TIME_SET 0
#define TIME_GET 1
struct rtc_time{
int tm_sec;
int tm_min;
int tm_hour;
int tm_mday;
int tm_mon;
int tm_year;
int tm_wday;
int tm_yday;
int tm_isdst;
};
int main(int argc,char **argv)
{
int fd,cmd;
struct rtc_time set_time,get_time;
if(argc != 2){
printf("Usage:./RTC_test set/get\n");
exit(-1);
}
if((fd = open("/dev/rtc",O_RDWR)) == -1){
perror("/dev/rtc open failed");
exit(-1);
}
if(strcmp(argv[1],"set") == 0){
printf("设置时间(如2011 11 28 19 30 0):\n");
scanf("%d%d%d%d%d%d",&set_time.tm_year,&set_time.tm_mon,&set_time.tm_mday
,&set_time.tm_hour,&set_time.tm_min,&set_time.tm_sec);
cmd = TIME_SET;
ioctl(fd,cmd,&set_time);
}
else if(strcmp(argv[1],"get") == 0){
cmd = TIME_GET;
while(1){
ioctl(fd,cmd,&get_time);
printf("北京时间:%4d-%02d-%02d,%02d:%02d:%02d",get_time.tm_year,get_time.tm_mon,get_time.tm_mday
,get_time.tm_hour,get_time.tm_min,get_time.tm_sec);
fflush(stdout);
usleep(500000);
printf("\r");
}
}
return 0;
}