Skip to content

DTU低功耗

1 低功耗操作

1.1 Clock Gating

在系统空闲时,开启Clock Gating可以让DTU进入暂停状态,基带中断或外部中断可唤醒,然后系统继续运行。

1.2 睡眠:RTC唤醒

设定时间后进入睡眠,使用RTC定时唤醒。这种方式比较简单,精度不是很高。

1.3 睡眠:DFE唤醒

设定时间后进入睡眠,使用DFE定时唤醒。这种方式相对RTC唤醒时间精度更高,达到us级别。

1.4 睡眠:同步信号检测唤醒

进入睡眠,基带会一直检测同步信号,一旦检测到同步唤醒信号,并确认唤醒ID正确就,则被唤醒。

1.5 睡眠:信号检测唤醒

进入睡眠,基带会一直检测信号,一旦检测到唤醒信号,并确认唤醒ID正确就,则被唤醒。

2 低功耗测试

2.1 测试模型

一种应用场景是把DTU作为一个模组使用,受MCU控制。

这里采用IOTE评估板作为MCU控制另外一个IOTE评估板(需要有外部32k晶振)演示DTU低功耗测试。

测试模型步骤:

步骤1:启动IOTE,等待其接入网关

步骤2:启动MCU,MCU向IOTE发送数据,发送完数据进入阻塞,等待通知信号

步骤3:IOTE收到数据后,将数据透传到网关,透传完数据,进入睡眠(DFE唤醒)

步骤3:IOTE醒来后通知MCU进行下次数据发送

步骤4:MCU收到通知信号,进行数据发送。然后进行步骤3,如此循环。

这里的睡眠时间满足:发送数据周期时间 = 发送数据时间 + 睡眠时间 + 程序启动到下次发送的时间,程序会自动计算,只需设置发送周期就行了。

MCU的参考程序在本文末尾。

2.2 参数配置

发送要求:MCU发送数据长度50字节、发送周期时间2s。

可以计算出在symbol len为256,MCS为3的情况下,IOTE需要发送2包才能发完,发送时长小于300ms(不重传),预留了足够的时间给IOTE睡眠和启动。

子系统配置参数(网关和IOTE保持一致):

名称 描述
symbol len 设1,代表256
下行上行比 设0,代表1:1
上行group数量 设0,代表1
其他保持一致,保证能正常接入网关

网关端:

名称 描述
上行编码 设2,代表16进制编码
连接态时间 设3,需要大于发送间隔时间2s
广播帧发送周期 设1
上行发送周期 设2000,代表2000ms的发送间隔
发送一次数据需要的帧数 设2,代表需要发送2包才能发完一次数据

IOTE端:

名称 描述
接入设备类型 设0,同步到网关
使能外部晶振 设1,用外部晶振时间才准确
硬件板类型 设1,代表IOTE评估板
连接态时间 设3,与网关端保持一致
数据速率 设3,即MCS设为3
分时发送开关 设1,开启后IOTE按照网关分配时隙发送数据
唤醒后IO输出开关 设1,开启唤醒后IO输出
唤醒后IO输出pin脚 设0x11,对应十进制为17
唤醒后IO输出高电平保持时间 设10,代表10ms
2.3 开始测试

如下图,将MCU和IOTE连接起来。其中IOTE评估板的GPIO17有针脚引出,同时连接了未定义指示功能的LED灯,有信号时可以观察到该灯的闪烁情景。

先保证IOTE正常运行,接入到网关。然后插上跳帽线启动MCU板。

观察MCU日志信息,是否正常发送数据;观察IOTE日志信息,是否收到配置命令,正常发送数据到网关,然后进入睡眠;

在MQTT工具中,查看收到的MQTT消息内容与发送信息是否一致,收到的时间是否满足2s时间间隔(选择时间精度高且刷新快的MQTT工具)。

IOTE日志和MCU日志信息如下:

MQTT消息如下:

观察MQTT消息接收时间,满足2s间隔。此时可以观察IOTE运行状态指示灯和其他指示灯,睡眠时所有灯是熄灭的。

程序调通后,可以将MCU单独供电,在静态数据表中把如下IOTE的灯都关闭,然后使用仪器测试功耗。

附录:

低功耗测试的MCU示例程序
#include <rtthread.h>
#include <rtdevice.h>
#include "uc_gpio.h"

const rt_uint8_t g_data[] = {   \
    0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, \
    0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, \
    0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, \
    0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, \
    0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99};
static rt_device_t g_user_com;
static rt_thread_t g_send_data_thread;
static rt_sem_t g_awaken_sem;
static rt_uint32_t g_send_cnt;

static void handle_awake_inform(void *p)
{
    if (g_awaken_sem)
    {
        rt_kprintf("g_awaken_sem release\n");
        rt_sem_release(g_awaken_sem);
    }
}

static void send_data_thread(void *p)
{
    rt_uint16_t send_len = 0;
    rt_thread_mdelay(2000);

    send_len = rt_device_write(g_user_com, 0, g_data, sizeof(g_data));
    rt_kprintf("send len %d send cnt %d\n", send_len, ++g_send_cnt);

    while (1)
    {
        rt_sem_take(g_awaken_sem, RT_WAITING_FOREVER);
        rt_kprintf("g_awaken_sem take success\n");

        send_len = rt_device_write(g_user_com, 0, g_data, sizeof(g_data));
        rt_kprintf("send len %d send cnt %d\n", send_len, ++g_send_cnt);
    }
}

int main(void)
{
    rt_err_t open_ret;

    g_user_com = rt_device_find("uart0");
    if (g_user_com)
    {
        struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
        RT_ASSERT(RT_Device_Class_Char == g_user_com->type);

        config.baud_rate = BAUD_RATE_4800;
        rt_device_control(g_user_com, RT_DEVICE_CTRL_CONFIG, &config);

        open_ret = rt_device_open(g_user_com, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX);
        if (RT_EOK != open_ret)
        {
            rt_kprintf("open device uart0 fail\n");
        }
    }
    else
    {
        rt_kprintf("not find device uart0\n");
        RT_ASSERT(0);
    }

    gpio_set_pin_mux(UC_GPIO_CFG, GPIO_PIN_17, GPIO_FUNC_0);
    rt_pin_write(GPIO_PIN_17, PIN_LOW);
    rt_pin_mode(GPIO_PIN_17, PIN_MODE_INPUT);
    rt_pin_attach_irq(GPIO_PIN_17, PIN_IRQ_MODE_RISING, handle_awake_inform, NULL);
    rt_pin_irq_enable(GPIO_PIN_17, PIN_IRQ_ENABLE);
    g_awaken_sem = rt_sem_create("awaken_sem", 0, RT_IPC_FLAG_PRIO);

    g_send_data_thread = rt_thread_create("send_data_thread", send_data_thread, NULL, 512, 5, 3);
    rt_thread_startup(g_send_data_thread);

    return 0;
}
Back to top