WhyCan Forum(哇酷开发者社区)

感谢为中文互联网持续输出优质内容的各位老铁们。 QQ: 516333132, 微信(wechat): whycan_cn (哇酷网/挖坑网/填坑网) service@whycan.cn

您尚未登录。

#1 2020-11-21 21:23:35

libc0607
会员
注册时间: 2018-12-13
累计积分: 12

关于联盛德W600 Wi-Fi部分的一点探索:自由通信接口、2.2G~2.8G中心频率、5/10MHz传输带宽

注1:这些内容同时发在了 Github 上, https://github.com/libc0607/w60x-rf-hacking 
注2:内容仅供学习,请遵守当地无线电法规,调试请上衰减器,搞事和楼主无关
注3:超出芯片设计工作范围外可能会造成损坏,和楼主无关

0. 简介
W600 是个对标 ESP8266 的 Wi-Fi 芯片, 晕哥早先的贴子里有介绍 https://whycan.com/t_1928.html
楼主通过逆向 SDK 中的 libwlan,得以扩展了一下它的中心频率
这里记录一下整个过程,万一有人用得上。。

2312

1. 关于中心频率
W600 的 SDK 仅有 libwlan 没有开源,但是保留了符号。
首先用 7z 解压,其中的 1.txt 记录了每个 .o 文件中对外提供的函数接口,如图

7z

list

通过搜索channel等关键词,觉得tls_wl_rf.o中应该有比较有趣的东西
载入IDA Pro,看到函数列表

ida

wm_rf_set_channel很是显眼,反编译出如下

int *__fastcall wm_rf_set_channel(int a1, unsigned int a2)
{
  unsigned int v2; // r4
  int v3; // r5
  int v4; // r0
  int v5; // r1
  unsigned int v6; // r0
  int v7; // r6
  int v8; // r0
  int *result; // r0

  v2 = a2;
  v3 = a1;
  if ( a2 <= 1 )
  {
    rf_spi_write(rf_chan24g_20m[2 * a1]);
    rf_spi_write(rf_chan24g_20m[2 * v3 + 1]);
    v4 = wm_rf_band_switch(0);
    v5 = tls_os_set_critical(v4);
    v6 = MEMORY[0x40001400] & 0xFFFFFFDF;
LABEL_8:
    MEMORY[0x40001400] = v6;
    tls_os_release_critical(v5);
    goto LABEL_9;
  }
  if ( a2 <= 3 )
  {
    if ( a2 == 2 )
      v7 = central_freq[2 * a1];
    else
      v7 = central_freq[2 * a1 + 1];
    rf_spi_write(rf_chan24g_20m[2 * v7]);
    rf_spi_write(rf_chan24g_20m[2 * v7 + 1]);
    v8 = wm_rf_band_switch(1);
    v5 = tls_os_set_critical(v8);
    if ( v2 == 2 )
      v6 = MEMORY[0x40001400] & 0xFFFEFF3F | 0xA0;
    else
      v6 = MEMORY[0x40001400] & 0xFFFFFF3F | 0x100E0;
    goto LABEL_8;
  }
LABEL_9:
  result = &hed_rf_current_channel;
  hed_rf_current_channel = v3;
  *(_DWORD *)&hed_rf_chan_type = v2;
  return result;
}

这里明显调用了一个 rf_spi_write()

int __fastcall rf_spi_write(int a1)
{
  MEMORY[0x40011408] = a1 << 10;
  tls_wl_delay(1);
  MEMORY[0x40011400] = 1;
  while ( MEMORY[0x40011404] & 0x40000 )
    ;
  return tls_wl_delay(1);
}
int __fastcall rf_spi_read(int a1)
{
  MEMORY[0x40011408] = (a1 << 27) | 0x4000000;
  tls_wl_delay(10);
  MEMORY[0x40011400] = 1;
  while ( MEMORY[0x40011404] & 0x40000 )
    ;
  tls_wl_delay(200);
  return MEMORY[0x4001140C] >> 16;
}

看到这里直接操作了寄存器,查找手册中的寄存器分布

reg1

reg2

可以猜测,他们在Wi-Fi部分使用的频率合成器是通过SPI接口控制的,他们在APB上挂了一个简易的SPI控制器用来控制频率合成器
根据读写函数,容易猜测该简易SPI控制器的寄存器 MEMORY[0x40011408] 的结构为

5'b<addr> + 1'b<read/write> + 16'b<data> + 10'b <unknown/padding>

