MAPM例程¶
1功能介绍¶
在ChirpIOT星状组网使用场景中,为了保证节点端设备能收到网关发送的数据,网关端会使用超长Preamble进行发送,如Preamble占用时间1s。在这种情况下,所有节点端设备在收到Preamble后都会一直接收直到Payload阶段显示节点网络地址,此时,节点端设备的软件可以比较收到的网络地址和节点设备自己地址,如不同,则停止接收,降低功耗,如满足地址接收条件则继续接收。这种方案存在几个问题:
不满足地址接收条件的节点端设备,直到payload阶段才能停止接收,浪费大量功耗
满足地址接收条件的节点端设备也需要收满超长的preamble才能进入payload接收阶段,也较浪费功耗
为解决以上两个功耗问题,在芯片PAN3029中增加新的帧结构模式Multiple Address Preamble Mode(MAPM)。该新帧结构模组的思路是在Preamble阶段插入类似后面同步字(Sync Word)的地址,这样节点端在Preamble阶段就可以根据地址来提前判断是否满足地址接收条件,已解决1)问题。另外,为了解决第2)问题,在地址中增加可变计数器,表明后续还有多少Preamble长度,满足地址接收条件的节点端设备可提前进入低功耗休眠状态,后根据该计数器判断需要提前多久在进入接收状态,保证数据正常接收,以便进一步节省满足地址接收条件的节点端设备功耗。
2MAPM帧结构¶
原始的帧结构大致如下图1所示。
如下图2所示。MAPM方案将preamble分为Fn个Field,Fn为Field的数量,每一个Field的结构相同,内容可不相同,同时为了保证payload数据能正确接收,在sync word前至少保证Pn个preamble,Pn需要大于等于8。
如下图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个字节的数据,可以由寄存器自由配置。
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数量
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)
{
PAN3029_mapm_en();
PAN3029_set_mapm_mask(MAPM_ON);
}
目的
使能mapm模式,开mapm中断允许
3.2 rf_set_mapm_off¶
句法
void rf_set_mapm_off(void)
{
PAN3029_mapm_dis();
PAN3029_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)
{
PAN3029_set_mapm_field_num(p_mapm_cfg->fn);
PAN3029_set_mapm_field_num_mux(p_mapm_cfg->fnm);
PAN3029_set_mapm_group_fun_sel(p_mapm_cfg->gfs);
PAN3029_set_mapm_group_num(p_mapm_cfg->gn);
PAN3029_set_mapm_firgroup_preamble_num(p_mapm_cfg->pgl);
PAN3029_set_mapm_group_preamble_num(p_mapm_cfg->pgn);
PAN3029_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 |
3 |
gfs |
Field中最后一个Group,其ADDR位置功能选择 |
范围:0x00~0x01 |
4 |
gn |
一个Field中Group个数 |
范围:0x00~0x03 |
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 PAN3029_calculate_mapm_preambletime¶
句法
uint32_t PAN3029_calculate_mapm_preambletime(void)
目的
计算当前收到的preamble剩余时长(ms)
参数
无
返回值
当前收到的preamble剩余时长
3.5 PAN3029_set_mapm_addr¶
句法
uint32_t PAN3029_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 软件设计验证¶
注意事项
只有TX,RX mapm地址参数ADDR1相同时,RX才能进入mapm中断,所以TX,RX代码要配置一样的ADDR1,mapm功能才生效。
所有验证基于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进入低功耗模式,其中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= {0x31, 0x32, 0x23, 0x22}, //SF5 BW_500K
.fn = 32,
.fnm = 0,
.gfs = FIELD_COUNTER,
.gn = 2,
.pg1 = 10,
.pgn = 120,
.pn = 8
},
{
.mapm_addr= {0x73, 0x62, 0x51, 0x41}, //SF6 BW_500K
.fn = 64,
.fnm = 0,
.gfs = FIELD_COUNTER,
.gn = 2,
.pg1 = 10,
.pgn = 120,
.pn = 8
},
{
.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
.fn = 8,
.fnm = 0,
.gfs = FIELD_COUNTER,
.gn = 2,
.pg1 = 10,
.pgn = 120,
.pn = 8
},
{
.mapm_addr= {0x73, 0x62, 0x54, 0x81}, //SF11 BW_500K
.fn = 6,
.fnm = 0,
.gfs = FIELD_COUNTER,
.gn = 2,
.pg1 = 10,
.pgn = 120,
.pn = 8
},
{
.mapm_addr= {0x73, 0x62, 0x54, 0x81}, //SF12 BW_500K
.fn = 6,
.fnm = 0,
.gfs = FIELD_COUNTER,
.gn = 2,
.pg1 = 10,
.pgn = 120,
.pn = 8
},
};/*3029初始化配置*/
ret = rf_init(); //3029初始化
if(ret != OK)
{
printf(" RF Init Fail");
while(1);
}
rf_set_default_para(); //配置默认射频参数
//使用当前demo初始化的射频参数
now_bw = TEST_BW;
now_sf = TEST_SF;
PAN3029_set_bw(now_bw);
PAN3029_set_sf(now_sf);
PAN3029_set_code_rate(TEST_CR);
PAN3029_set_freq(TEST_FREQ);
memcpy((uint8_t*)&cur_mapm_cfg,(uint8_t*)&mapm_cfg[now_sf-SF_5], sizeof(stc_mapm_cfg_t));//根据SF获取当前mapm参数,第一个mapm参数是SF5的 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++)
{
PAN3029_set_mapm_addr(i, cur_mapm_cfg.mapm_addr[i]);
}
one_chirp_time = get_chirp_time(now_bw,now_sf);//计算一个包长时间us
preamble_time=PAN3029_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发送数据
if(now_sf == SF_5)
{
cur_mapm_cfg.mapm_addr[1] = 0x21;
PAN3029_set_mapm_addr(1, cur_mapm_cfg.mapm_addr[1]);
}
else
{
cur_mapm_cfg.mapm_addr[1] = 0x61;
PAN3029_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= PAN3029_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所示:
根据结果显示,当发送模组发送数据包时,RX1在唤醒后检测到TX数据,判断地址匹配后,计算出剩余preamble时长,休眠该时间后,唤醒进行payload数据接收。串口打印RX1结果如图4-2所示:
根据结果显示,只收到了preamble中6个mapm addr,而TX实际发送了96个mapm addr,其余90个mapm addr时间RX1进入了低功耗休眠,然后在payload前唤醒接收了100字节长度payload。 电流表抓取RX2结果如图4-3所示:
根据结果显示,当发送模组发送数据包时,RX2在唤醒后检测到TX数据,判断地址不匹配后,计算出剩余preamble和payload时长,休眠该时间后,唤醒重新进行接收检测。串口打印RX2结果如图4-4所示:
根据结果显示,RX2判断地址不匹配后直接休眠不再进行数据接收,所以未打印任何接收数信息。
5 系统演示板¶
演示系统板基于 HC32F460EVB的底板功能描述如图 5- 1 所示
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,ADDR支持8bit配置,SF5仅支持0b00xx00xx(0x11,0x12,0x13,0x21,0x22,0x23,0x31,0x32,0x33),SF6支持0b0xxx0xxx,这里仍然要求满足不支持小于0x11和不支持0xX0值。
(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配置,SF5仅支持0b00xx00xx(0x11,0x12,0x13,0x21,0x22,0x23,0x31,0x32,0x33),SF6支持0b0xxx0xxx,这里仍然要求满足不支持小于0x11和不支持0xX0值。
6.4 Preamble数量配置¶
(1)每个Field中第一个Group内Preamble(pg1)的数量最小为8。
(2)所有的Field都发送完毕后syncword前Preamble(pn)的数量最小为8。
6.5 休眠时间¶
根据参数算出后续preamble接收时间,进入休眠时休眠时间需注意减去休眠,休眠唤醒及其他代码运行时间,尽量稍微提前唤醒,避免唤醒错过syncword,无法接收payload数据。