这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 活动中心 » 板卡试用 » 【分享开发笔记,赚取电动螺丝刀】mcxa156使用低功耗定时器适配硬件RTC框架

共3条 1/1 1 跳转至

【分享开发笔记,赚取电动螺丝刀】mcxa156使用低功耗定时器适配硬件RTC框架

工程师
2025-02-28 13:08:19     打赏

       首先,个人不太认同使用mcx156的LPTMR模块适配RTC驱动的做法,但是既然群友提到了可以这么做,那就把这个模块适配一下玩玩。

硬件资源

      从MCXAP100M96FS6RM.pdf上可以知道,LPTMR模块可以用作1s计时,但是存在一个问题,就是计数器不能设置,只能读。这就导致我们使用此模块适配RTC时,只能通过rtc驱动内部维护的变量来实现计时计算。其结构框图如下:

1.jpg

      此处提到了lptmr的计数器无法初始化,只能读取。

2.jpg


驱动适配

KConfig修改

     对应芯片的KConfig文件存储位置为:bsp\nxp\mcx\mcxa\frdm-mcxa156\board\Kconfig

      我们仅仅需要在该文件的On-chip Peripheral Drivers项目中增加硬件RTC相关配置即可:

menuconfig BSP_USING_RTC
        config BSP_USING_RTC
            bool "Enable RTC"
            select RT_USING_RTC
            default y
        
            if BSP_USING_RTC
                config BSP_USING_ALARM
                    bool "Enable Alarm"
                    default y
            endif

SConscript修改

     MCXA系列芯片驱动的SConscript文件存储位置为:bsp\nxp\mcx\mcxa\Libraries\drivers\SConscript

      由于此文件中之前便有了RTC的配置,因此不需要修改。

1.jpg

驱动文件添加

     在SConscript同一目录下添加drv_rtc.c文件,并填入以下内容。

/*
 * Copyright (c) 2006-2025, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2025-02-28     oxlm         Initial version.
 */

#include <rtthread.h>
#include <rtdevice.h>
#include <sys/time.h>
#include "fsl_common.h"
#include "fsl_lptmr.h"

#ifdef RT_USING_RTC

struct rtc_device_object
{
    rt_rtc_dev_t  dev;
    time_t ts;
    rt_bool_t is_ts_set;
    time_t ts_new;
#ifdef BSP_USING_ALARM
    struct rt_rtc_wkalarm alarm;
#endif
};

static struct rtc_device_object rtc_dev;

void LPTMR0_IRQHandler(void)
{
    LPTMR_ClearStatusFlags(LPTMR0, kLPTMR_TimerCompareFlag);
    if(rtc_dev.is_ts_set)
    {
        rtc_dev.is_ts_set = RT_FALSE;
        rtc_dev.ts = rtc_dev.ts_new;
    }
    rtc_dev.ts++;

#ifdef BSP_USING_ALARM
    if(rtc_dev.alarm.enable)
    {
        rt_alarm_update(&rtc_dev.dev.parent, 0);
    }
#endif

    /*
     * Workaround for TWR-KV58: because write buffer is enabled, adding
     * memory barrier instructions to make sure clearing interrupt flag completed
     * before go out ISR
     */
    __DSB();
    __ISB();
}

static rt_err_t mcx_rtc_init(void)
{
    lptmr_config_t lptmrConfig;

    LPTMR_GetDefaultConfig(&lptmrConfig);
    LPTMR_Init(LPTMR0, &lptmrConfig);
    LPTMR_SetTimerPeriod(LPTMR0, USEC_TO_COUNT(1000000, 16000U));
    LPTMR_EnableInterrupts(LPTMR0, kLPTMR_TimerInterruptEnable);
    EnableIRQ(LPTMR0_IRQn);
    LPTMR_StartTimer(LPTMR0);

    return RT_EOK;
}

static rt_err_t mcx_rtc_get_time(time_t *ts)
{
    if(rtc_dev.is_ts_set)
    {
        *ts = rtc_dev.ts_new;
    }
    else
    {
        *ts = rtc_dev.ts;
    }

    return RT_EOK;
}

static rt_err_t mcx_rtc_set_time(time_t *ts)
{
    rtc_dev.ts_new = *ts;
    rtc_dev.is_ts_set = RT_TRUE;

    return RT_EOK;
}

#ifdef BSP_USING_ALARM
rt_err_t mcx_rtc_get_alarm(struct rt_rtc_wkalarm *alarm)
{
    rt_memcpy(alarm, &rtc_dev.alarm, sizeof(struct rt_rtc_wkalarm));
    return RT_EOK;
}

rt_err_t mcx_rtc_set_alarm(struct rt_rtc_wkalarm *alarm)
{
    rt_memcpy(&rtc_dev.alarm, alarm, sizeof(struct rt_rtc_wkalarm));
    return RT_EOK;
}
#endif

static const struct rt_rtc_ops ops =
{
    .init = mcx_rtc_init,
    .get_secs = mcx_rtc_get_time,
    .set_secs = mcx_rtc_set_time,
#ifdef BSP_USING_ALARM
    .get_alarm = mcx_rtc_get_alarm,
    .set_alarm = mcx_rtc_set_alarm,
#else
    .get_alarm = RT_NULL,
    .set_alarm = RT_NULL,
#endif
    .get_timeval = RT_NULL,
    .set_timeval = RT_NULL,
};