那接下来的方向就是找出他们往频率合成器中写了什么数据
wm_rf_set_channel 这个函数中涉及了两个表:rf_chan24g_20m[] 与 central_freq[]

.data:000009B4                 EXPORT rf_chan24g_20m
.data:000009B4 ; _DWORD rf_chan24g_20m[30]
.data:000009B4 rf_chan24g_20m  DCD 0, 0, 0x2A203, 0x43333, 0x2A204, 0x48888, 0x2A205
.data:000009B4                                         ; DATA XREF: wm_rf_set_channel+4↑o
.data:000009B4                                         ; wm_rf_set_channel:loc_1BA↑o ...
.data:000009B4                 DCD 0x4DDDD, 0x2A207, 0x43333, 0x2A208, 0x48888, 0x2A209
.data:000009B4                 DCD 0x4DDDD, 0x2A20B, 0x43333, 0x2A20C, 0x48888, 0x2A20D
.data:000009B4                 DCD 0x4DDDD, 0x2A20F, 0x43333, 0x2A600, 0x48888, 0x2A601
.data:000009B4                 DCD 0x4DDDD, 0x2A603, 0x43333, 0x2A606, 0x46666
.constdata:000008BC                 EXPORT central_freq
.constdata:000008BC ; _DWORD central_freq[30]
.constdata:000008BC central_freq    DCD 0, 0, 3, 3, 4, 4, 1, 5, 2, 6, 3, 7, 4, 8, 5, 9, 6
.constdata:000008BC                                         ; DATA XREF: wm_rf_set_channel+3C↑o
.constdata:000008BC                                         ; wm_rf_init:off_438↑o ...
.constdata:000008BC                 DCD 0xA, 7, 0xB, 8, 0xC, 9, 0xD, 0xA, 0xA, 0xB, 0xB, 0 ; Alternative name is 'BuildAttributes$$THM_ISAv4$P$D$K$B$S$PE$A:L22UL41UL21$X:L11$S22US41US21$IEEE1$IW$USESV6$~STKCKD$USESV7$~SHL$OSPACE$EBA8$REQ8$PRES8$EABIv2'
.constdata:000008BC                 DCD 0
.constdata:000008BC ; .constdata    ends
.constdata:000008BC

这种 0x3333, 0x8888, 0xDDDD 的感觉很像是频率合成器的小数部分,而central_freq这个一看就明白了是给ht40-和ht40+用的。。
这样 wm_rf_set_channel 的两个参数就容易明白了,分别为频道与带宽模式
结合前面猜出的结构,整理往 rf synth 中某个寄存器可能写入的数据如下:

const uint32_t rf_chan24g_20m[] = {
	
//	<reg:0x1>	<reg:0x2>	chan 	freq	reg			    int		frac
	0x2A203, 	0x43333, //1		  2412	0xA2033333	40		0x33333
	0x2A204, 	0x48888, // 2		  2417	0xA2048888	40		0x48888
	0x2A205, 	0x4DDDD, // 3		  2422	0xA205DDDD	40		0x5DDDD
	0x2A207, 	0x43333, // 4		  2427	0xA2073333	40		0x73333
	0x2A208, 	0x48888, // 5		  2432	0xA2088888	40		0x88888
	0x2A209, 	0x4DDDD, // 6		  2437	0xA209DDDD	40		0x9DDDD
	0x2A20B, 	0x43333, // 7		  2442	0xA20B3333	40		0xB3333
	0x2A20C, 	0x48888, // 8		  2447	0xA20C8888	40		0xC8888
	0x2A20D, 	0x4DDDD, // 9		  2452	0xA20DDDDD	40		0xDDDDD
	0x2A20F, 	0x43333, // 10		2457	0xA20F3333	40		0xF3333
	0x2A600, 	0x48888, // 11		2462	0xA6008888	41		0x08888
	0x2A601, 	0x4DDDD, // 12		2467	0xA601DDDD	41		0x1DDDD
	0x2A603, 	0x43333, // 13		2472	0xA6033333	41		0x33333
	0x2A606, 	0x46666, // 14		2484	0xA6066666	41		0x66666
}

这里的推导过程省略,主要是观察到
1.在2457-2462之间发生了进位
2. 在1-10频道中每次增加的小数分频值代表5MHz
最终得出 W60x 的频率合成器计算公式为

F = 60 MHz * (int + frac/0xFFFFF)

并且该寄存器的结构为

