detect_chip 0x60000078
UART_DATE_REG_ADDR = 0x60000078 # used to differentiate ESP8266 vs ESP32*
UART_DATE_REG2_ADDR = 0x3f400074 # used to differentiate ESP32S2 vs other models
uart_register.h` 中定义如下所示:(这里为何读取0x60000078, REG_UART_BASE( i )的确定在哪里)
#define DR_REG_UART_BASE 0x3ff40000
#define REG_UART_BASE( i ) (DR_REG_UART_BASE + (i) * 0x10000 + ( (i) > 1 ? 0xe000 : 0 ) )
#define REG_UART_AHB_BASE(i) (0x60000000 + (i) * 0x10000 + ( (i) > 1 ? 0xe000 : 0 ) )
#define UART_FIFO_AHB_REG(i) (REG_UART_AHB_BASE(i) + 0x0)
#define UART_FIFO_REG(i) (REG_UART_BASE(i) + 0x0)
#define UART_DATE_REG(i) (REG_UART_BASE(i) + 0x78)
/* UART_DATE : R/W ;bitpos:[31:0] ;default: 32'h15122500 ; */
(1) 从esp32 的技术手册未查找到的 0x60000078 的内容
(2) 该寄存器在 esptool.py 的注释
“”" Use serial access to detect the chip type.
We use the UART’s datecode register for this, it’s mapped at
the same address on ESP8266 & ESP32 so we can use one
memory read and compare to the datecode register for each chip
type.
This routine automatically performs ESPLoader.connect() (passing
connect_mode parameter) as part of querying the chip.
“”"
而在 esp32.peripherals.ld
中,UART 的外设地址如下:
PROVIDE ( UART0 = 0x3ff40000 );
PROVIDE ( UART1 = 0x3ff50000 );
PROVIDE ( UART2 = 0x3ff6E000 );
则,读该寄存器,内容为 0x15122500
,那么识别此芯片为 ESP32.
detect_chip 0x60000078
UART_DATE_REG_ADDR = 0x60000078 # used to differentiate ESP8266 vs ESP32*
uart_register.h
中定义如下所示:
#define REG_UART_BASE(i) (0x60000000 + (i)*0xf00)
//version value:32'h062000
...
#define UART_DATE(i) (REG_UART_BASE(i) + 0x78)
esp8266 的技术手册中描述如下:
则,读该寄存器,内容为 0x60000200
,那么识别此芯片为 ESP8266.
ESP8266 技术手册中只有 GPIO, SPI, UART 寄存器的介绍, 然而并没有将介绍 efuse 寄存器,只能从代码中获取此部分信息。
esp8266/efuse_register.h
的定义如下图所示:
#define DR_REG_EFUSE_BASE 0x3FF00050
#define EFUSE_DATA0_REG (DR_REG_EFUSE_BASE + 0x000)
#define EFUSE_IS_ESP8285 (1 << 4)
返回的128 bits of ESP8266 efuse
//esptool.py code
ESP_OTP_MAC0 = 0x3ff00050
ESP_OTP_MAC1 = 0x3ff00054
ESP_OTP_MAC4 = 0x3ff00058
ESP_OTP_MAC3 = 0x3ff0005c
则,(efuses & ((1 << 4)) != 0 ,芯片就是ESP8285.
然而 esptool.py
中的判断如下:
is_8285 = (efuses & ((1 << 4) | 1 << 80)) != 0 # One or the other efuse bit is set for ESP8285
难道 第 4 bit 和 第 80 bit 只有 1 bit 是 1, 就可以识别为 8285 了?
MAC 地址的读取也是从 efuse 寄存器读取,如下图,可在技术
esp32/include/soc/efuse_reg.h
的定义如下图所示:
#define DR_REG_EFUSE_BASE 0x3ff5A000
#define EFUSE_BLK0_RDATA0_REG (DR_REG_EFUSE_BASE + 0x000)
利用这个信息可在技术手册找到相应内容:
接下来:我们直接将 efuse 区 dump 出来:
$ espefuse.py --port /dev/ttyUSB2 dump
espefuse.py v2.8
Connecting........_
EFUSE block 0:
00000000 c4014d9c 00eb240a 00000000 00000032 00000000 00000004
EFUSE block 1:
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
EFUSE block 2:
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
EFUSE block 3:
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
然后,我们利用 esptool 直接读出 mac 地址:
$ esptool.py read_mac
esptool.py v2.8
...
MAC: 24:0a:c4:01:4d:9c
...
Hard resetting via RTS pin...
可以看出:esp32 的 mac 地址为 EFUSE_BLK0_RDATA2_REG 中 EFUSE_RD_WIFI_MAC_CRC_HIGH 值 与 EFUSE_BLK0_RDATA1_REG 的值拼接之后的后六个字节,其中 EFUSE_RD_WIFI_MAC_CRC_HIGH 值的第一个字节是 mac 地址的校验码
最后进行验证:
$ espefuse.py --port /dev/ttyUSB1 summary
espefuse.py v2.8
Connecting........_
...
Identity fuses:
MAC Factory MAC Address
= 24:0a:c4:01:4d:9c (CRC 0xeb OK) R/W
...
存在的疑问:esptool.py 中 EFUSE_REG_BASE = 0x6001a000 ,而不是 0x3ff5A000
//esptool.py
EFUSE_REG_BASE = 0x6001a000
针对 esp8266, 貌似不能用 espefuse.py 命令来 dump efuse. 也没有找到公开的文档描述,SDK 中efuse_register.h 的信息也很少。
$ espefuse.py --port /dev/ttyUSB1 dump
espefuse.py v2.8
Connecting....
A fatal error occurred: Timed out waiting for packet header
这里只是从 esptool.py 的源码中来解读 esp8266 的 mac 地址是如何计算出来的。
首先,从如下的 efuse 地址中获取数值,为对应寄存器的值,其中,可以从代码中看出寄存器的位数为32.
ESP_OTP_MAC0 = 0x3ff00050
ESP_OTP_MAC1 = 0x3ff00054
ESP_OTP_MAC3 = 0x3ff0005c
def read_mac(self):
""" Read MAC from OTP ROM """
mac0 = self.read_reg(self.ESP_OTP_MAC0)
mac1 = self.read_reg(self.ESP_OTP_MAC1)
mac3 = self.read_reg(self.ESP_OTP_MAC3)
if (mac3 != 0):
oui = ((mac3 >> 16) & 0xff, (mac3 >> 8) & 0xff, mac3 & 0xff)
elif ((mac1 >> 16) & 0xff) == 0:
oui = (0x18, 0xfe, 0x34)
elif ((mac1 >> 16) & 0xff) == 1:
oui = (0xac, 0xd0, 0x74)
else:
raise FatalError("Unknown OUI")
return oui + ((mac1 >> 8) & 0xff, mac1 & 0xff, (mac0 >> 24) & 0xff)
这里用表格来表示寄存器:
MAC3
F | E | D | C | B | A | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0H |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
F | E | D | C | B | A | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0L |
MAC1:
F | E | D | C | B | A | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0H |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
F | E | D | C | B | A | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0L |
MAC0:
F | E | D | C | B | A | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0H |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
F | E | D | C | B | A | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0L |
如果 MAC3 的值不为 0 时,芯片 mac 地址的组成为:A:B:C:D:E:F(如下所示)
A: (mac3 >> 16) & 0xff
* |
* |
* |
* |
* |
* |
* |
* |
* |
* |
* |
* |
* |
* |
* |
* H |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
L |
B: (mac3 >> 8) & 0xff
* |
* |
* |
* |
* |
* |
* |
* H |
||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
* |
* |
* |
* |
* |
* |
* |
* |
L |
C: (mac3 >> 16) & 0xff
H | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
* |
* |
* |
* |
* |
* |
* |
* |
* |
* |
* |
* |
* |
* |
* |
* L |
D: (mac1 >> 8) & 0xff
* |
* |
* |
* |
* |
* |
* |
* H |
||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
* |
* |
* |
* |
* |
* |
* |
* |
L |
E: mac1 & 0xff
H | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
* |
* |
* |
* |
* |
* |
* |
* |
* |
* |
* |
* |
* |
* |
* |
* L |
F: (mac0 >> 24) & 0xff
* |
* |
* |
* |
* |
* |
* |
* |
H | |||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
* L |
如果 MAC3 的值为 0 时,MAC1 的高 16 位为0, 芯片 mac 地址的组成为:0x18 : 0xfe : 0x34 : D : E : F(DEF 如上所示)
如果 MAC3 的值为 0 时,MAC1 的高 16 位为1, 芯片 mac 地址的组成为:0xac : 0xd0 : 0x74 : D : E : F(DEF 如上所示)
除此以外的情况,芯片 mac 地址都不会识别出来。
关于 芯片mac 地址的一点说明:
esp8266 有 chip_id, esp32 没有 chip_id
其中,chid_ip 长 4 个字节,低三字节为 mac 地址,最高字节为 0.
可能写入又有了别的用途,被覆盖
esp-idf/examples/get-started/hello_world$ esptool.py write_mem 0x3FFAF000 0xAAAAAAAA 0xFFFFFFFF
esptool.py v2.8
Found 2 serial ports
Serial port /dev/ttyUSB1
Connecting....
Detecting chip type... ESP32
Chip is ESP32D0WDQ6 (revision 0)
Features: WiFi, BT, Dual Core, Coding Scheme None
Crystal is 40MHz
MAC: 24:0a:c4:01:4d:9c
Uploading stub...
Running stub...
Stub running...
Wrote aaaaaaaa, mask ffffffff to 3ffaf000
Hard resetting via RTS pin...
esp-idf/examples/get-started/hello_world$ esptool.py read_mem 0x3FFAF000
esptool.py v2.8
Found 2 serial ports
Serial port /dev/ttyUSB1
Connecting........__
Detecting chip type... ESP32
Chip is ESP32D0WDQ6 (revision 0)
Features: WiFi, BT, Dual Core, Coding Scheme None
Crystal is 40MHz
MAC: 24:0a:c4:01:4d:9c
Uploading stub...
Running stub...
Stub running...
0x3ffaf000 = 0x6129e3c8
Hard resetting via RTS pin...