当前页面为 开发中 版本,查看特定版本的文档,请在页面左下角的下拉菜单中进行选择。

MAPM例程

1功能介绍

在ChirpIOT星状组网使用场景中,为了保证节点端设备能收到网关发送的数据,网关端会使用超长Preamble进行发送,如Preamble占用时间1s。在这种情况下,所有节点端设备在收到Preamble后都会一直接收直到Payload阶段显示节点网络地址,此时,节点端设备的软件可以比较收到的网络地址和节点设备自己地址,如不同,则停止接收,降低功耗,如满足地址接收条件则继续接收。这种方案存在几个问题:

  1. 不满足地址接收条件的节点端设备,直到payload阶段才能停止接收,浪费大量功耗

  2. 满足地址接收条件的节点端设备也需要收满超长的preamble才能进入payload接收阶段,也较浪费功耗

为解决以上两个功耗问题,在芯片PAN3029/PAN3060中增加新的帧结构模式Multiple Address Preamble Mode(MAPM)。该新帧结构模组的思路是在Preamble阶段插入类似后面同步字(Sync Word)的地址,这样节点端在Preamble阶段就可以根据地址来提前判断是否满足地址接收条件,已解决1)问题。另外,为了解决第2)问题,在地址中增加可变计数器,表明后续还有多少Preamble长度,满足地址接收条件的节点端设备可提前进入低功耗休眠状态,后根据该计数器判断需要提前多久在进入接收状态,保证数据正常接收,以便进一步节省满足地址接收条件的节点端设备功耗。

2MAPM帧结构

原始的帧结构大致如下图1所示。

img

图1 原始帧结构

如下图2所示。MAPM方案将preamble分为Fn个Field,Fn为Field的数量,每一个Field的结构相同,内容可不相同,同时为了保证payload数据能正确接收,在sync word前至少保证Pn个preamble,Pn需要大于等于8。

img

图2 MAPM帧结构

如下图3所示。在一个Field内部,分为若干个Group。Group的Gn个数最少1个,最多4个,Gn可以由寄存器配置。注意:TX和RX的Gn配置相同且事先确定。 一个Group分为Pg个未经调制的chirp加两个带调制的ADDR,第一个Group中,Pg的值最小为8,其他Group中Pg的最小值位0,也就是让所有的ADDR都连在一起,也可在其中插入preamble,其最大数量为255个(8bits),ADDR为1个字节的数据,可以由寄存器自由配置。

img

图3 Field帧结构

Group1的ADDR固定地作为标识符,其中ADDR1用于MAPM硬件同步,ADDR2~ADDR4用于软件应用。注意:TX和RX的地址配置需事先约定好,其中ADDR1必须相同MAPM功能才能生效。

Group的数量Gn,为0时只有1个Group; 为1时有2个Group;为2时有3个Group;为3时有4个Group。 不管有几个Group,最后一个Group的ADDR,存在两种模式:

  • 地址模式(ADDR),可用1字节寄存器配置

  • 计数器模式(COUNT),根据当前Field数量倒计时,由RF芯片自动填入,该值表示剩下的Field数量

image-20240103110652100

图4 终端工作状态对比图

  • RX1:开启MAPM模式,同时MAPM的ADDR跟TX匹配

  • RX2:关闭MAPM模式

  • RX3:开启MAPM模式,但MAPM的ADDR跟TX端不匹配

3 SDK接口函数

3.1 rf_set_mapm_on

句法

void rf_set_mapm_on(void)
{
    rf_mapm_en();
    rf_set_mapm_mask(MAPM_ON);
}

目的

使能mapm模式,开mapm中断允许

3.2 rf_set_mapm_off

句法

void rf_set_mapm_off(void)
{
    rf_mapm_dis();
    rf_set_mapm_mask(MAPM_OFF);
}

目的

关mapm模式,关mapm中断允许

3.3 rf_set_mapm_para

句法

void rf_set_mapm_para(stc_mapm_cfg_t *p_mapm_cfg)
{
    rf_set_mapm_field_num(p_mapm_cfg->fn);
    rf_set_mapm_field_num_mux(p_mapm_cfg->fnm);
    rf_set_mapm_group_fun_sel(p_mapm_cfg->gfs);
    rf_set_mapm_group_num(p_mapm_cfg->gn);
    rf_set_mapm_firgroup_preamble_num(p_mapm_cfg->pgl);
    rf_set_mapm_group_preamble_num(p_mapm_cfg->pgn);
    rf_set_mapm_neces_preamble_num(p_mapm_cfg->pn);
}

目的

设置mapm模式相关参数

参数

序号

参数名

参数含义

参数说明

1

fn

mapm preamble中Field数量{field1, field2,……fieldfn}

范围:0x01~0xe0

2

fnm