int rt_hw_rtc_init(void)
{
    rtc_dev.is_ts_set = RT_FALSE;
    rtc_dev.ts = 0;

    rtc_dev.dev.ops = &ops;
    if (rt_hw_rtc_register(&rtc_dev.dev, "rtc", RT_DEVICE_FLAG_RDWR, RT_NULL) != RT_EOK)
    {
        rt_kprintf("rtc init failed");
        return -RT_ERROR;
    }

    return RT_EOK;
}

INIT_DEVICE_EXPORT(rt_hw_rtc_init);

#endif /*RT_USING_RTC */

时钟树修改

    在 bsp\nxp\mcx\mcxa\frdm-mcxa156\board\MCUX_Config\board\pin_mux.c中的函数BOARD_InitPins中添加如下代码:

#ifdef BSP_USING_RTC
    CLOCK_SetClockDiv(kCLOCK_DivLPTMR0, 1u);
    CLOCK_AttachClk(kFRO12M_to_LPTMR0);

    CLOCK_SetupFRO16KClocking(kCLKE_16K_SYSTEM | kCLKE_16K_COREMAIN);
#endif

    至此,代码修改部分已经完成。

开启RTC功能

menuconfig设置

    配置好后按Q键并按Y键保存。

生成工程

1.jpg

添加测试代码

    在main.c中添加如下代码。

void user_alarm_callback(rt_alarm_t alarm, time_t timestamp)
{
    time_t now = (time_t)0;
    struct timeval tv = { 0 };

    gettimeofday(&tv, RT_NULL);
    now = tv.tv_sec;

    rt_kprintf("local time: %.*s", 25U, ctime(&now));
}

void alarm_sample(void)
{  
    rt_device_t dev = rt_device_find("rtc");
    struct rt_alarm_setup setup;
    struct rt_alarm * alarm = RT_NULL;
    static time_t now;
    struct tm p_tm;

    if (alarm != RT_NULL)
        return;

    now = time(NULL) + 1;
    gmtime_r(&now,&p_tm);

    setup.flag = RT_ALARM_SECOND;            
    setup.wktime.tm_year = p_tm.tm_year;
    setup.wktime.tm_mon = p_tm.tm_mon;
    setup.wktime.tm_mday = p_tm.tm_mday;
    setup.wktime.tm_wday = p_tm.tm_wday;
    setup.wktime.tm_hour = p_tm.tm_hour;
    setup.wktime.tm_min = p_tm.tm_min;
    setup.wktime.tm_sec = p_tm.tm_sec;   

    alarm = rt_alarm_create(user_alarm_callback, &setup);    
    if(RT_NULL != alarm)
    {
        rt_alarm_start(alarm);
    }
}
MSH_CMD_EXPORT(alarm_sample,alarm sample);

结果验证

    编译后将固件下载至板卡,复位板卡后输入命令alarm_sample并回车,得到如下结果:

sram heap, begin: 0x0x200015dc, end: 0x0x2001dc00

 \ | /
- RT -     Thread Operating System
 / | \     5.2.0 build Feb 28 2025 00:37:09
 2006 - 2024 Copyright by RT-Thread team
using armclang, version: 6210000
MCXA156 HelloWorld
msh >
msh >
msh >alar
alarm_sample
msh >alarm_sample
msh >local time: Thu Jan  1 08:00:02 1970
local time: Thu Jan  1 08:00:03 1970
local time: Thu Jan  1 08:00:04 1970
local time: Thu Jan  1 08:00:05 1970
local time: Thu Jan  1 08:00:06 1970
local time: Thu Jan  1 08:00:07 1970
local time: Thu Jan  1 08:00:08 1970
local time: Thu Jan  1 08:00:09 1970
local time: Thu Jan  1 08:00:10 1970
local time: Thu Jan  1 08:00:11 1970
local time: Thu Jan  1 08:00:12 1970
local time: Thu Jan  1 08:00:13 1970
local time: Thu Jan  1 08:00:14 1970
local time: Thu Jan  1 08:00:15 1970
local time: Thu Jan  1 08:00:16 1970
local time: Thu Jan  1 08:00:17 1970
local time: Thu Jan  1 08:00:18 1970
local time: Thu Jan  1 08:00:19 1970
local time: Thu Jan  1 08:00:20 1970
local time: Thu Jan  1 08:00:21 1970
local time: Thu Jan  1 08:00:22 1970
local time: Thu Jan  1 08:00:23 1970
local time: Thu Jan  1 08:00:24 1970
local time: Thu Jan  1 08:00:25 1970
local time: Thu Jan  1 08:00:26 1970
local time: Thu Jan  1 08:00:27 1970
local time: Thu Jan  1 08:00:28 1970

       至此,功能部分验证完成。

最后

    正如我一开始所说,这方法仅适用于玩玩,毕竟不是真正的硬件RTC,与其这么干还不如之接弄软件RTC实在。





关键词: 电动     赚取     笔记     开发     分享     螺丝刀     mcxa15    

专家
2025-02-28 19:10:09     打赏
2楼

理解力、动手能力真强!羡慕!


高工
2025-03-01 10:01:00     打赏
3楼

也是一个思路。



共3条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]