Версия ядра Linux: 3.5
Система Linux содержит два времени: системное время и время RTC.
Системное время: это время, поддерживаемое таймером основного чипа. Как правило, в качестве основы синхронизации системного времени выбирается наиболее точный таймер на чипе, чтобы избежать больших отклонений во времени после длительной работы системы. . Особенность в том, что он не сохраняется после выключения питания.
Время RTC: относится к времени, поддерживаемому внутри чипа RTC, включенного в систему. Чип RTC имеет двойной механизм питания: батарея + питание системы. Когда система работает нормально, она питается от системы, а когда система выключена, она питается от батареи. Таким образом, время RTC может продолжать работать нормально после отключения питания системы.
Каждый раз при запуске системы Linux драйвер RTC будет обнаруживаться и монтироваться в процессе запуска. После монтирования время будет автоматически считываться с чипа RTC и устанавливаться на системное время. Впоследствии, если нет явной команды для управления операциями чтения и записи часов реального времени, система больше не будет получать или синхронизировать время установки от часов реального времени.
Такие команды, как дата и время в командах Linux, используются для установки системного времени.,иhwclockКоманды используются для установки, чтения и записи.RTCвременный。
Войдите в корневой каталог ядра и введите: make Menuconfig, чтобы войти в меню конфигурации ядра:
Войдите в меню драйвера реального времени RTC согласно параметрам:
Device Drivers ---> [*] Real Time Clock ---> --- Real Time Clock │ │ │ │ [*] Set system time from RTC on startup and resume │ │ │ │ (rtc0) RTC used to set the system time │ │ │ │ [ ] RTC debug support │ │ │ │ *** RTC interfaces *** │ │ │ │ [*] /sys/class/rtc/rtcN (sysfs) [*] /proc/driver/rtc (procfs for rtc0) │ │ │ │ [*] /dev/rtcN (character devices) │ │ │ │ [ ] RTC UIE emulation on dev interface │ │ │ │ < > Test driver/device │ │ │ │ *** I2C RTC drivers *** │ │ │ │ < > Dallas/Maxim DS1307/37/38/39/40, ST M41T00, EPSON RX-8025 < > Dallas/Maxim DS1374 │ │ │ │ < > Dallas/Maxim DS1672 │ │ │ │ < > Dallas/Maxim DS3232 │ │ │ │ < > Maxim MAX6900 │ │ │ │ < > Ricoh R2025S/D, RS5C372A/B, RV5C386, RV5C387A < > Intersil ISL1208 │ │ │ │ < > Intersil ISL12022 │ │ │ │ < > Xicor/Intersil X1205 │ │ │ │ < > Philips PCF8563/Epson RTC8564 │ │ │ │ < > Philips PCF8583 │ │ │ │ < > ST M41T62/65/M41T80/81/82/83/84/85/87 < > TI BQ32000 │ │ │ │ < > Seiko Instruments S-35390A │ │ │ │ < > Ramtron FM3130 │ │ │ │ < > Epson RX-8581 │ │ │ │ < > Epson RX-8025SA/NB │ │ │ │ < > EM Microelectronic EM3027 < > Micro Crystal RTC │ │ │ │ *** SPI RTC drivers *** │ │ │ │ < > ST M41T93 │ │ │ │ < > ST M41T94 │ │ │ │ < > Dallas/Maxim DS1305/DS1306 │ │ │ │ < > Dallas/Maxim DS1390/93/94 *** Platform RTC drivers *** │ │ │ │ < > PC-style 'CMOS' │ │ │ │ < > Dallas DS1286 │ │ │ │ < > Dallas DS1511 │ │ │ │ < > Maxim/Dallas DS1553 *** on-CPU RTC drivers *** │ │ │ │ <*> Samsung S3C series SoC RTC │ │ │ │ < > ARM AMBA PL030 RTC │ │ │ │ < > ARM AMBA PL031 RTC │ │ │ └──────────────────────────────
В зависимости от конфигурации ядра известны три части информации (параметры конфигурации выделены красным):
1. Системное время по умолчанию получает время из RTC0 и устанавливает его.
(rtc0 представляет первый драйвер RTC в /dev. Если установлен второй драйвер RTC, он будет представлен как rtc1 и т. д.)
2. Используйте proc для просмотра информации RTC. По умолчанию ее можно получить только с узла rtc0 (первый драйвер RTC в системе).
[root@XiaoLong /]#cat /proc/driver/rtc
3. По умолчанию ядро выбирает RTC, поставляемый с самим процессором, в качестве системных часов реального времени.
Исходный код драйвера\linux-3.5\drivers\rtc\ rtc-s3c.cЭто драйвер RTC, написанный Samsung.。
date — это команда, используемая для отображения или установки системной даты и времени.
Формат использования команды: date [параметр]... [+формат]
Параметры, которые может принимать команда, следующие:
Пример использования: date '+%A' Обязательные параметры: %H Часы (выражены как 00-23). %I Часы (выражены как 01-12). %K Часы (выражены как 0–23). %l Часы (выражены в цифрах 0–12). %M Минуты (выражены как 00-59). %P Утро или вечер. %r Время (включая часы, минуты и секунды, часы выражаются в 12-часовом формате AM/PM). %s Всего секунд. Время начала: 1 января 1970 г. 00:00:00 UTC。 %S Секунды (выраженные на местной идиоме). %T Время (включая часы, минуты и секунды, часы выражаются в 24-часовом формате). %X Время (выраженное на местной идиоме). %Z городской район. %a Аббревиатура недели. %A Полное название недели. %b Аббревиатура английского названия месяца. %B Полное английское название месяца. %c Дата и время. Ввод только команды даты приведет к тому же результату. %d Дата (выраженная как 01-31). %D Дата (включая год, месяц и день). %j День года. %m Месяц (выраженный как 01–12). %U Количество недель в году. %w Количество дней в неделе: 0 — воскресенье, 1 — понедельник и т. д. %x Дата (выраженная на местном языке). %y Год (выраженный как 00–99). %Y Год (выраженный четырьмя цифрами). %n При отображении вставьте новую строку. %t При отображении вставьте вкладки. MM Месяц (обязательно) DD Дата (обязательно) hh часы (обязательно) mm минут (обязательно) ss секунды (необязательно) Выберите параметры: -d<нить> Отображает дату и время, на которые указывает строка. Строке должны предшествовать и следовать двойные кавычки. -s<нить> Установите дату и время на основе строки. Строке должны предшествовать и следовать двойные кавычки. -u Отображать время по Гринвичу. --help Онлайн-помощь. --version Показать информацию о версии |
---|
Режим системного времени
[root@XiaoLong /]# date -s "2018-07-28 14:21:22" //Установить все даты и время [root@XiaoLong /]# date -s "14:30:22" //Установить только Time [root@XiaoLong /]# date -s «2017-07-28» //Установка даты, время по умолчанию — 00:00:00 |
---|
Пример формата
[root@XiaoLong /]# date -r app // Опция -r позволяет распечатать время последнего изменения указанного файла. Пт, 29 апреля, 05:17:34 UTC 2016 [root@XiaoLong /]# date -d 23: 39:00 //Распечатываем время в указанном формате (только эффект печати не имеет других эффектов) Сб, 30 апреля 23:39:00 UTC 2016 [root@XiaoLong /]# date -s 12:20:30 //Установим системное время на 12:20:30 Сб, 30 апреля 12:20:30 UTC 2016 [root@XiaoLong /]# date -s 2016.04.30-23:20:10 / /Установить системное время на 23:20:10 30 апреля 2016 г., суббота, 30 апреля. 23:20:10 UTC 2016 |
---|
1. Синхронизируйте время RTC с системным временем.
[root@XiaoLong /]# hwclock -s |
---|
Чтобы автоматически синхронизировать время RTC с системным временем при запуске, вы можете добавить команду hwclock -s в профиль или файл rcS.
2. Получите и отобразите время RTC.
[root@XiaoLong /]# hwclock -r Sun May 1 00:09:36 2016 0.000000 seconds
3. Синхронизируйте системное время с RTC для установки времени.
[root@XiaoLong /]# hwclock -w
4. Просмотр информации RTC
[root@XiaoLong /]# cat /proc/driver/rtc rtc_time : 00:09:27 rtc_date : 2016-05-01 alrm_time : 23:24:07 alrm_date : 2016-05-01 alarm_IRQ : no alrm_pending : no update IRQ enabled : no periodic IRQ enabled : no periodic IRQ frequency : 1 max user IRQ frequency : 32768 24hr : yes periodic_IRQ : no
1. /drivers/rtc/class.c Этот файл регистрирует класс RTC в ядре модели устройства Linux, а затем предоставляет драйверу интерфейс регистрации/отмены регистрации.
2. /drivers/rtc/rtc-dev.c Этот файл определяет основные функции работы с файлом устройства, такие как: открытие, чтение и т. д.
3. /drivers/rtc/interface.c Как следует из названия, этот файл в основном обеспечивает функции интерфейса между пользовательской программой и драйвером RTC. Пользовательская программа обычно взаимодействует с драйвером RTC через ioctl. по каждой команде ioctl определены здесь.
4. /drivers/rtc/rtc-sysfs.c связан с sysfs.
5. /drivers/rtc/rtc-proc.c связан с файловой системой proc.
6. /include/linux/rtc.h определяет структуры данных, относящиеся к RTC.
Место хранения кода драйвера RTC, который поставляется с исходным кодом ядра Linux:
Каталог \linux-3.5\drivers\rtc\ полон примеров кодов драйверов RTC. Среди них: rtc-s3c.c — драйвер RTC, написанный Samsung. |
---|
1. Функция регистрации структуры RTC
struct rtc_device *rtc_device_register( const char *name, //имя часов RTC struct device *dev, //указатель устройства. Этот указатель необходимо получить через устройство платформы. const struct rtc_class_ops *ops, //модуль структуры сбора операций с файлами rtc *владелец ) //Владелец драйвера. Заполните: THIS_MODULE |
---|
Пример использования: rtc_device_register("tiny4412_rtc",&pdev->dev, &tiny4412_rtcops,THIS_MODULE);
После успешной регистрации с помощью функции rtc_device_register,существовать/dev/Вы можете увидеть это нижеrtcxузел устройства(xдаrtcпорядковый номер)。
2. Функция выхода из системы RTC
void rtc_device_unregister(struct rtc_device *rtc)
После анализа формальных параметров функции регистрации RTC необходимо выполнить регистрацию подсистемы RTC через структуру платформенного устройства. Регистрация rtc выполняется в функции проверки на стороне драйвера платформенного устройства, а затем выполняется отмена регистрации. в функции удаления требования к оборудованию RTC передаются со стороны устройства RTC на сторону драйвера.
rtc_class_ops Эта структура представляет собой базовую операционную функцию, реализуемую драйвером RTC. Драйвер связывает реализуемые им функции с ядром RTC, инициализируя такую структуру. Большинство функций здесь должны быть реализованы драйвером. Более того, эти функции работают на базовом оборудовании и относятся к функциям самого низкого уровня. Этот интерфейс драйвера связан с командой hwclock прикладного уровня, а базовые функции RTC можно вызывать с помощью команды hwclock.
struct rtc_class_ops { int (*open)(struct device *); //Открыть void (*release)(struct device *); int (*ioctl)(struct device *, unsigned int, unsigned long); /*функция ioctl*/ int (*read_time)(struct device *, struct rtc_time *); //время чтения int (*set_time)(struct device *, struct rtc_time *); //Установим время int (*read_alarm)(struct device *, struct rtc_wkalrm *); //Читаем будильник int (*set_alarm)(struct device *, struct rtc_wkalrm *); //Установим будильник int (*proc)(struct device *, struct seq_file *); //интерфейс процесса int (*set_mmss)(struct device *, unsigned long secs); //Установим второй юнит int (*read_callback)(struct device *, int data); //функция обратного вызова int (*alarm_irq_enable)(struct device *, unsigned int enabled); //Включение прерывания будильника };
Драйверам в подсистеме RTC обычно требуется реализовать только функциональные интерфейсы для установки и получения времени. Пользователи могут передать соответствующую команду через функцию ioctl на уровне приложения, чтобы вызвать интерфейс уровня драйвера для получения и настройки времени.
Две часто используемые команды:
#define RTC_RD_TIME _IOR(RTC_MAGIC, 0x09, struct rtc_time) /* Чтение времени RTC */ #define RTC_SET_TIME _IOW(RTC_MAGIC, 0x0a, struct rtc_time) /* Установка времени RTC */ //Все поддерживаемые команды находятся в интерфейсе.c. В документации есть примеры использования. Эти команды можно использовать, когда пользователи пишут свой собственный код прикладного уровня. RTC_ALM_READ rtc_read_alarm Чтение времени сигнала RTC_ALM_SET rtc_set_alarm Установка времени сигнала RTC_RD_TIME rtc_read_time Чтение времени и даты RTC_SET_TIME rtc_set_time Установка времени и даты RTC_PIE_ON RTC_PIE_OFF rtc_irq_set_state Функция переключения глобального прерывания RTC RTC_AIE_ON RTC_AIE_OFF rtc_alarm_irq_enable Включение и отключение прерывания тревоги RTC RTC_UIE_OFF RTC_UIE_ON rtc_update_irq_enable Включение и отключение прерывания обновления RTC RTC_IRQP_SET rtc_irq_set_freq Установка частоты прерывания |
---|
rtc_time представляет время и дату, записанные RTC. Время и дата, считанные с устройства RTC, хранятся в этой структуре.
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; //Действительно летнее время };
struct rtc_wkalrm { unsigned char enabled; /* Переключатель включения будильника 0 = alarm disabled, 1 = alarm enabled */ unsigned char pending; /* Статус обработки сигнала будильника 0 = alarm not pending не производится, 1 = alarm pending Генерируется сигнал тревоги*/ struct rtc_time time; /* Время установки будильника */ };
Чтобы протестировать собственный драйвер RTC, вам необходимо заранее удалить драйвер RTC, идущий в комплекте с ядром, перекомпилировать и запрограммировать ядро, а затем установить и протестировать его.
На примере платы разработки tiny4412 удалите встроенный драйвер rtc.
1. Войдите в меню конфигурации ядра: make menuconfig
Device Drivers --->
[*] Real Time Clock --->
2. Перекомпилируем ядро, а затем перепрограммируем ядро на SD или EMMC:
[root@wbyq boot]# ./123.sh записано 9288+1 операций чтения и записано 9288+1 операций записи, скопировано 4755752 байта (4,8 МБ), 33,2798 секунды, 143 КБ/сек. |
---|
По умолчанию без драйвера RTC системное время получается начиная с 1970 года:
Следующий код демонстрирует только структуру регистрации на основе RTC.
1. Код устройства RTC:
#include "linux/module.h"
#include "linux/init.h"
#include <linux/platform_device.h>
/*
* device Сторона устройства
*/
//Освобождаем шину платформы
static void pdev_release(struct device *dev)
{
printk("rtc_pdev:the rtc_pdev is close!!!\n");
}
/*Сторона устройства Структура*/
struct platform_device rtc_pdev= /*Структура устройства, имя устройства очень важно!*/
{
.name = "tiny4412rtc", /*Имя устройства*/
.id = -1, /*-1 означает, что имя устройства здесь будет указано после успешного создания. Если значение равно 0 или 1, имя устройства будет myled.0, myled.1...*/.
.dev = /*Вызывается при удалении драйвера*/
{
.release = pdev_release,/*Освободить ресурсы*/
},
};
/*платформа Сторона функция входа в устройство*/
static int __init plat_dev_init(void)
{
platform_device_register(&rtc_pdev);/*зарегистрироватьсяплатформа Сторона устройства*/
return 0;
}
/*платформа Сторона функция экспорта устройства */
static void __exit plat_dev_exit(void)
{
platform_device_unregister(&rtc_pdev);/*Выйтиплатформа Сторона устройства*/
}
module_init(plat_dev_init);
module_exit(plat_dev_exit);
MODULE_LICENSE("GPL");
2. Код драйвера RTC
#include <linux/module.h> /*Связано с модулем привода*/
#include <linux/init.h>
#include <linux/fs.h> /*Коллекция файловых операций*/
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/miscdevice.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/interrupt.h> /*Файлы заголовков, связанные с прерываниями*/
#include <linux/irq.h> /*Файлы заголовков, связанные с прерываниями*/
#include <linux/gpio.h> /*Аппаратное обеспечение->Имена и адреса регистров определены*/
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/timer.h> /*Таймер ядра*/
#include <asm-generic/poll.h>
#include <linux/poll.h> /* механизм опроса*/
#include <linux/platform_device.h> /* Заголовочные файлы, связанные с драйверами устройств платформы*/
#include <linux/rtc.h>
static int tiny4412_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
{
printk("Время получено успешно\n");
return 0;
}
static int tiny4412_rtc_settime(struct device *dev, struct rtc_time *tm)
{
printk("Время установлено успешно\n");
return 0;
}
static int tiny4412_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)
{
printk("Вызов getalarm успешен\n");
return 0;
}
static int tiny4412_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
{
printk("Вызов getalarm успешен\n");
return 0;
}
static int tiny4412_rtc_proc(struct device *dev, struct seq_file *seq)
{
printk("вызов процедуры успешен\n");
return 0;
}
static int tiny4412_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
printk("alarm_irq_enable был успешно вызван\n");
return 0;
}
static int tiny4412_rtc_ioctl(struct device *dev, unsigned int cmd,unsigned long arg)
{
printk("вызов ioctl успешен\n");
return 0;
}
/*Операция с файлом RTC*/
static const struct rtc_class_ops tiny4412_rtcops = {
.read_time = tiny4412_rtc_gettime,
.set_time = tiny4412_rtc_settime,
.read_alarm = tiny4412_rtc_getalarm,
.set_alarm = tiny4412_rtc_setalarm,
.proc = tiny4412_rtc_proc,
.alarm_irq_enable = tiny4412_rtc_alarm_irq_enable,
.ioctl = tiny4412_rtc_ioctl,
};
struct rtc_device *rtc=NULL;
/*Функция, которая успешно выполняется при совпадении устройства — функция исследования ресурса*/
static int drv_probe(struct platform_device *pdev)
{
rtc = rtc_device_register("tiny4412_rtc",&pdev->dev, &tiny4412_rtcops,THIS_MODULE);
if(rtc==NULL)
printk("Ошибка регистрации драйвера RTC\n");
else
{
printk("Регистрация драйвера RTC прошла успешно\n");
}
return 0;
}
static int drv_remove(struct platform_device *dev)/*Эта функция вызывается при удалении устройства*/
{
rtc_device_unregister(rtc);
printk("Драйвер RTC успешно удален\n");
return 0;
}
/*Структура драйвера устройства платформы — содержит имя устройства, соответствующее зонду*/
struct platform_driver drv=
{
.probe = drv_probe, /*Необходимо создать функцию зонда, которая будет управлять устройством*/
.remove = drv_remove, /*Создаем функцию удаления для выхода из устройства*/
.driver =
{
.name = "tiny4412rtc",/*Имя устройства,используется с Сторона устройствоматч (очень важно)*/
},
};
/*Функция входа драйвера платформы*/
static int __init plat_drv_init(void)
{
platform_driver_register(&drv);/*зарегистрироватьсяплатформаводить машину*/
return 0;
}
/*Функция экспорта драйвера платформы*/
static void __exit plat_drv_exit(void)
{
platform_driver_unregister(&drv);/*выпускатьплатформаводить машину*/
}
module_init(plat_drv_init); /*Вход модуля драйвера*/
module_exit(plat_drv_exit); /*Экспорт модуля драйвера*/
MODULE_LICENSE("GPL"); /*Положение о водительских правах*/
3. Установите драйвер RTC.
4. Просмотр узла устройства сгенерированного RTC.
5. Просмотр информации о RTC
При просмотре файла /proc/driver/rtc интерфейсы функций базового драйвера также вызываются один за другим. Однако только что написанный драйвер RTC не идеален, поэтому полученная информация неверна и является значением по умолчанию.
6. Установите тесты команд, связанные со временем RTC.
Посредством тестирования команд как установка времени, так и получение времени вызывают базовый интерфейс функции RTC, а оставшаяся работа заключается в улучшении кода драйвера.
Предыдущий шаг завершил написание структуры кода драйвера RTC. На этом этапе мы не добавляем аппаратный код RTC и используем программное обеспечение для имитации передачи времени на прикладной уровень.
Примечание. Преобразование времени RTC в ядре рассчитывается от: 1900, а месяц начинается с 0.
При присвоении значения структуре rtc нужно вычесть 1900 из обычного года и 1 из месяца.
Пример назначения:
//Эту функцию можно вызвать через команду RTC_RD_TIME ioctl прикладного уровня
static int tiny4412_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
{
rtc_tm->tm_year=2018-1900; //Год
rtc_tm->tm_mon=8-1; //луна
rtc_tm->tm_mday=18; //день
rtc_tm->tm_hour=18; //час
rtc_tm->tm_min=18; //точка
rtc_tm->tm_sec=18;//Второй
printk("Успешно получено время с нижнего уровня RTC!\n");
return 0;
}
Время, полученное прикладным уровнем, выглядит следующим образом:
Улучшенный код драйвера устройства RTC.
#include <linux/module.h> /*Связано с модулем привода*/
#include <linux/init.h>
#include <linux/fs.h> /*Коллекция файловых операций*/
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/miscdevice.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/interrupt.h> /*Файлы заголовков, связанные с прерываниями*/
#include <linux/irq.h> /*Файлы заголовков, связанные с прерываниями*/
#include <linux/gpio.h> /*Аппаратное обеспечение->Имена и адреса регистров определены*/
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/timer.h> /*Таймер ядра*/
#include <asm-generic/poll.h>
#include <linux/poll.h> /* механизм опроса*/
#include <linux/platform_device.h> /* Заголовочные файлы, связанные с драйверами устройств платформы*/
#include <linux/rtc.h>
//Эту функцию можно вызвать через команду RTC_RD_TIME ioctl прикладного уровня
static int tiny4412_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
{
rtc_tm->tm_year=2018-1900; //Год
rtc_tm->tm_mon=8-1; //луна
rtc_tm->tm_mday=18; //день
rtc_tm->tm_hour=18; //час
rtc_tm->tm_min=18; //точка
rtc_tm->tm_sec=18;//Второй
printk("Успешно получено время с нижнего уровня RTC!\n");
return 0;
}
//Эту функцию можно вызвать через команду RTC_SET_TIME ioctl уровня приложения
static int tiny4412_rtc_settime(struct device *dev, struct rtc_time *tm)
{
printk("Время получения RTC: %d-%d-%d %d-%d-%d\n",1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
return 0;
}
//Получаем время будильника
static int tiny4412_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)
{
alrm->enabled=0; //Будильник по умолчанию выключен
alrm->time.tm_year=2018-1900; //Год
alrm->time.tm_mon=8-1; //луна
alrm->time.tm_mday=18; //день
alrm->time.tm_hour=18; //час
alrm->time.tm_min=18; //точка
alrm->time.tm_sec=18; //Второй
printk("Успешно получено время будильника с нижнего уровня RTC!\n");
return 0;
}
//Установить время будильника
static int tiny4412_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
{
printk("Будильник RTC установлен успешно\n");
return 0;
}
//интерфейс процессавызов
static int tiny4412_rtc_proc(struct device *dev, struct seq_file *seq)
{
printk("вызов процедуры успешен\n");
return 0;
}
//Включение прерывания будильника
static int tiny4412_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
printk("alarm_irq_enable был успешно вызван\n");
return 0;
}
//Может реализовывать пользовательские команды
static int tiny4412_rtc_ioctl(struct device *dev, unsigned int cmd,unsigned long arg)
{
printk("вызов ioctl успешен\n");
return 0;
}
/*Операция с файлом RTC*/
static const struct rtc_class_ops tiny4412_rtcops = {
.read_time = tiny4412_rtc_gettime,
.set_time = tiny4412_rtc_settime,
.read_alarm = tiny4412_rtc_getalarm,
.set_alarm = tiny4412_rtc_setalarm,
.proc = tiny4412_rtc_proc,
.alarm_irq_enable = tiny4412_rtc_alarm_irq_enable,
.ioctl = tiny4412_rtc_ioctl,
};
struct rtc_device *rtc=NULL;
/*Функция, которая успешно выполняется при совпадении устройства — функция исследования ресурса*/
static int drv_probe(struct platform_device *pdev)
{
rtc = rtc_device_register("tiny4412_rtc",&pdev->dev, &tiny4412_rtcops,THIS_MODULE);
if(rtc==NULL)
printk("Ошибка регистрации драйвера RTC\n");
else
{
printk("Регистрация драйвера RTC прошла успешно\n");
}
return 0;
}
static int drv_remove(struct platform_device *dev)/*Эта функция вызывается при удалении устройства*/
{
rtc_device_unregister(rtc);
printk("Драйвер RTC успешно удален\n");
return 0;
}
/*Структура драйвера устройства платформы — содержит имя устройства, соответствующее зонду*/
struct platform_driver drv=
{
.probe = drv_probe, /*Необходимо создать функцию зонда, которая будет управлять устройством*/
.remove = drv_remove, /*Создаем функцию удаления для выхода из устройства*/
.driver =
{
.name = "tiny4412rtc",/*Имя устройства,используется с Сторона устройствоматч (очень важно)*/
},
};
/*Функция входа драйвера платформы*/
static int __init plat_drv_init(void)
{
platform_driver_register(&drv);/*зарегистрироватьсяплатформаводить машину*/
return 0;
}
/*Функция экспорта драйвера платформы*/
static void __exit plat_drv_exit(void)
{
platform_driver_unregister(&drv);/*выпускатьплатформаводить машину*/
}
module_init(plat_drv_init); /*Вход модуля драйвера*/
module_exit(plat_drv_exit); /*Экспорт модуля драйвера*/
MODULE_LICENSE("GPL"); /*Положение о водительских правах*/
Результаты испытаний установки:
[root@XiaoLong /code]# date
Thu Jan 1 00:00:13 UTC 1970
[root@XiaoLong /code]# insmod plat_rtc_device.ko
[root@XiaoLong /code]# insmod plat_rtc_drver.ko
[ 24.350000] Получение времени от нижнего уровня RTC успешно!
[ 24.350000] Успешно получено время будильника с нижнего уровня RTC!
[ 24.350000] Получение времени от нижнего уровня RTC успешно!
[ 24.350000] tiny4412rtc tiny4412rtc: rtc core: registered tiny4412_rtc as rtc0
[ 24.350000] Регистрация драйвера RTC прошла успешно
[root@XiaoLong /code]# cat /proc/driver/rtc
[ 37.085000] Получение времени от нижнего уровня RTC успешно!
[ 37.085000] вызов процедуры успешен
rtc_time : 18:18:18
rtc_date : 2018-08-18
alrm_time : 18:18:18
alrm_date : 2018-08-18
alarm_IRQ : no
alrm_pending : no
update IRQ enabled : no
periodic IRQ enabled : no
periodic IRQ frequency : 1
max user IRQ frequency : 64
24hr : yes
[root@XiaoLong /code]#
[root@XiaoLong /code]# hwclock -s
[ 58.600000] Получение времени от нижнего уровня RTC успешно!
[root@XiaoLong /code]# hwclock -r
[ 61.020000] Получение времени от нижнего уровня RTC успешно!
Sat Aug 18 18:18:18 2018 0.000000 seconds
[root@XiaoLong /code]# hwclock -w
[ 62.920000] Время получения RTC: 18 июля 2018 г. 18-18-22
[ 62.920000] Получение времени от нижнего уровня RTC успешно!
[ 62.920000] Alarm_irq_enable был успешно вызван
[root@XiaoLong /code]# date
Sat Aug 18 18:18:24 UTC 2018
Если уровень приложения хочет взаимодействовать с драйвером RTC, он может использовать некоторые команды, специфичные для функции ioctl.
Обычно используемые команды ioctl в подсистеме RTC:
//Все поддерживаемые команды Примеры использования есть в файлеinterface.c. Эти команды можно использовать, когда пользователи сами пишут код прикладного уровня.
RTC_ALM_READ rtc_read_alarm Прочитать время будильника
RTC_ALM_SET rtc_set_alarm Установить время будильника
RTC_RD_TIME rtc_read_time Чтение времени и даты
RTC_SET_TIME rtc_set_time Установите время и дату
RTC_PIE_ON RTC_PIE_OFF rtc_irq_set_state Функция включения и выключения глобального прерывания RTC
RTC_AIE_ON RTC_AIE_OFF rtc_alarm_irq_enable Включение и отключение прерывания тревоги RTC
RTC_UIE_OFF RTC_UIE_ON rtc_update_irq_enable Включить и отключить прерывание обновления RTC
RTC_IRQP_SET rtc_irq_set_freq Установить частоту прерываний
Пример кода:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/rtc.h>
struct rtc_time time; //сохраняем значение времени
int main(int argc,char **argv)
{
if(argc!=2)
{
printf("Формат параметра:/dev/rtc\r\n");
return;
}
int fd=open(argv[1],O_RDWR); // 2==O_RDWR
if(fd<0)
{
printf("Не удалось открыть файл драйвера устройства!\r\n");
return 0;
}
time.tm_year=2017;
time.tm_mon=10;
time.tm_mday=13;
time.tm_hour=21;
time.tm_min=10;
time.tm_sec=10;
//Примечание: год, месяц и день должны быть заполнены обычным образом, иначе базовая функция не будет успешно вызвана.
ioctl(fd,RTC_SET_TIME,&time); //Нижний уровень реализует функцию ioctl и устанавливает время RTC
while(1)
{
ioctl(fd,RTC_RD_TIME,&time);
printf("%d-%d-%d %d:%d:%d\r\n",time.tm_year,time.tm_mon,time.tm_mday,time.tm_hour,time.tm_min,time.tm_sec);
sleep(1);
}
}
Некоторые аппаратные настройки часов реального времени RTC отсчитывают только секунды и не обеспечивают настройки времени в формате года, месяца, дня, часа, минуты и секунды. В этом случае вам необходимо самостоятельно преобразовать стандартное время.
Преобразование стандартного времени в секунды:
/*
* С 01.01.1970 года происходит перевод дат по григорианскому календарю в секунды.
*/
int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time)
{
*time = mktime(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
return 0;
}
Все приведенные выше коды представляют собой аналоговые часы. Чтобы узнать, как использовать структуру RTC, следующие коды добавляют фактическое оборудование RTC для достижения полной синхронизации RTC.
Код драйвера DS1302:
#include <linux/module.h> /*Связано с модулем привода*/
#include <linux/init.h>
#include <linux/fs.h> /*Коллекция файловых операций*/
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/miscdevice.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/interrupt.h> /*Файлы заголовков, связанные с прерываниями*/
#include <linux/irq.h> /*Файлы заголовков, связанные с прерываниями*/
#include <linux/gpio.h> /*Аппаратное обеспечение->Имена и адреса регистров определены*/
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/timer.h> /*Таймер ядра*/
#include <asm-generic/poll.h>
#include <linux/poll.h> /* механизм опроса*/
#include <linux/platform_device.h> /* Заголовочные файлы, связанные с драйверами устройств платформы*/
#include <linux/rtc.h>
#include <linux/gpio.h>
#include <mach/gpio.h>
#include <plat/gpio-cfg.h>
#include <linux/delay.h>
/*--------------------------------Коды операций, связанные с DS1302------------ ----------------------------------*/
static unsigned char RTC_bin2bcd(unsigned val)
{
return ((val/10)<<4)+val%10;
}
static unsigned RTC_bcd2bin(unsigned char val)
{
return (val&0x0f)+(val>>4)*10;
}
/*
Функция: инициализация DS1302
Аппаратное подключение Tiny4412:
CLK :GPB_4
DAT :GPB_5
RST :GPB_6
*/
void DS1302IO_Init(void)
{
/*1. Зарегистрировать GPIO*/
gpio_request(EXYNOS4_GPB(4), "DS1302_CLK");
gpio_request(EXYNOS4_GPB(5), "DS1302_DAT");
gpio_request(EXYNOS4_GPB(6), "DS1302_RST");
/*2. Настройте режим порта GPIO*/
s3c_gpio_cfgpin(EXYNOS4_GPB(4), S3C_GPIO_OUTPUT); //часколокол
s3c_gpio_cfgpin(EXYNOS4_GPB(5), S3C_GPIO_OUTPUT); //данные
// s3c_gpio_cfgpin(EXYNOS4_GPB(2), S3C_GPIO_INPUT); //режим ввода
s3c_gpio_cfgpin(EXYNOS4_GPB(6), S3C_GPIO_OUTPUT); //Перезагрузить
/*3. Поднимите порт GPIO*/
gpio_set_value(EXYNOS4_GPB(4), 1); //CLK
gpio_set_value(EXYNOS4_GPB(5), 1); //DAT
gpio_set_value(EXYNOS4_GPB(6), 1); //RST
gpio_set_value(EXYNOS4_GPB(6), 0); //Устанавливаем низкий уровень на выводе RST
gpio_set_value(EXYNOS4_GPB(4), 0); //Устанавливаем низкий уровень на выводе SCK
}
//#define RTC_CMD_READ 0x81 /* Read command */
//#define RTC_CMD_WRITE 0x80 /* Write command */
//#define RTC_ADDR_RAM0 0x20 /* Address of RAM0 */
//#define RTC_ADDR_TCR 0x08 /* Address of trickle charge register */
//#define RTC_ADDR_YEAR 0x06 /* Address of year register */
//#define RTC_ADDR_DAY 0x05 /* Address of day of week register */
//#define RTC_ADDR_MON 0x04 /* Address of month register */
//#define RTC_ADDR_DATE 0x03 /* Address of day of month register */
//#define RTC_ADDR_HOUR 0x02 /* Address of hour register */
//#define RTC_ADDR_MIN 0x01 /* Address of minute register */
//#define RTC_ADDR_SEC 0x00 /* Address of second register */
//Определение адреса DS1302
#define ds1302_sec_add 0x80 //Второй адрес данных
#define ds1302_min_add 0x82 //адрес точки данных
#define ds1302_hr_add 0x84 //адрес часовданных
#define ds1302_date_add 0x86 //деньдата адреса
#define ds1302_month_add 0x88 //адрес лунных данных
#define ds1302_day_add 0x8a //адрес недельных данных
#define ds1302_year_add 0x8c //Адрес данных Бога
#define ds1302_control_add 0x8e //Адрес управляющих данных
#define ds1302_charger_add 0x90
#define ds1302_clkburst_add 0xbe
//Начальное определение времени
static unsigned char time_buf[8] = {0x20,0x10,0x06,0x01,0x23,0x59,0x55,0x02};//Начальное время: 23:59:55 1 июня 2010 г. Вторник
static unsigned char readtime[14];//текущее время
static unsigned char sec_buf=0; //Второйкэш
static unsigned char sec_flag=0; //Второй флаг
//Записываем один байт данных в DS1302
static void ds1302_write_byte(unsigned char addr, unsigned char d)
{
unsigned char i;
gpio_set_value(EXYNOS4_GPB(6), 1); //Запускаем шину DS1302
//Записываем целевой адрес: addr
addr = addr & 0xFE; //Младший бит равен нулю, запись, когда бит регистра 0 равен 0, чтение, когда он равен 1
for(i=0;i<8;i++)
{
if(addr&0x01){gpio_set_value(EXYNOS4_GPB(5), 1);}
else{gpio_set_value(EXYNOS4_GPB(5), 0);}
gpio_set_value(EXYNOS4_GPB(4), 1); //генерируем часы
gpio_set_value(EXYNOS4_GPB(4), 0);
addr=addr >> 1;
}
//Запись данных: d
for(i=0;i<8;i++)
{
if(d & 0x01) {gpio_set_value(EXYNOS4_GPB(5), 1);}
else {gpio_set_value(EXYNOS4_GPB(5), 0);}
gpio_set_value(EXYNOS4_GPB(4), 1); //генерируем часы
gpio_set_value(EXYNOS4_GPB(4), 0);
d = d >> 1;
}
gpio_set_value(EXYNOS4_GPB(6), 0); //Остановим шину DS1302
}
//Читаем один байт данных из DS1302
static unsigned char ds1302_read_byte(unsigned char addr)
{
unsigned char i,temp;
gpio_set_value(EXYNOS4_GPB(6), 1);//Запускаем шину DS1302
//Записываем целевой адрес: addr
addr=addr | 0x01; //Младший бит высокий, запись, когда бит регистра 0 равен 0, чтение, когда он равен 1
for(i=0; i<8; i++)
{
if(addr & 0x01){gpio_set_value(EXYNOS4_GPB(5), 1);}
else {gpio_set_value(EXYNOS4_GPB(5), 0);}
gpio_set_value(EXYNOS4_GPB(4), 1);
gpio_set_value(EXYNOS4_GPB(4), 0);
addr=addr >> 1;
}
s3c_gpio_cfgpin(EXYNOS4_GPB(5), S3C_GPIO_INPUT); //режим ввода
//Выходные данные: температура
for(i=0; i<8; i++)
{
temp=temp>>1;
if(gpio_get_value(EXYNOS4_GPB(5))){temp |= 0x80;}
else{temp&=0x7F;}
gpio_set_value(EXYNOS4_GPB(4), 1);
gpio_set_value(EXYNOS4_GPB(4), 0);
}
s3c_gpio_cfgpin(EXYNOS4_GPB(5), S3C_GPIO_OUTPUT); //режим вывода
gpio_set_value(EXYNOS4_GPB(6), 0); //Остановим шину DS1302
return temp;
}
//Запись данных часов в DS302
static void ds1302_write_time(struct rtc_time *time)
{
ds1302_write_byte(ds1302_control_add,0x00); //Отключаем защиту от записи
ds1302_write_byte(ds1302_sec_add,0x80); //Приостанавливаем часы
//ds1302_write_byte(ds1302_charger_add,0xa9); //Капельная зарядка
/*Установить время RTC*/
//Поскольку год DS1302 можно установить только по двум последним цифрам, вам нужно использовать обычный год минус 2000, чтобы получить фактические две последние цифры.
ds1302_write_byte(ds1302_year_add,RTC_bin2bcd(time->tm_year-2000)); //Год
ds1302_write_byte(ds1302_month_add,RTC_bin2bcd(time->tm_mon)); //луна
ds1302_write_byte(ds1302_date_add,RTC_bin2bcd(time->tm_mday)); //день
ds1302_write_byte(ds1302_hr_add,RTC_bin2bcd(time->tm_hour)); //час
ds1302_write_byte(ds1302_min_add,RTC_bin2bcd(time->tm_min)); //точка
ds1302_write_byte(ds1302_sec_add,RTC_bin2bcd(time->tm_sec)); //Второй
//ds1302_write_byte(ds1302_day_add,RTC_bin2bcd(time->tm_wday)); //неделя time->tm_wdayдень недели
ds1302_write_byte(ds1302_control_add,0x80); //Открываем защиту от записи
}
static int DS1302_rtc_ioctl(struct device *dev, unsigned int cmd,unsigned long arg)
{
/*Установить время RTC*/
struct rtc_time time;
copy_from_user(&time,(const void __user *)arg,sizeof(struct rtc_time));
ds1302_write_time(&time);
return 0;
}
//Эта функция вызывается через команду RTC_RD_TIME ioctl уровня приложения
static int tiny4412_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
{
rtc_tm->tm_year=RTC_bcd2bin(ds1302_read_byte(ds1302_year_add))+2000; //Год
rtc_tm->tm_mon=RTC_bcd2bin(ds1302_read_byte(ds1302_month_add)); //луна
rtc_tm->tm_mday=RTC_bcd2bin(ds1302_read_byte(ds1302_date_add)); //день
rtc_tm->tm_hour=RTC_bcd2bin(ds1302_read_byte(ds1302_hr_add)); //час
rtc_tm->tm_min=RTC_bcd2bin(ds1302_read_byte(ds1302_min_add)); //точка
rtc_tm->tm_sec=RTC_bcd2bin((ds1302_read_byte(ds1302_sec_add))&0x7f);//Второй,Заблокируйте 7-ю цифру второго,избегайте превышения59
//time_buf[7]=ds1302_read_byte(ds1302_day_add); //неделя
return 0;
}
//Эта функция вызывается через команду RTC_SET_TIME ioctl уровня приложения
static int tiny4412_rtc_settime(struct device *dev, struct rtc_time *tm)
{
ds1302_write_time(tm);
return 0;
}
/*Операция с файлом RTC*/
static const struct rtc_class_ops DS1302_rtcops = {
.ioctl=DS1302_rtc_ioctl,
.read_time = tiny4412_rtc_gettime,
.set_time = tiny4412_rtc_settime
};
static struct rtc_device *rtc=NULL;
/*Функция, которая успешно выполняется при совпадении устройства — функция исследования ресурса*/
static int drv_probe(struct platform_device *pdev)
{
rtc = rtc_device_register("DS1302RTC",&pdev->dev, &DS1302_rtcops,THIS_MODULE);
if(rtc==NULL)
printk("Ошибка регистрации драйвера RTC 1\n");
else
{
printk("Регистрация драйвера RTC прошла успешно1\n");
}
/*1. Инициализировать порт GPIO*/
DS1302IO_Init();
msleep(10);
return 0;
}
static int drv_remove(struct platform_device *dev)/*Эта функция вызывается при удалении устройства*/
{
/*Освобождаем порт GPIO*/
gpio_free(EXYNOS4_GPB(4));
gpio_free(EXYNOS4_GPB(5));
gpio_free(EXYNOS4_GPB(6));
rtc_device_unregister(rtc);
printk("Драйвер RTC успешно удален\n");
return 0;
}
/*Структура драйвера устройства платформы — содержит имя устройства, соответствующее зонду*/
struct platform_driver drv=
{
.probe = drv_probe, /*Необходимо создать функцию зонда, которая будет управлять устройством*/
.remove = drv_remove, /*Создаем функцию удаления для выхода из устройства*/
.driver =
{
.name = "DS1302rtc",/*Имя устройства,используется с Сторона устройствоматч (очень важно)*/
},
};
/*Функция входа драйвера платформы*/
static int __init plat_drv_init(void)
{
platform_driver_register(&drv);/*зарегистрироватьсяплатформаводить машину*/
return 0;
}
/*Функция экспорта драйвера платформы*/
static void __exit plat_drv_exit(void)
{
platform_driver_unregister(&drv);/*выпускатьплатформаводить машину*/
}
module_init(plat_drv_init); /*Вход модуля драйвера*/
module_exit(plat_drv_exit); /*Экспорт модуля драйвера*/
MODULE_LICENSE("GPL"); /*Положение о водительских правах*/
Код стороны устройства DS1320
#include "linux/module.h"
#include "linux/init.h"
#include <linux/platform_device.h>
/*
* device Сторона устройства
*/
//Освобождаем шину платформы
static void pdev_release(struct device *dev)
{
printk("rtc_pdev:the rtc_pdev is close!!!\n");
}
/*Сторона устройства Структура*/
struct platform_device rtc_pdev= /*Структура устройства, имя устройства очень важно!*/
{
.name = "DS1302rtc", /*Имя устройства*/
.id = -1, /*-1 означает, что имя устройства здесь будет указано после успешного создания. Если значение равно 0 или 1, имя устройства будет myled.0, myled.1...*/.
.dev = /*Вызывается при удалении драйвера*/
{
.release = pdev_release,/*Освободить ресурсы*/
},
};
/*платформа Сторона функция входа в устройство*/
static int __init plat_dev_init(void)
{
platform_device_register(&rtc_pdev);/*зарегистрироватьсяплатформа Сторона устройства*/
return 0;
}
/*платформа Сторона функция экспорта устройства */
static void __exit plat_dev_exit(void)
{
platform_device_unregister(&rtc_pdev);/*Выйтиплатформа Сторона устройства*/
}
module_init(plat_dev_init);
module_exit(plat_dev_exit);
MODULE_LICENSE("GPL");