6'b<int> + 6'b<unknown???> + 20'b<frac>

(楼主有个想法,新出的那个 W800 如果用的也是相同的 IPCore……

最后作为老缝合怪,可以在 arduino 环境中糊出一堆勉强能用的测试代码
在我的这块 TB-01 开发板上,频率范围在 2161MHz~2931MHz 之间调节时,频谱都没有出现明显不对劲(PLL锁上了大概
但射频性能在 Wi-Fi 频段以外会明显劣化,故不建议使用偏移过远的中心频率

// Notice that 'extern "C"' 
extern "C" {
  #include <wm_wifi.h>
  #include <wm_osal.h>
}

void _rf_spi_w(int arg)
{
  *((uint32_t*)0x40011408) = arg << 10;    
  delayMicroseconds(1);
  *((uint32_t*)0x40011400) = 1;
  while(*((uint32_t*)0x40011404) & 0x40000);
  delayMicroseconds(1);
  return;
}

void w60x_set_center_frequency_20mbw(uint32_t freq_mhz) 
{
  uint32_t spi_reg1, spi_reg2, reg_synth;
  uint32_t chan_div_int, chan_div_frac;
  uint32_t cpu_sr;
  
  chan_div_int = 0x0000003F & (freq_mhz/60);
  chan_div_frac = 0x000FFFFF & ( ((freq_mhz-(chan_div_int*60)) * (0xFFFFF)) / 60 );
  
  reg_synth = 0x02000000 | (chan_div_int << 26) | (chan_div_frac);
  spi_reg1 = 0x00020000 | (reg_synth >> 16);
  spi_reg2 = 0x00040000 | (reg_synth & 0x0000FFFF);
  
  _rf_spi_w(spi_reg1);
  _rf_spi_w(spi_reg2);

  // wm_rf_band_switch @20MHz BW
  _rf_spi_w(0x102640);  //write(0x8, 0x2640)
  _rf_spi_w(0x146967);  //write(0xA, 0x6967)
  _rf_spi_w(0x102641);  //write(0x8, 0x2641)
  delayMicroseconds(180);
  _rf_spi_w(0x102740);  //write(0x8, 0x2740)
  _rf_spi_w(0x145327);  //write(0xA, 0x5327)
  _rf_spi_w(0x102741);  //write(0x8, 0x2741)
  delayMicroseconds(180);
  _rf_spi_w(0x1027C1);  //write(0x8, 0x27C1)
  _rf_spi_w(0x10CDC0);  //write(0x8, 0xCDC0)
  // end of wm_rf_band_switch @20MHz BW

  // I don't know what's 0x40001400 controls
  cpu_sr  = tls_os_set_critical();
  *((uint32_t*)0x40001400) = *((uint32_t*)0x40001400) & 0xFFFFFFDF;
  tls_os_release_critical(cpu_sr);  

  return;
}

2. 关于频宽
W60X 传输时占用的频宽可以通过调节 WLAN 系统根时钟分频系数来改变。
蛋疼的事是APB时钟又从这个时钟分频而来,改变这里的时钟会导致APB下面挂的所有设备跟着改变;
即,假如写了 Serial.begin(230400); 又写了 w60x_set_wlan_channel_bw(10); 那串口实际只有 115200。

关于更改时钟分频系数的部分,寄存器手册里说得比较清楚;
直接上代码,可以实现 5/10/20MHz 传输带宽:

// usable bw_mhz: 20(default), 10, 5
// note1: this func assume cpu is running at 80MHz
// note2: this func affect all devices' clock under APB
// (e.g. set channel bw to 10MHz & set UART to 115200 ==> you'll get a 57600 UART)
void w60x_set_wlan_channel_bw(uint32_t bw_mhz)
{
  uint32_t reg, clk_mhz;
  uint8_t wlan_div, bus2_factor; 
  
  reg = *((uint32_t*)0x40000710);
  clk_mhz = bw_mhz * 8;
  
  switch(clk_mhz) {
  case 80:
    wlan_div = 2;
    bus2_factor = 4;
  break;
  case 40:
    wlan_div = 4;
    bus2_factor = 8;
  break;
  default:  // 160mhz
    wlan_div = 1;
    bus2_factor = 2;
  break;
  }
  
  reg &= ~(0x00000FF0);
  reg |= (wlan_div <<4);
  reg |= (bus2_factor <<8);

  *((uint32_t*)0x40000710) = reg;
  delayMicroseconds(1);
  *((uint32_t*)0x40000710) = reg | 0x80000000;
  delayMicroseconds(1);
  
  return;
}

3.自由通信接口 & 一个测试 Demo

官方给了个文档叫  《WM_WiFi_自由通信接口使用指导》,参考这个接口糊了一堆测试代码
在 2.17GHz~2.87GHz 之间,以 100MHz 步进, 10MHz 频宽通信,跳频点灯,亲测可用,需要两块板子

代码见
https://github.com/libc0607/w60x-rf-hacking/tree/main/w60x-rf-rx

https://github.com/libc0607/w60x-rf-hacking/tree/main/w60x-rf-tx

(楼主代码水平不行 轻喷(

离线

#2 2020-11-21 22:23:00

k455619
会员
注册时间: 2018-07-29
累计积分: 148

Re: 关于联盛德W600 Wi-Fi部分的一点探索:自由通信接口、2.2G~2.8G中心频率、5/10MHz传输带宽

牛逼!!!!!!

离线

#3 2020-11-22 17:33:45

le062
会员
注册时间: 2019-02-07
累计积分: 16

Re: 关于联盛德W600 Wi-Fi部分的一点探索:自由通信接口、2.2G~2.8G中心频率、5/10MHz传输带宽

强大  big_smile big_smile big_smile

离线

#4 2020-11-22 21:22:29

aozima
会员
所在地: 深圳
注册时间: 2019-05-25
累计积分: 133
个人网站

Re: 关于联盛德W600 Wi-Fi部分的一点探索:自由通信接口、2.2G~2.8G中心频率、5/10MHz传输带宽

orz...

离线

#5 2020-11-22 22:10:56

rick lou
会员
注册时间: 2019-09-12
累计积分: 96

Re: 关于联盛德W600 Wi-Fi部分的一点探索:自由通信接口、2.2G~2.8G中心频率、5/10MHz传输带宽

ida使用给下截图

离线

#6 2020-11-23 16:30:26

sy373466062
会员
注册时间: 2018-11-12
累计积分: 81

Re: 关于联盛德W600 Wi-Fi部分的一点探索:自由通信接口、2.2G~2.8G中心频率、5/10MHz传输带宽

有些意思。

离线

#7 2020-11-23 19:34:08

dgtg
会员
注册时间: 2017-11-08
累计积分: 181

Re: 关于联盛德W600 Wi-Fi部分的一点探索:自由通信接口、2.2G~2.8G中心频率、5/10MHz传输带宽

厉害了!
是不是说可以使用非标的2.4G频率来通信了?
可以避免wifi干扰?

离线

#8 2020-11-23 22:30:39

libc0607
会员
注册时间: 2018-12-13
累计积分: 12

Re: 关于联盛德W600 Wi-Fi部分的一点探索:自由通信接口、2.2G~2.8G中心频率、5/10MHz传输带宽

rick lou 说:

ida使用给下截图

呃 是指使用过程么。。觉得麻烦就没全截图
关键部分我都摘出来了,如果需要的话我截个大致的步骤

离线

#9 2020-11-23 22:34:10

libc0607
会员
注册时间: 2018-12-13
累计积分: 12

Re: 关于联盛德W600 Wi-Fi部分的一点探索:自由通信接口、2.2G~2.8G中心频率、5/10MHz传输带宽

dgtg 说:

厉害了!
是不是说可以使用非标的2.4G频率来通信了?
可以避免wifi干扰?

是,很多网桥像ubnt之类的,就有2.3~2.7G的频率范围
还有像是openhd这类图传,用ath9k也可以解锁一些频率
不过要小心避开LTE频段,也不要搞大功率,小心喝茶。。(

离线

#10 2020-11-24 09:22:00

dgtg
会员
注册时间: 2017-11-08
累计积分: 181

Re: 关于联盛德W600 Wi-Fi部分的一点探索:自由通信接口、2.2G~2.8G中心频率、5/10MHz传输带宽

libc0607 说:
dgtg 说:

厉害了!
是不是说可以使用非标的2.4G频率来通信了?
可以避免wifi干扰?

是,很多网桥像ubnt之类的,就有2.3~2.7G的频率范围
还有像是openhd这类图传,用ath9k也可以解锁一些频率
不过要小心避开LTE频段,也不要搞大功率,小心喝茶。。(

厉害啊!避开2.4G间的干扰,大有可为啊!

离线

页脚

工信部备案:粤ICP备20025096号 Powered by FluxBB