mapm preamble中每个field重复次数

范围:0x00~0x03
00 –>重复1次{field1, field2,……fieldfn}
01 –> 重复2次{field1, field1, field2, field2……fieldfn, fieldfn}
10 –> 重复4次
11 –> 重复8次

3

gfs

Field中最后一个Group,其ADDR位置功能选择

范围:0x00~0x01
0:普通地址{addr1, addr2, addr3, addr4}
1:Field个数计数器{addr1, addr2, addr3, count}

4

gn

一个Field中Group个数

范围:0x00~0x03
00–> 1个group
01–> 2个group
02–> 3个group
03–> 4个group

5

pgl

每个Field中第一个Group内Preamble数量

范围:0x08~0xff,默认为0x08

6

pgn

每个Field中其他Group内Preamble数量

范围:0x08~0xff,默认为0x08

7

pn

所有的Field都发送完毕后syncword前Preamble的数量

范围:0x08~0xfff,默认为0x08

3.4 rf_calculate_mapm_preambletime

句法

uint32_t rf_calculate_mapm_preambletime(void)

目的

计算当前收到的preamble剩余时长(ms)

参数

返回值

当前收到的preamble剩余时长

3.5 rf_set_mapm_addr

句法

uint32_t rf_set_mapm_addr(uint8_t addr_no, uint8_t addr)

目的

配置mapm Group中地址

参数

  • addr_no 想要配置的地址序号

    数值

    含义

    0

    ADDR1

    1

    ADDR2

    2

    ADDR3

    3

    ADDR4

  • addr ADDR配置的值,注:地址配置范围见6.1地址配置

返回值 FAIL 操作失败 OK 操作成功

4 软件设计验证

注意事项

  1. 只有TX,RX mapm地址参数ADDR1相同时,RX才能进入mapm中断,所以TX,RX代码要配置一样的ADDR1,mapm功能才生效。

  2. 所有验证基于HC32F460EVB底板,详细操作方式见第5章节系统演示板。

4.1 验证内容

本次验证使用3个模组进行,一个发送TX,两个接收RX。验证代码共用同一工程,通过底板拨码开关选择TX\RX功能;通过代码中宏ADDR_MATCH来选择RX与TX ADDR2是否相同,从而判断是否接收TX发送数据。两个RX,一个开启宏,一个关闭宏进行对比。

4.2 软件设计流程

1、芯片初始化,上电默认SF7 ,BW500K; 2、配置mapm初始化; 3、TX进入发送模式,RX1,RX2 3029/3060进入低功耗模式,其中RX1 ADDR2与TX相同,RX2 ADDR2与TX不同; 4、RX 3029每隔当前前参数下preamble时长一半唤醒检测接收数据。

4.3 验证步骤

1、TX按键周期性发送数据; 2、RX1,RX2每隔当前参数下preamble时长一半周期性唤醒检测接收数据; 3、使用电流表统计两个RX功耗情况; 4、串口调试工具监视RX接收数据。

4.3.1 SDK示例

参考代码:

#define  ADDR_MATCH 1 //地址匹配
/*初始化不同SF mapm参数*/ 
const stc_mapm_cfg_t mapm_cfg[] =
{
  {
    .mapm_addr= {0x73, 0x62, 0x54, 0x81},   //SF7 BW_500K
    .fn = 64,
    .fnm = 0,
    .gfs = FIELD_COUNTER,
    .gn = 2,
    .pg1 = 10,
    .pgn = 120,
    .pn = 8
  },
  {
    .mapm_addr= {0x73, 0x62, 0x54, 0x81},   //SF8 BW_500K
    .fn = 32,
    .fnm = 0,
    .gfs = FIELD_COUNTER,
    .gn = 2,
    .pg1 = 10,
    .pgn = 120,
    .pn = 8
  },
  {
    .mapm_addr= {0x73, 0x62, 0x54, 0x81},   //SF9 BW_500K
    .fn = 16,
    .fnm = 0,
    .gfs = FIELD_COUNTER,
    .gn = 2,
    .pg1 = 10,
    .pgn = 120,
    .pn = 8
  },
  {
    .mapm_addr= {0x73, 0x62, 0x54, 0x81},   //SF10 BW_500K,only for PAN3029
    .fn = 8,
    .fnm = 0,
    .gfs = FIELD_COUNTER,
    .gn = 2,
    .pg1 = 10,
    .pgn = 120,
    .pn = 8
  },
  {
    .mapm_addr= {0x73, 0x62, 0x54, 0x81},   //SF11 BW_500K,only for PAN3029
    .fn = 6,
    .fnm = 0,
    .gfs = FIELD_COUNTER,
    .gn = 2,
    .pg1 = 10,
    .pgn = 120,
    .pn = 8
  },
  {
    .mapm_addr= {0x73, 0x62, 0x54, 0x81},   //SF12 BW_500K,only for PAN3029
    .fn = 6,
    .fnm = 0,
    .gfs = FIELD_COUNTER,
    .gn = 2,
    .pg1 = 10,
    .pgn = 120,
    .pn = 8
  },
};/*3029初始化配置*/
  ret = rf_init(); //3029/3060初始化
  if(ret != OK)
  {
    printf("  RF Init Fail");
    while(1);
  }
  rf_set_default_para();	 //配置默认射频参数  
