Hwclock 使用自定义 RTC 驱动程序显示错误输出

问题描述 投票:0回答:1

我正在尝试将 DS3231 与 Beaglebone Black 一起使用。我是用 buildroot (BusyBox v1.31.1) 构建的自定义系统,我还编写了我正在使用的驱动程序,这是一项大学作业,所以我不能使用预构建的系统或任何现有的驱动程序。

我正在使用 Linaro 的 Linux 交叉编译器 (v7.5.0 2019.12) 进行构建,并使用内核版本 5.10.65-ti-r30。

系统检测到RTC并且我的驱动程序探测成功,它在

/dev/rtc2
中生成一个RTC文件,我可以用
hwclock --systohc -f /dev/rtc2
在RTC中设置时间,但是每当我用
hwclock -f /dev/rtc2
读取它时,它说它是1秒之前Unix 纪元 (1969/12/31 23:59:59)。我还编写了一个用户空间程序,它使用
ioctl()
来读取和设置 RTC,它设置和读取时间没有任何问题,所以我知道我的驱动程序正在工作。

我还在

/dev/rtc0
中修改了内部 RTC 中的时间,
hwclock
毫无问题地输出其时间。

这是使用我的程序时我的 rtc 的输出,

hwclock

# ./a.out r /dev/rtc2
Time read: 2023/07/24 19:03:22
# hwclock -f /dev/rtc2
Wed Dec 31 23:59:59 1969  0.000000 seconds

hwclock
上显示的日期应该与我的计划相同。如果我将
pr_info()
语句放入驱动程序中来打印时间,它们就会打印正确的时间。

这是我的驱动程序的读取功能:

static int ds3231_read_time(struct device* dev, struct rtc_time* tm){
    struct i2c_client* client = to_i2c_client(dev);
    s32 ret;
    u8 reg;
    ret = i2c_smbus_read_byte_data(client, DS3231_REG_SEC);
    if(ret < 0){
        pr_err("Error %d during seconds read\n", ret);
        return ret;
    }
    reg = (u8)(ret);
    tm->tm_sec = 10 * (reg >> 4) + (reg & DS3231_MSK_SEC);
    ret = i2c_smbus_read_byte_data(client, DS3231_REG_MIN);
    if(ret < 0){
        pr_err("Error %d during minutes read\n", ret);
        return ret;
    }
    reg = (u8)(ret);
    tm->tm_min = 10 * (reg >> 4) + (reg & DS3231_MSK_MIN);
    ret = i2c_smbus_read_byte_data(client, DS3231_REG_HRS);
    if(ret < 0){
        pr_err("Error %d during hours read\n", ret);
        return ret;
    }
    reg = (u8)(ret);
    tm->tm_hour = 20 * ((reg >> 5) & 1) + 10 * ((reg >> 4) & 1) + (reg & DS3231_MSK_HR);
    ret = i2c_smbus_read_byte_data(client, DS3231_REG_MDAY);
    if(ret < 0){
        pr_err("Error %d during day read\n", ret);
        return ret;
    }
    reg = (u8)(ret);
    tm->tm_mday = 10 * (reg >> 4) + (reg & DS3231_MSK_DAY);
    ret = i2c_smbus_read_byte_data(client, DS3231_REG_MON);
    if(ret < 0){
        pr_err("Error %d during month read\n", ret);
        return ret;
    }
    reg = (u8)(ret);
    tm->tm_mon = 10 * ((reg >> 4) & 1) + (reg & DS3231_MSK_MON);
    ret = i2c_smbus_read_byte_data(client, DS3231_REG_YEAR);
    if(ret < 0){
        pr_err("Error %d during year read\n", ret);
        return ret;
    }
    reg = (u8)(ret);
    tm->tm_year = 2000 + 100 * (tm->tm_mon >> 7) + 10 * (reg >> 4) + (reg & DS3231_MSK_YEAR);
    tm->tm_wday = calculate_wday(tm->tm_year, tm->tm_mon, tm->tm_mday);
    tm->tm_yday = calculate_yday(tm->tm_year, tm->tm_mon, tm->tm_mday);
    tm->tm_isdst = 0;
    return 0;
}

我不认为这个函数会导致问题,但我将其包含在内以防万一。

driver embedded-linux real-time-clock hwclock
1个回答
0
投票

经过一番修改,我解决了这个问题;事实证明我的驱动程序实际上有一个错误,

tm_year
中的字段
struct rtc_time
存储的是1900年以来的年份,而不是当前年份。

线路:

tm->tm_year = 2000 + 100 * (tm->tm_mon >> 7) + 10 * (reg >> 4) + (reg & DS3231_MSK_YEAR);

有一个问题,它在年份字段中添加了 2000,因此将该字段变成了 2023,但是,它实际上应该包含 123 (2023 - 1900 = 123)。

我还修改了月份部分,以便在修改之前保存从RTC读取的值,因为未修改的值需要用于年份计算。最后看起来像这样:

reg = (u8)(ret);
last_message = reg;
tm->tm_mon = 10 * ((reg & DS3231_MSK_10MON) >> 4) + (reg & DS3231_MSK_MON);

然后,我现在使用

tm->tm_mon
,而不是在年份计算中使用
last_message

tm->tm_year = 100 * (last_message >> 7) + 10 * (reg >> 4) + (reg & DS3231_MSK_YEAR);

除此之外,我确保我的用户空间程序在读取和写入时分别对月份减1和加1,以便RTC保存0到12之间的数字,这是因为Linux读取这个范围内的月份。

© www.soinside.com 2019 - 2024. All rights reserved.