//使用当前demo初始化的射频参数
  now_bw = TEST_BW;
  now_sf = TEST_SF;
  rf_set_bw(now_bw);
  rf_set_sf(now_sf);
  rf_set_code_rate(TEST_CR);
  rf_set_freq(TEST_FREQ);
  memcpy((uint8_t*)&cur_mapm_cfg,(uint8_t*)&mapm_cfg[now_sf-SF_7], sizeof(stc_mapm_cfg_t));//根据SF获取当前mapm参数,第一个mapm参数是SF7的 	   rf_set_mapm_on(); //使能 mapm 模式
  rf_set_mapm_para(&cur_mapm_cfg); //配置mapm参数  	
  for(uint8_t i=0; i<cur_mapm_cfg.gn+1; i++)
  {
    rf_set_mapm_addr(i, cur_mapm_cfg.mapm_addr[i]);
  }
  one_chirp_time = get_chirp_time(now_bw,now_sf);//计算一个包长时间us
  preamble_time=rf_calculate_mapm_preambletime(&cur_mapm_cfg, one_chirp_time);//计算preamble时长
  rx_timeout_val = preamble_time + calculate_payload_time(tx_len) + 200;//计算完整包长时间,在此基础上加200ms作为接收超时判断时间
  sleep_timer_val = preamble_time/2;
  if(app_tx_mode)
  {
    DDL_Printf("tx\r\n");
  }
  else
  {
    DDL_Printf("rx\r\n");
#ifndef ADDR_MATCH
//修改ADDR1,软件用来区分是否接收TX发送数据    
     cur_mapm_cfg.mapm_addr[1] = 0x61;
     rf_set_mapm_addr(1, cur_mapm_cfg.mapm_addr[1]);
#endif
    rf_set_cad(CAD_DETECT_THRESHOLD_10, CAD_DETECT_NUMBER_3);
    rf_set_dcdc_mode(DCDC_ON);
    rf_enter_single_timeout_rx(rx_timeout_val);
  }	
  while(1){
    rf_irq_process();		
    key_scan();
    key_event_process();
    process_rf_events();
  }	
/*MAPM 接收数据后休眠处理*/
  flag = rf_get_recv_flag();
  if(flag == RADIO_FLAG_MAPM)
  {
    rf_set_recv_flag(RADIO_FLAG_IDLE);
    if(RxDoneParams.mpam_recv_index == cur_mapm_cfg.gn + 1)//接收到一个完整Field
    {
      uint8_t i;
      if(cur_mapm_cfg.gfs == FIELD_COUNTER)
      {
        addr_num = cur_mapm_cfg.gn;
      }
      else
      {
        addr_num = cur_mapm_cfg.gn + 1;
      }
      for(i=0; i<addr_num; i++)
      {
        if(cur_mapm_cfg.mapm_addr[i] != RxDoneParams.mpam_recv_buf[i])  //addr不匹配,不需要接收
        {
          mapm_target = 0;
          break;
        }
      }
      if(i == addr_num)
      {
        mapm_target = 1;  //接收地址匹配,需要接收数据
      }
      if(cur_mapm_cfg.gfs == FIELD_COUNTER)//计数器模式
      {
        cur_mapm_cfg.fn = RxDoneParams.mpam_recv_buf[cur_mapm_cfg.gn];
        mapm_preamgle_time= rf_calculate_mapm_preambletime(&cur_mapm_cfg, one_chirp_time);
        one_field_chirp = cur_mapm_cfg.pg1+2 + (cur_mapm_cfg.pgn+2) * 	cur_mapm_cfg.gn;
        if(mapm_target)
        {
          mapm_sleeptime = mapm_preamgle_time - one_field_chirp*one_chirp_time/1000; //计算可以休眠时间
          if(mapm_sleeptime > CODE_RUNTIME) 
          {
            rf_sleep();
            mapm_sleep_flag = 1;
            mapm_sleep_begtime = SysTick_GetTick();
          }
          else //休眠时间太短不休眠
          {
            DDL_Printf("sleep time too short\r\n");
          }
        }
        else
        {
          memset(RxDoneParams.mpam_recv_buf, 0, RxDoneParams.mpam_recv_index); 
          RxDoneParams.mpam_recv_index = 0;
          mapm_sleeptime = mapm_preamgle_time + PAYLOAD_LEN*one_chirp_time/1000;
          rf_sleep();
          mapm_sleep_flag = 1;
          mapm_sleep_begtime = SysTick_GetTick();
        }
      }
    }
    }

/*mapm 休眠唤醒处理*/
  if(mapm_sleep_flag == 1)
  {
    if((SysTick_GetTick()-mapm_sleep_begtime) > (mapm_sleeptime-CODE_RUNTIME)) //达到休眠时间后唤醒
    {
      rf_sleep_wakeup();
      mapm_sleep_flag = 0;
      if(mapm_target)
      {
        mapm_target = 0;
      }
      else
      {
        recv_flag = 0;
      }
      if(rf_enter_continous_rx() != OK)
      {
        DDL_Printf("set rx FAIL\r\n");
      }
    }
 }

示例代码配置了mapm初始化,TX发送数据后,RX接收后判断是否需要接收数据,然后进行休眠唤醒处理。

发送模组发送数据包(默认参数SF7 BW500K数据包preamble的持续时间约4200ms,payload的持续时间约40ms),用电流表抓取两个RX接收模组电流波形,观察结果。

4.3.2 验证结果

电流表抓取RX1结果如图4-1所示:

img

图4-1 RX1电流表功耗抓取结果

根据结果显示,当发送模组发送数据包时,RX1在唤醒后检测到TX数据,判断地址匹配后,计算出剩余preamble时长,休眠该时间后,唤醒进行payload数据接收。串口打印RX1结果如图4-2所示:

img

图4-2 RX1串口抓取结果

根据结果显示,只收到了preamble中6个mapm addr,而TX实际发送了96个mapm addr,其余90个mapm addr时间RX1进入了低功耗休眠,然后在payload前唤醒接收了100字节长度payload。 电流表抓取RX2结果如图4-3所示:

img

图4-3 RX2电流图

根据结果显示,当发送模组发送数据包时,RX2在唤醒后检测到TX数据,判断地址不匹配后,计算出剩余preamble和payload时长,休眠该时间后,唤醒重新进行接收检测。串口打印RX2结果如图4-4所示:

img

图4-4 RX2串口抓取结果

根据结果显示,RX2判断地址不匹配后直接休眠不再进行数据接收,所以未打印任何接收数信息。

5 系统演示板

演示系统板基于 HC32F460EVB的底板功能描述如图 5- 1 所示

img

图 5- 1 HC32 底板

5.1 模组RX,TX设置

拨码开关:收发模式切换。往上拨到TX为 TX 模式,往下拨到RX为 RX 模式。

5.2 按键功能

按键 3:TX按下发送数据 按键 5:切换SF,范围5~12,步径1 按键 6:切换BW,62.5K/125K/250K/500K

6 注意事项

6.1 地址配置

(1)由于调制Chirp的特点,所有ADDR配置范围0x11~0xFF,不支持小于0x11和不支持0xX0值,如果软件收到这些值时,软件操作芯片复位。同时需要注意Group1中的ADDR1、Group中的ADDR2~4以及正常帧结构中的SyncWord这三者都不相同。

(2)SF7~SF12(PAN3060只支持到SF9),ADDR支持8bit配置,SF5仅支持0b00xx00xx(0x11,0x12,0x13,0x21,0x22,0x23,0x31,0x32,0x33),SF6支持0b0xxx0xxx,这里仍然要求满足不支持小于0x11和不支持0xX0值。(注意:在SF5\SF6配置下,MAPM的计数器模式count值在小于0x11时计数器值可能会有异常,不建议用户在SF5\SF6配置下使用MAPM功能)

(3)地址配置配合参数gn使用,根据gn数量从addr1开始连续配置相应数量的addr。

(4)每个ADDR为无符号8位数据,配置时高4位和低4位尽量不要一样。

6.2 Field中最后一个Group其ADDR位置功能选择

(1)参数gfs = 0x00,field中最后一个group配置为普通Addr功能

(2)参数gfs = 0x01,field中最后一个group配置为计数器,注意fn 和 addr的配置,避免出现fn不断自减出现计数器与ADDR1或同步字syncword相等的情况误触发mapm中断或错误同步的情况。

6.3 同步字配置

SF7~SF12,同步字syncword支持8bit配置。

6.4 Preamble数量配置

(1)每个Field中第一个Group内Preamble(pg1)的数量最小为8。

(2)所有的Field都发送完毕后syncword前Preamble(pn)的数量最小为8。

6.5 休眠时间

根据参数算出后续preamble接收时间,进入休眠时休眠时间需注意减去休眠,休眠唤醒及其他代码运行时间,尽量稍微提前唤醒,避免唤醒错过syncword,无法接收payload数据。