IDF release/v3.2 d3e562907 (#3292)

This commit is contained in:
Me No Dev 2019-10-01 11:21:44 +03:00 committed by GitHub
parent 40ebee1cb1
commit 5f1dff7dad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
85 changed files with 978 additions and 295 deletions

View File

@ -22,7 +22,7 @@ compiler.warning_flags.all=-Wall -Werror=all -Wextra
compiler.path={runtime.tools.xtensa-esp32-elf-gcc.path}/bin/
compiler.sdk.path={runtime.platform.path}/tools/sdk
compiler.cpreprocessor.flags=-DESP_PLATFORM -DMBEDTLS_CONFIG_FILE="mbedtls/esp_config.h" -DHAVE_CONFIG_H "-I{compiler.sdk.path}/include/config" "-I{compiler.sdk.path}/include/app_trace" "-I{compiler.sdk.path}/include/app_update" "-I{compiler.sdk.path}/include/asio" "-I{compiler.sdk.path}/include/bootloader_support" "-I{compiler.sdk.path}/include/bt" "-I{compiler.sdk.path}/include/coap" "-I{compiler.sdk.path}/include/console" "-I{compiler.sdk.path}/include/driver" "-I{compiler.sdk.path}/include/esp-tls" "-I{compiler.sdk.path}/include/esp32" "-I{compiler.sdk.path}/include/esp_adc_cal" "-I{compiler.sdk.path}/include/esp_event" "-I{compiler.sdk.path}/include/esp_http_client" "-I{compiler.sdk.path}/include/esp_http_server" "-I{compiler.sdk.path}/include/esp_https_ota" "-I{compiler.sdk.path}/include/esp_ringbuf" "-I{compiler.sdk.path}/include/ethernet" "-I{compiler.sdk.path}/include/expat" "-I{compiler.sdk.path}/include/fatfs" "-I{compiler.sdk.path}/include/freemodbus" "-I{compiler.sdk.path}/include/freertos" "-I{compiler.sdk.path}/include/heap" "-I{compiler.sdk.path}/include/idf_test" "-I{compiler.sdk.path}/include/jsmn" "-I{compiler.sdk.path}/include/json" "-I{compiler.sdk.path}/include/libsodium" "-I{compiler.sdk.path}/include/log" "-I{compiler.sdk.path}/include/lwip" "-I{compiler.sdk.path}/include/mbedtls" "-I{compiler.sdk.path}/include/mdns" "-I{compiler.sdk.path}/include/micro-ecc" "-I{compiler.sdk.path}/include/mqtt" "-I{compiler.sdk.path}/include/newlib" "-I{compiler.sdk.path}/include/nghttp" "-I{compiler.sdk.path}/include/nvs_flash" "-I{compiler.sdk.path}/include/openssl" "-I{compiler.sdk.path}/include/protobuf-c" "-I{compiler.sdk.path}/include/protocomm" "-I{compiler.sdk.path}/include/pthread" "-I{compiler.sdk.path}/include/sdmmc" "-I{compiler.sdk.path}/include/smartconfig_ack" "-I{compiler.sdk.path}/include/soc" "-I{compiler.sdk.path}/include/spi_flash" "-I{compiler.sdk.path}/include/spiffs" "-I{compiler.sdk.path}/include/tcp_transport" "-I{compiler.sdk.path}/include/tcpip_adapter" "-I{compiler.sdk.path}/include/ulp" "-I{compiler.sdk.path}/include/vfs" "-I{compiler.sdk.path}/include/wear_levelling" "-I{compiler.sdk.path}/include/wifi_provisioning" "-I{compiler.sdk.path}/include/wpa_supplicant" "-I{compiler.sdk.path}/include/xtensa-debug-module" "-I{compiler.sdk.path}/include/esp-face" "-I{compiler.sdk.path}/include/esp32-camera" "-I{compiler.sdk.path}/include/esp-face" "-I{compiler.sdk.path}/include/fb_gfx"
compiler.cpreprocessor.flags=-DESP_PLATFORM -DMBEDTLS_CONFIG_FILE="mbedtls/esp_config.h" -DHAVE_CONFIG_H -DGCC_NOT_5_2_0=0 -DWITH_POSIX "-I{compiler.sdk.path}/include/config" "-I{compiler.sdk.path}/include/app_trace" "-I{compiler.sdk.path}/include/app_update" "-I{compiler.sdk.path}/include/asio" "-I{compiler.sdk.path}/include/bootloader_support" "-I{compiler.sdk.path}/include/bt" "-I{compiler.sdk.path}/include/coap" "-I{compiler.sdk.path}/include/console" "-I{compiler.sdk.path}/include/driver" "-I{compiler.sdk.path}/include/esp-tls" "-I{compiler.sdk.path}/include/esp32" "-I{compiler.sdk.path}/include/esp_adc_cal" "-I{compiler.sdk.path}/include/esp_event" "-I{compiler.sdk.path}/include/esp_http_client" "-I{compiler.sdk.path}/include/esp_http_server" "-I{compiler.sdk.path}/include/esp_https_ota" "-I{compiler.sdk.path}/include/esp_ringbuf" "-I{compiler.sdk.path}/include/ethernet" "-I{compiler.sdk.path}/include/expat" "-I{compiler.sdk.path}/include/fatfs" "-I{compiler.sdk.path}/include/freemodbus" "-I{compiler.sdk.path}/include/freertos" "-I{compiler.sdk.path}/include/heap" "-I{compiler.sdk.path}/include/idf_test" "-I{compiler.sdk.path}/include/jsmn" "-I{compiler.sdk.path}/include/json" "-I{compiler.sdk.path}/include/libsodium" "-I{compiler.sdk.path}/include/log" "-I{compiler.sdk.path}/include/lwip" "-I{compiler.sdk.path}/include/mbedtls" "-I{compiler.sdk.path}/include/mdns" "-I{compiler.sdk.path}/include/micro-ecc" "-I{compiler.sdk.path}/include/mqtt" "-I{compiler.sdk.path}/include/newlib" "-I{compiler.sdk.path}/include/nghttp" "-I{compiler.sdk.path}/include/nvs_flash" "-I{compiler.sdk.path}/include/openssl" "-I{compiler.sdk.path}/include/protobuf-c" "-I{compiler.sdk.path}/include/protocomm" "-I{compiler.sdk.path}/include/pthread" "-I{compiler.sdk.path}/include/sdmmc" "-I{compiler.sdk.path}/include/smartconfig_ack" "-I{compiler.sdk.path}/include/soc" "-I{compiler.sdk.path}/include/spi_flash" "-I{compiler.sdk.path}/include/spiffs" "-I{compiler.sdk.path}/include/tcp_transport" "-I{compiler.sdk.path}/include/tcpip_adapter" "-I{compiler.sdk.path}/include/ulp" "-I{compiler.sdk.path}/include/vfs" "-I{compiler.sdk.path}/include/wear_levelling" "-I{compiler.sdk.path}/include/wifi_provisioning" "-I{compiler.sdk.path}/include/wpa_supplicant" "-I{compiler.sdk.path}/include/xtensa-debug-module" "-I{compiler.sdk.path}/include/esp-face" "-I{compiler.sdk.path}/include/esp32-camera" "-I{compiler.sdk.path}/include/esp-face" "-I{compiler.sdk.path}/include/fb_gfx"
compiler.c.cmd=xtensa-esp32-elf-gcc
compiler.c.flags=-std=gnu99 -Os -g3 -fstack-protector -ffunction-sections -fdata-sections -fstrict-volatile-bitfields -mlongcalls -nostdlib -Wpointer-arith {compiler.warning_flags} -Wno-maybe-uninitialized -Wno-unused-function -Wno-unused-but-set-variable -Wno-unused-variable -Wno-deprecated-declarations -Wno-unused-parameter -Wno-sign-compare -Wno-old-style-declaration -MMD -c
@ -35,7 +35,7 @@ compiler.S.flags=-c -g3 -x assembler-with-cpp -MMD -mlongcalls
compiler.c.elf.cmd=xtensa-esp32-elf-gcc
compiler.c.elf.flags=-nostdlib "-L{compiler.sdk.path}/lib" "-L{compiler.sdk.path}/ld" -T esp32_out.ld -T esp32.common.ld -T esp32.rom.ld -T esp32.peripherals.ld -T esp32.rom.libgcc.ld -T esp32.rom.spiram_incompatible_fns.ld -u ld_include_panic_highint_hdl -u call_user_start_cpu0 -Wl,--gc-sections -Wl,-static -Wl,--undefined=uxTopUsedPriority -u __cxa_guard_dummy -u __cxx_fatal_exception
compiler.c.elf.libs=-lgcc -lopenssl -lbtdm_app -lfatfs -lwps -lcoexist -lwear_levelling -lesp_http_client -lprotobuf-c -lhal -lnewlib -ldriver -lbootloader_support -lpp -lfreemodbus -lmesh -lsmartconfig -ljsmn -lwpa -lethernet -lphy -lapp_trace -lconsole -lulp -lwpa_supplicant -lfreertos -lbt -lmicro-ecc -lesp32-camera -lcxx -lxtensa-debug-module -ltcp_transport -lmdns -lvfs -lesp_ringbuf -lsoc -lcore -lfb_gfx -lsdmmc -llibsodium -lcoap -ltcpip_adapter -lprotocomm -lesp_event -limage_util -lc_nano -lesp-tls -lasio -lrtc -lspi_flash -lwpa2 -lwifi_provisioning -lesp32 -lface_recognition -lapp_update -lnghttp -lspiffs -lface_detection -lespnow -lnvs_flash -lesp_adc_cal -llog -ldl_lib -lsmartconfig_ack -lexpat -lm -lfr -lmqtt -lc -lheap -lmbedtls -llwip -lnet80211 -lesp_http_server -lpthread -ljson -lesp_https_ota -lfd -lstdc++
compiler.c.elf.libs=-lgcc -lesp32 -lphy -lesp_http_client -lmbedtls -lrtc -lesp_http_server -lbtdm_app -lspiffs -lbootloader_support -lmdns -lnvs_flash -lfatfs -lpp -lnet80211 -ljsmn -lface_detection -llibsodium -lvfs -ldl_lib -llog -lfreertos -lcxx -lsmartconfig_ack -lxtensa-debug-module -lheap -ltcpip_adapter -lmqtt -lulp -lfd -lfb_gfx -lnghttp -lprotocomm -lsmartconfig -lm -lethernet -limage_util -lc_nano -lsoc -ltcp_transport -lc -lmicro-ecc -lface_recognition -ljson -lwpa_supplicant -lmesh -lesp_https_ota -lwpa2 -lexpat -llwip -lwear_levelling -lapp_update -ldriver -lbt -lespnow -lcoap -lasio -lnewlib -lconsole -lapp_trace -lesp32-camera -lhal -lprotobuf-c -lsdmmc -lcore -lpthread -lcoexist -lfreemodbus -lspi_flash -lesp-tls -lwpa -lwifi_provisioning -lwps -lesp_adc_cal -lesp_event -lopenssl -lesp_ringbuf -lfr -lstdc++
compiler.as.cmd=xtensa-esp32-elf-as

View File

@ -60,7 +60,7 @@ except ImportError:
"Check the README for installation instructions." % (sys.VERSION, sys.executable))
raise
__version__ = "2.6"
__version__ = "2.8-dev"
MAX_UINT32 = 0xffffffff
MAX_UINT24 = 0xffffff
@ -135,6 +135,15 @@ except NameError:
basestring = str
def _mask_to_shift(mask):
""" Return the index of the least significant bit in the mask """
shift = 0
while mask & 0x1 == 0:
shift += 1
mask >>= 1
return shift
def esp8266_function_only(func):
""" Attribute for a function only supported on ESP8266 """
return check_supported_function(func, lambda o: o.CHIP_NAME == "ESP8266")
@ -180,6 +189,9 @@ class ESPLoader(object):
ESP_READ_FLASH = 0xD2
ESP_RUN_USER_CODE = 0xD3
# Flash encryption debug more command
ESP_FLASH_ENCRYPT_DATA = 0xD4
# Maximum block sized for RAM and Flash writes, respectively.
ESP_RAM_BLOCK = 0x1800
@ -197,8 +209,11 @@ class ESPLoader(object):
# Flash sector size, minimum unit of erase.
FLASH_SECTOR_SIZE = 0x1000
# This register happens to exist on both ESP8266 & ESP32
UART_DATA_REG_ADDR = 0x60000078
UART_CLKDIV_MASK = 0xFFFFF
# Memory addresses
IROM_MAP_START = 0x40200000
IROM_MAP_END = 0x40300000
@ -467,8 +482,8 @@ class ESPLoader(object):
print('') # end 'Connecting...' line
raise FatalError('Failed to connect to %s: %s' % (self.CHIP_NAME, last_error))
""" Read memory address in target """
def read_reg(self, addr):
""" Read memory address in target """
# we don't call check_command here because read_reg() function is called
# when detecting chip type, and the way we check for success (STATUS_BYTES_LENGTH) is different
# for different chip types (!)
@ -477,11 +492,28 @@ class ESPLoader(object):
raise FatalError.WithResult("Failed to read register address %08x" % addr, data)
return val
""" Write to memory address in target """
def write_reg(self, addr, value, mask=0xFFFFFFFF, delay_us=0):
""" Write to memory address in target
Note: mask option is not supported by stub loaders, use update_reg() function.
"""
return self.check_command("write target memory", self.ESP_WRITE_REG,
struct.pack('<IIII', addr, value, mask, delay_us))
def update_reg(self, addr, mask, new_val):
""" Update register at 'addr', replace the bits masked out by 'mask'
with new_val. new_val is shifted left to match the LSB of 'mask'
Returns just-written value of register.
"""
shift = _mask_to_shift(mask)
val = self.read_reg(addr)
val &= ~mask
val |= (new_val << shift) & mask
self.write_reg(addr, val)
return val
""" Start downloading an application image to RAM """
def mem_begin(self, size, blocks, blocksize, offset):
if self.IS_STUB: # check we're not going to overwrite a running stub with this data
@ -549,6 +581,14 @@ class ESPLoader(object):
self.checksum(data),
timeout=timeout)
""" Encrypt before writing to flash """
def flash_encrypt_block(self, data, seq, timeout=DEFAULT_TIMEOUT):
self.check_command("Write encrypted to target Flash after seq %d" % seq,
self.ESP_FLASH_ENCRYPT_DATA,
struct.pack('<IIII', len(data), seq, 0, 0) + data,
self.checksum(data),
timeout=timeout)
""" Leave flash mode and run/reboot """
def flash_finish(self, reboot=False):
pkt = struct.pack('<I', int(not reboot))
@ -706,6 +746,7 @@ class ESPLoader(object):
progress_fn(len(data), length)
if len(data) > length:
raise FatalError('Read more than expected')
digest_frame = self.read()
if len(digest_frame) != 16:
raise FatalError('Expected digest, got: %s' % hexify(digest_frame))
@ -899,6 +940,22 @@ class ESPLoader(object):
self.run_spiflash_command(SPIFLASH_WRDI)
def get_crystal_freq(self):
# Figure out the crystal frequency from the UART clock divider
# Returns a normalized value in integer MHz (40 or 26 are the only supported values)
#
# The logic here is:
# - We know that our baud rate and the ESP UART baud rate are roughly the same, or we couldn't communicate
# - We can read the UART clock divider register to know how the ESP derives this from the APB bus frequency
# - Multiplying these two together gives us the bus frequency which is either the crystal frequency (ESP32)
# or double the crystal frequency (ESP8266). See the self.XTAL_CLK_DIVIDER parameter for this factor.
uart_div = self.read_reg(self.UART_CLKDIV_REG) & self.UART_CLKDIV_MASK
est_xtal = (self._port.baudrate * uart_div) / 1e6 / self.XTAL_CLK_DIVIDER
norm_xtal = 40 if est_xtal > 33 else 26
if abs(norm_xtal - est_xtal) > 1:
print("WARNING: Detected crystal freq %.2fMHz is quite different to normalized freq %dMHz. Unsupported crystal in use?" % (est_xtal, norm_xtal))
return norm_xtal
def hard_reset(self):
self._setRTS(True) # EN->LOW
time.sleep(0.1)
@ -943,6 +1000,10 @@ class ESP8266ROM(ESPLoader):
SPI_W0_OFFS = 0x40
SPI_HAS_MOSI_DLEN_REG = False
UART_CLKDIV_REG = 0x60000014
XTAL_CLK_DIVIDER = 2
FLASH_SIZES = {
'512KB':0x00,
'256KB':0x10,
@ -957,6 +1018,11 @@ class ESP8266ROM(ESPLoader):
BOOTLOADER_FLASH_OFFSET = 0
MEMORY_MAP = [[0x3FF00000, 0x3FF00010, "DPORT"],
[0x3FFE8000, 0x40000000, "DRAM"],
[0x40100000, 0x40108000, "IRAM"],
[0x40201010, 0x402E1010, "IROM"]]
def get_efuses(self):
# Return the 128 bits of ESP8266 efuse as a single Python integer
return (self.read_reg(0x3ff0005c) << 96 |
@ -1055,6 +1121,7 @@ class ESP32ROM(ESPLoader):
"""
CHIP_NAME = "ESP32"
IMAGE_CHIP_ID = 0
IS_STUB = False
DATE_REG_VALUE = 0x15122500
@ -1070,9 +1137,15 @@ class ESP32ROM(ESPLoader):
SPI_REG_BASE = 0x60002000
EFUSE_REG_BASE = 0x6001a000
DR_REG_SYSCON_BASE = 0x3ff66000
SPI_W0_OFFS = 0x80
SPI_HAS_MOSI_DLEN_REG = True
UART_CLKDIV_REG = 0x3ff40014
XTAL_CLK_DIVIDER = 1
FLASH_SIZES = {
'1MB':0x00,
'2MB':0x10,
@ -1085,9 +1158,77 @@ class ESP32ROM(ESPLoader):
OVERRIDE_VDDSDIO_CHOICES = ["1.8V", "1.9V", "OFF"]
MEMORY_MAP = [[0x3F400000, 0x3F800000, "DROM"],
[0x3F800000, 0x3FC00000, "EXTRAM_DATA"],
[0x3FF80000, 0x3FF82000, "RTC_DRAM"],
[0x3FF90000, 0x40000000, "BYTE_ACCESSIBLE"],
[0x3FFAE000, 0x40000000, "DRAM"],
[0x3FFAE000, 0x40000000, "DMA"],
[0x3FFE0000, 0x3FFFFFFC, "DIRAM_DRAM"],
[0x40000000, 0x40070000, "IROM"],
[0x40070000, 0x40078000, "CACHE_PRO"],
[0x40078000, 0x40080000, "CACHE_APP"],
[0x40080000, 0x400A0000, "IRAM"],
[0x400A0000, 0x400BFFFC, "DIRAM_IRAM"],
[0x400C0000, 0x400C2000, "RTC_IRAM"],
[0x400D0000, 0x40400000, "IROM"],
[0x50000000, 0x50002000, "RTC_DATA"]]
""" Try to read the BLOCK1 (encryption key) and check if it is valid """
def is_flash_encryption_key_valid(self):
""" Bit 0 of efuse_rd_disable[3:0] is mapped to BLOCK1
this bit is at position 16 in EFUSE_BLK0_RDATA0_REG """
word0 = self.read_efuse(0)
rd_disable = (word0 >> 16) & 0x1
# reading of BLOCK1 is NOT ALLOWED so we assume valid key is programmed
if rd_disable:
return True
else:
""" reading of BLOCK1 is ALLOWED so we will read and verify for non-zero.
When ESP32 has not generated AES/encryption key in BLOCK1, the contents will be readable and 0.
If the flash encryption is enabled it is expected to have a valid non-zero key. We break out on
first occurance of non-zero value """
key_word = [0] * 7
for i in range(len(key_word)):
key_word[i] = self.read_efuse(14 + i)
# key is non-zero so break & return
if key_word[i] != 0:
return True
return False
""" For flash encryption related commands we need to make sure
user has programmed all the relevant efuse correctly so at
the end of write_flash_encrypt esptool will verify the values
of flash_crypt_config to be non zero if they are not read
protected. If the values are zero a warning will be printed
"""
def get_flash_crypt_config(self):
""" bit 3 in efuse_rd_disable[3:0] is mapped to flash_crypt_config
this bit is at position 19 in EFUSE_BLK0_RDATA0_REG """
word0 = self.read_efuse(0)
rd_disable = (word0 >> 19) & 0x1
if rd_disable == 0:
""" we can read the flash_crypt_config efuse value
so go & read it (EFUSE_BLK0_RDATA5_REG[31:28]) """
word5 = self.read_efuse(5)
word5 = (word5 >> 28) & 0xF
return word5
else:
# if read of the efuse is disabled we assume it is set correctly
return 0xF
def get_chip_description(self):
word3 = self.read_efuse(3)
chip_ver_rev1 = (word3 >> 15) & 0x1
word5 = self.read_efuse(5)
apb_ctl_date = self.read_reg(self.DR_REG_SYSCON_BASE + 0x7C)
rev_bit0 = (word3 >> 15) & 0x1
rev_bit1 = (word5 >> 20) & 0x1
rev_bit2 = (apb_ctl_date >> 31) & 0x1
pkg_version = (word3 >> 9) & 0x07
chip_name = {
@ -1097,7 +1238,16 @@ class ESP32ROM(ESPLoader):
5: "ESP32-PICO-D4",
}.get(pkg_version, "unknown ESP32")
return "%s (revision %d)" % (chip_name, chip_ver_rev1)
chip_revision = 0
if rev_bit0:
if rev_bit1:
if rev_bit2:
chip_revision = 3
else:
chip_revision = 2
else:
chip_revision = 1
return "%s (revision %d)" % (chip_name, chip_revision)
def get_chip_features(self):
features = ["WiFi"]
@ -1298,11 +1448,11 @@ class BaseFirmwareImage(object):
self.elf_sha256_offset = 0
def load_common_header(self, load_file, expected_magic):
(magic, segments, self.flash_mode, self.flash_size_freq, self.entrypoint) = struct.unpack('<BBBBI', load_file.read(8))
(magic, segments, self.flash_mode, self.flash_size_freq, self.entrypoint) = struct.unpack('<BBBBI', load_file.read(8))
if magic != expected_magic:
raise FatalError('Invalid firmware image magic=0x%x' % (magic))
return segments
if magic != expected_magic:
raise FatalError('Invalid firmware image magic=0x%x' % (magic))
return segments
def verify(self):
if len(self.segments) > 16:
@ -1328,16 +1478,19 @@ class BaseFirmwareImage(object):
def maybe_patch_segment_data(self, f, segment_data):
"""If SHA256 digest of the ELF file needs to be inserted into this segment, do so. Returns segment data."""
segment_len = len(segment_data)
file_pos = f.tell()
file_pos = f.tell() # file_pos is position in the .bin file
if self.elf_sha256_offset >= file_pos and self.elf_sha256_offset < file_pos + segment_len:
# SHA256 digest needs to be patched into this segment,
# calculate offset of the digest inside the segment.
# SHA256 digest needs to be patched into this binary segment,
# calculate offset of the digest inside the binary segment.
patch_offset = self.elf_sha256_offset - file_pos
# Sanity checks
if patch_offset < self.SEG_HEADER_LEN or patch_offset + self.SHA256_DIGEST_LEN > segment_len:
raise FatalError('Can not place SHA256 digest on segment boundary' +
raise FatalError('Cannot place SHA256 digest on segment boundary' +
'(elf_sha256_offset=%d, file_pos=%d, segment_size=%d)' %
(self.elf_sha256_offset, file_pos, segment_len))
if segment_data[patch_offset:patch_offset + self.SHA256_DIGEST_LEN] != b'\x00' * self.SHA256_DIGEST_LEN:
raise FatalError('Contents of segment at SHA256 digest offset 0x%x are not all zero. Refusing to overwrite.' %
self.elf_sha256_offset)
assert(len(self.elf_sha256) == self.SHA256_DIGEST_LEN)
# offset relative to the data part
patch_offset -= self.SEG_HEADER_LEN
@ -1386,12 +1539,12 @@ class BaseFirmwareImage(object):
return ESP8266ROM.IROM_MAP_START <= addr < ESP8266ROM.IROM_MAP_END
def get_irom_segment(self):
irom_segments = [s for s in self.segments if self.is_irom_addr(s.addr)]
if len(irom_segments) > 0:
if len(irom_segments) != 1:
raise FatalError('Found %d segments that could be irom0. Bad ELF file?' % len(irom_segments))
return irom_segments[0]
return None
irom_segments = [s for s in self.segments if self.is_irom_addr(s.addr)]
if len(irom_segments) > 0:
if len(irom_segments) != 1:
raise FatalError('Found %d segments that could be irom0. Bad ELF file?' % len(irom_segments))
return irom_segments[0]
return None
def get_non_irom_segments(self):
irom_segment = self.get_irom_segment()
@ -1440,6 +1593,9 @@ class ESP8266ROMFirmwareImage(BaseFirmwareImage):
self.append_checksum(f, checksum)
ESP8266ROM.BOOTLOADER_IMAGE = ESP8266ROMFirmwareImage
class ESP8266V2FirmwareImage(BaseFirmwareImage):
""" 'Version 2' firmware image, segments loaded by software bootloader stub
(ie Espressif bootloader or rboot)
@ -1558,7 +1714,7 @@ class ESP32FirmwareImage(BaseFirmwareImage):
# to be set to this value so ROM bootloader will skip it.
WP_PIN_DISABLED = 0xEE
EXTENDED_HEADER_STRUCT_FMT = "B" * 16
EXTENDED_HEADER_STRUCT_FMT = "<BBBBHB" + ("B" * 8) + "B"
IROM_ALIGN = 65536
@ -1576,6 +1732,7 @@ class ESP32FirmwareImage(BaseFirmwareImage):
self.cs_drv = 0
self.hd_drv = 0
self.wp_drv = 0
self.min_rev = 0
self.append_digest = True
@ -1745,15 +1902,21 @@ class ESP32FirmwareImage(BaseFirmwareImage):
self.d_drv, self.cs_drv = split_byte(fields[2])
self.hd_drv, self.wp_drv = split_byte(fields[3])
if fields[15] in [0, 1]:
self.append_digest = (fields[15] == 1)
else:
raise RuntimeError("Invalid value for append_digest field (0x%02x). Should be 0 or 1.", fields[15])
chip_id = fields[4]
if chip_id != self.ROM_LOADER.IMAGE_CHIP_ID:
print("Unexpected chip id in image. Expected %d but value was %d. Is this image for a different chip model?" % (self.ROM_LOADER.IMAGE_CHIP_ID, chip_id))
# remaining fields in the middle should all be zero
if any(f for f in fields[4:15] if f != 0):
# reserved fields in the middle should all be zero
if any(f for f in fields[6:-1] if f != 0):
print("Warning: some reserved header fields have non-zero values. This image may be from a newer esptool.py?")
append_digest = fields[-1] # last byte is append_digest
if append_digest in [0, 1]:
self.append_digest = (append_digest == 1)
else:
raise RuntimeError("Invalid value for append_digest field (0x%02x). Should be 0 or 1.", append_digest)
def save_extended_header(self, save_file):
def join_byte(ln,hn):
return (ln & 0x0F) + ((hn & 0x0F) << 4)
@ -1763,14 +1926,19 @@ class ESP32FirmwareImage(BaseFirmwareImage):
fields = [self.wp_pin,
join_byte(self.clk_drv, self.q_drv),
join_byte(self.d_drv, self.cs_drv),
join_byte(self.hd_drv, self.wp_drv)]
fields += [0] * 11
join_byte(self.hd_drv, self.wp_drv),
self.ROM_LOADER.IMAGE_CHIP_ID,
self.min_rev]
fields += [0] * 8 # padding
fields += [append_digest]
packed = struct.pack(self.EXTENDED_HEADER_STRUCT_FMT, *fields)
save_file.write(packed)
ESP32ROM.BOOTLOADER_IMAGE = ESP32FirmwareImage
class ELFFile(object):
SEC_TYPE_PROGBITS = 0x01
SEC_TYPE_STRTAB = 0x03
@ -2087,8 +2255,26 @@ def _update_image_flash_params(esp, address, args, image):
# unpack the (potential) image header
magic, _, flash_mode, flash_size_freq = struct.unpack("BBBB", image[:4])
if address != esp.BOOTLOADER_FLASH_OFFSET or magic != esp.ESP_IMAGE_MAGIC:
return image # not flashing a bootloader, so don't modify this
if address != esp.BOOTLOADER_FLASH_OFFSET:
return image # not flashing bootloader offset, so don't modify this
if (args.flash_mode, args.flash_freq, args.flash_size) == ('keep',) * 3:
return image # all settings are 'keep', not modifying anything
# easy check if this is an image: does it start with a magic byte?
if magic != esp.ESP_IMAGE_MAGIC:
print("Warning: Image file at 0x%x doesn't look like an image file, so not changing any flash settings." % address)
return image
# make sure this really is an image, and not just data that
# starts with esp.ESP_IMAGE_MAGIC (mostly a problem for encrypted
# images that happen to start with a magic byte
try:
test_image = esp.BOOTLOADER_IMAGE(io.BytesIO(image))
test_image.verify()
except Exception:
print("Warning: Image file at 0x%x is not a valid %s image, so not changing any flash settings." % (address,esp.CHIP_NAME))
return image
if args.flash_mode != 'keep':
flash_mode = {'qio':0, 'qout':1, 'dio':2, 'dout': 3}[args.flash_mode]
@ -2115,23 +2301,53 @@ def write_flash(esp, args):
if args.compress is None and not args.no_compress:
args.compress = not args.no_stub
# For encrypt option we do few sanity checks before actual flash write
if args.encrypt:
do_write = True
crypt_cfg_efuse = esp.get_flash_crypt_config()
if crypt_cfg_efuse != 0xF:
print('\nWARNING: Unexpected FLASH_CRYPT_CONFIG value', hex(crypt_cfg_efuse))
print('\nMake sure flash encryption is enabled correctly, refer to Flash Encryption documentation')
do_write = False
enc_key_valid = esp.is_flash_encryption_key_valid()
if not enc_key_valid:
print('\nFlash encryption key is not programmed')
print('\nMake sure flash encryption is enabled correctly, refer to Flash Encryption documentation')
do_write = False
if (esp.FLASH_WRITE_SIZE % 32) != 0:
print('\nWARNING - Flash write address is not aligned to the recommeded 32 bytes')
do_write = False
if not do_write and not args.ignore_flash_encryption_efuse_setting:
raise FatalError("Incorrect efuse setting: aborting flash write")
# verify file sizes fit in flash
flash_end = flash_size_bytes(args.flash_size)
for address, argfile in args.addr_filename:
argfile.seek(0,2) # seek to end
if address + argfile.tell() > flash_end:
raise FatalError(("File %s (length %d) at offset %d will not fit in %d bytes of flash. " +
"Use --flash-size argument, or change flashing address.")
% (argfile.name, argfile.tell(), address, flash_end))
argfile.seek(0)
if args.flash_size != 'keep': # TODO: check this even with 'keep'
flash_end = flash_size_bytes(args.flash_size)
for address, argfile in args.addr_filename:
argfile.seek(0,2) # seek to end
if address + argfile.tell() > flash_end:
raise FatalError(("File %s (length %d) at offset %d will not fit in %d bytes of flash. " +
"Use --flash-size argument, or change flashing address.")
% (argfile.name, argfile.tell(), address, flash_end))
argfile.seek(0)
if args.erase_all:
erase_flash(esp, args)
if args.encrypt and args.compress:
print('\nWARNING: - compress and encrypt options are mutually exclusive ')
print('Will flash uncompressed')
args.compress = False
for address, argfile in args.addr_filename:
if args.no_stub:
print('Erasing flash...')
image = pad_to(argfile.read(), 4)
image = pad_to(argfile.read(), 32 if args.encrypt else 4)
if len(image) == 0:
print('WARNING: File %s is empty' % argfile.name)
continue
@ -2159,7 +2375,10 @@ def write_flash(esp, args):
else:
# Pad the last block
block = block + b'\xff' * (esp.FLASH_WRITE_SIZE - len(block))
esp.flash_block(block, seq)
if args.encrypt:
esp.flash_encrypt_block(block, seq)
else:
esp.flash_block(block, seq)
image = image[esp.FLASH_WRITE_SIZE:]
seq += 1
written += len(block)
@ -2173,17 +2392,19 @@ def write_flash(esp, args):
if t > 0.0:
speed_msg = " (%.1f kbit/s)" % (written / t * 8 / 1000)
print('\rWrote %d bytes at 0x%08x in %.1f seconds%s...' % (written, address, t, speed_msg))
try:
res = esp.flash_md5sum(address, uncsize)
if res != calcmd5:
print('File md5: %s' % calcmd5)
print('Flash md5: %s' % res)
print('MD5 of 0xFF is %s' % (hashlib.md5(b'\xFF' * uncsize).hexdigest()))
raise FatalError("MD5 of file does not match data in flash!")
else:
print('Hash of data verified.')
except NotImplementedInROMError:
pass
if not args.encrypt:
try:
res = esp.flash_md5sum(address, uncsize)
if res != calcmd5:
print('File md5: %s' % calcmd5)
print('Flash md5: %s' % res)
print('MD5 of 0xFF is %s' % (hashlib.md5(b'\xFF' * uncsize).hexdigest()))
raise FatalError("MD5 of file does not match data in flash!")
else:
print('Hash of data verified.')
except NotImplementedInROMError:
pass
print('\nLeaving...')
@ -2207,11 +2428,12 @@ def image_info(args):
print('Image version: %d' % image.version)
print('Entry point: %08x' % image.entrypoint if image.entrypoint != 0 else 'Entry point not set')
print('%d segments' % len(image.segments))
print
print()
idx = 0
for seg in image.segments:
idx += 1
print('Segment %d: %r' % (idx, seg))
seg_name = ", ".join([seg_range[2] for seg_range in image.ROM_LOADER.MEMORY_MAP if seg_range[0] <= seg.addr < seg_range[1]])
print('Segment %d: %r [%s]' % (idx, seg, seg_name))
calc_checksum = image.calculate_checksum()
print('Checksum: %02x (%s)' % (image.checksum,
'valid' if image.checksum == calc_checksum else 'invalid - calculated %02x' % calc_checksum))
@ -2249,6 +2471,7 @@ def elf2image(args):
if args.chip == 'esp32':
image = ESP32FirmwareImage()
image.secure_pad = args.secure_pad
image.min_rev = int(args.min_rev)
elif args.version == '1': # ESP8266
image = ESP8266ROMFirmwareImage()
else:
@ -2397,7 +2620,8 @@ def main(custom_commandline=None):
Main function for esptool
custom_commandline - Optional override for default arguments parsing (that uses sys.argv), can be a list of custom arguments
as strings.
as strings. Arguments and their values need to be added as individual items to the list e.g. "-b 115200" thus
becomes ['-b', '115200'].
"""
parser = argparse.ArgumentParser(description='esptool.py v%s - ESP8266 ROM Bootloader Utility' % __version__, prog='esptool')
@ -2483,6 +2707,11 @@ def main(custom_commandline=None):
extra_keep_args = [] if is_elf2image else ['keep']
auto_detect = not is_elf2image
if auto_detect:
extra_fs_message = ", detect, or keep"
else:
extra_fs_message = ""
parent.add_argument('--flash_freq', '-ff', help='SPI Flash frequency',
choices=extra_keep_args + ['40m', '26m', '20m', '80m'],
default=os.environ.get('ESPTOOL_FF', '40m' if is_elf2image else 'keep'))
@ -2490,12 +2719,15 @@ def main(custom_commandline=None):
choices=extra_keep_args + ['qio', 'qout', 'dio', 'dout'],
default=os.environ.get('ESPTOOL_FM', 'qio' if is_elf2image else 'keep'))
parent.add_argument('--flash_size', '-fs', help='SPI Flash size in MegaBytes (1MB, 2MB, 4MB, 8MB, 16M)'
' plus ESP8266-only (256KB, 512KB, 2MB-c1, 4MB-c1)',
' plus ESP8266-only (256KB, 512KB, 2MB-c1, 4MB-c1)' + extra_fs_message,
action=FlashSizeAction, auto_detect=auto_detect,
default=os.environ.get('ESPTOOL_FS', 'detect' if auto_detect else '1MB'))
add_spi_connection_arg(parent)
parser_write_flash = subparsers.add_parser('write_flash', help='Write a binary blob to flash')
parser_write_flash = subparsers.add_parser(
'write_flash',
help='Write a binary blob to flash')
parser_write_flash.add_argument('addr_filename', metavar='<address> <filename>', help='Address followed by binary filename, separated by space',
action=AddrFilenamePairAction)
parser_write_flash.add_argument('--erase-all', '-e',
@ -2506,6 +2738,10 @@ def main(custom_commandline=None):
parser_write_flash.add_argument('--no-progress', '-p', help='Suppress progress output', action="store_true")
parser_write_flash.add_argument('--verify', help='Verify just-written data on flash ' +
'(mostly superfluous, data is read back during flashing)', action='store_true')
parser_write_flash.add_argument('--encrypt', help='Encrypt before write ',
action='store_true')
parser_write_flash.add_argument('--ignore-flash-encryption-efuse-setting', help='Ignore flash encryption efuse settings ',
action='store_true')
compress_args = parser_write_flash.add_mutually_exclusive_group(required=False)
compress_args.add_argument('--compress', '-z', help='Compress data in transfer (default unless --no-stub is specified)',action="store_true", default=None)
@ -2534,6 +2770,7 @@ def main(custom_commandline=None):
parser_elf2image.add_argument('input', help='Input ELF file')
parser_elf2image.add_argument('--output', '-o', help='Output filename prefix (for version 1 image), or filename (for version 2 single image)', type=str)
parser_elf2image.add_argument('--version', '-e', help='Output image version', choices=['1','2'], default='1')
parser_elf2image.add_argument('--min-rev', '-r', help='Minimum chip revision', choices=['0','1','2','3'], default='0')
parser_elf2image.add_argument('--secure-pad', action='store_true', help='Pad image so once signed it will end on a 64KB boundary. For ESP32 images only.')
parser_elf2image.add_argument('--elf-sha256-offset', help='If set, insert SHA256 hash (32 bytes) of the input ELF file at specified offset in the binary.',
type=arg_auto_int, default=None)
@ -2658,12 +2895,14 @@ def main(custom_commandline=None):
print("%s failed to connect: %s" % (each_port, err))
esp = None
if esp is None:
raise FatalError("All of the %d available serial ports could not connect to a Espressif device." % len(ser_list))
raise FatalError("Could not connect to an Espressif device on any of the %d available serial ports." % len(ser_list))
print("Chip is %s" % (esp.get_chip_description()))
print("Features: %s" % ", ".join(esp.get_chip_features()))
print("Crystal is %dMHz" % esp.get_crystal_freq())
read_mac(esp, args)
if not args.no_stub:
@ -2692,7 +2931,8 @@ def main(custom_commandline=None):
if hasattr(args, "flash_size"):
print("Configuring flash size...")
detect_flash_size(esp, args)
esp.flash_set_parameters(flash_size_bytes(args.flash_size))
if args.flash_size != 'keep': # TODO: should set this even with 'keep'
esp.flash_set_parameters(flash_size_bytes(args.flash_size))
try:
operation_func(esp, args)
@ -2775,6 +3015,7 @@ class FlashSizeAction(argparse.Action):
known_sizes.update(ESP32ROM.FLASH_SIZES)
if self._auto_detect:
known_sizes['detect'] = 'detect'
known_sizes['keep'] = 'keep'
if value not in known_sizes:
raise argparse.ArgumentError(self, '%s is not a known flash size. Known sizes: %s' % (value, ", ".join(known_sizes.keys())))
setattr(namespace, self.dest, value)
@ -2846,104 +3087,105 @@ class AddrFilenamePairAction(argparse.Action):
# Binary stub code (see flasher_stub dir for source & details)
ESP8266ROM.STUB_CODE = eval(zlib.decompress(base64.b64decode(b"""
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\
""")))
ESP32ROM.STUB_CODE = eval(zlib.decompress(base64.b64decode(b"""
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\
""")))

View File

@ -165,7 +165,7 @@ env.Append(
],
LIBS=[
"-lgcc", "-lopenssl", "-lbtdm_app", "-lfatfs", "-lwps", "-lcoexist", "-lwear_levelling", "-lesp_http_client", "-lprotobuf-c", "-lhal", "-lnewlib", "-ldriver", "-lbootloader_support", "-lpp", "-lfreemodbus", "-lmesh", "-lsmartconfig", "-ljsmn", "-lwpa", "-lethernet", "-lphy", "-lapp_trace", "-lconsole", "-lulp", "-lwpa_supplicant", "-lfreertos", "-lbt", "-lmicro-ecc", "-lesp32-camera", "-lcxx", "-lxtensa-debug-module", "-ltcp_transport", "-lmdns", "-lvfs", "-lesp_ringbuf", "-lsoc", "-lcore", "-lfb_gfx", "-lsdmmc", "-llibsodium", "-lcoap", "-ltcpip_adapter", "-lprotocomm", "-lesp_event", "-limage_util", "-lc_nano", "-lesp-tls", "-lasio", "-lrtc", "-lspi_flash", "-lwpa2", "-lwifi_provisioning", "-lesp32", "-lface_recognition", "-lapp_update", "-lnghttp", "-lspiffs", "-lface_detection", "-lespnow", "-lnvs_flash", "-lesp_adc_cal", "-llog", "-ldl_lib", "-lsmartconfig_ack", "-lexpat", "-lm", "-lfr", "-lmqtt", "-lc", "-lheap", "-lmbedtls", "-llwip", "-lnet80211", "-lesp_http_server", "-lpthread", "-ljson", "-lesp_https_ota", "-lfd", "-lstdc++"
"-lgcc", "-lesp32", "-lphy", "-lesp_http_client", "-lmbedtls", "-lrtc", "-lesp_http_server", "-lbtdm_app", "-lspiffs", "-lbootloader_support", "-lmdns", "-lnvs_flash", "-lfatfs", "-lpp", "-lnet80211", "-ljsmn", "-lface_detection", "-llibsodium", "-lvfs", "-ldl_lib", "-llog", "-lfreertos", "-lcxx", "-lsmartconfig_ack", "-lxtensa-debug-module", "-lheap", "-ltcpip_adapter", "-lmqtt", "-lulp", "-lfd", "-lfb_gfx", "-lnghttp", "-lprotocomm", "-lsmartconfig", "-lm", "-lethernet", "-limage_util", "-lc_nano", "-lsoc", "-ltcp_transport", "-lc", "-lmicro-ecc", "-lface_recognition", "-ljson", "-lwpa_supplicant", "-lmesh", "-lesp_https_ota", "-lwpa2", "-lexpat", "-llwip", "-lwear_levelling", "-lapp_update", "-ldriver", "-lbt", "-lespnow", "-lcoap", "-lasio", "-lnewlib", "-lconsole", "-lapp_trace", "-lesp32-camera", "-lhal", "-lprotobuf-c", "-lsdmmc", "-lcore", "-lpthread", "-lcoexist", "-lfreemodbus", "-lspi_flash", "-lesp-tls", "-lwpa", "-lwifi_provisioning", "-lwps", "-lesp_adc_cal", "-lesp_event", "-lopenssl", "-lesp_ringbuf", "-lfr", "-lstdc++"
],
LIBSOURCE_DIRS=[

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -14,6 +14,7 @@
#pragma once
#include "esp_flash_data_types.h"
#include "esp_image_format.h"
/// Type of hold a GPIO in low state
typedef enum {
@ -92,6 +93,17 @@ bool bootloader_common_label_search(const char *list, char *label);
*/
esp_err_t bootloader_common_get_sha256_of_partition(uint32_t address, uint32_t size, int type, uint8_t *out_sha_256);
/**
* @brief Check if the image (bootloader and application) has valid chip ID and revision
*
* @param img_hdr: image header
* @return
* - ESP_OK: image and chip are matched well
* - ESP_FAIL: image doesn't match to the chip
*/
esp_err_t bootloader_common_check_chip_validity(const esp_image_header_t* img_hdr);
/**
* @brief Configure VDDSDIO, call this API to rise VDDSDIO to 1.9V when VDDSDIO regulator is enabled as 1.8V mode.
*/

View File

@ -91,6 +91,13 @@ esp_err_t esp_efuse_apply_34_encoding(const uint8_t *in_bytes, uint32_t *out_wor
*/
void esp_efuse_write_random_key(uint32_t blk_wdata0_reg);
/**
* @brief Returns chip version from efuse
*
* @return chip version
*/
uint8_t esp_efuse_get_chip_ver(void);
#ifdef __cplusplus
}
#endif

View File

@ -55,6 +55,19 @@ typedef enum {
#define ESP_IMAGE_HEADER_MAGIC 0xE9
/**
* @brief ESP chip ID
*
*/
typedef enum {
ESP_CHIP_ID_ESP32 = 0x0000, /*!< chip ID: ESP32 */
ESP_CHIP_ID_INVALID = 0xFFFF /*!< Invalid chip ID (we defined it to make sure the esp_chip_id_t is 2 bytes size) */
} __attribute__((packed)) esp_chip_id_t;
/** @cond */
_Static_assert(sizeof(esp_chip_id_t) == 2, "esp_chip_id_t should be 16 bit");
/* Main header of binary image */
typedef struct {
uint8_t magic;
@ -71,8 +84,12 @@ typedef struct {
uint8_t wp_pin;
/* Drive settings for the SPI flash pins (read by ROM bootloader) */
uint8_t spi_pin_drv[3];
/* Reserved bytes in ESP32 additional header space, currently unused */
uint8_t reserved[11];
/*!< Chip identification number */
esp_chip_id_t chip_id;
/*!< Minimum chip revision supported by image */
uint8_t min_chip_rev;
/*!< Reserved bytes in additional header space, currently unused */
uint8_t reserved[8];
/* If 1, a SHA256 digest "simple hash" (of the entire image) is appended after the checksum. Included in image length. This digest
* is separate to secure boot and only used for detecting corruption. For secure boot signed images, the signature
* is appended after this (and the simple hash is included in the signed data). */

View File

@ -75,6 +75,7 @@
#define CONFIG_MBEDTLS_ECP_DP_BP384R1_ENABLED 1
#define CONFIG_MBEDTLS_ECP_DP_SECP256K1_ENABLED 1
#define CONFIG_CAMERA_CORE1 1
#define CONFIG_ESP32_DPORT_DIS_INTERRUPT_LVL 5
#define CONFIG_MB_SERIAL_BUF_SIZE 256
#define CONFIG_CONSOLE_UART_BAUDRATE 115200
#define CONFIG_SPIRAM_SUPPORT 1
@ -153,8 +154,10 @@
#define CONFIG_ADC2_DISABLE_DAC 1
#define CONFIG_HFP_ENABLE 1
#define CONFIG_BLE_ADV_REPORT_FLOW_CONTROL_NUM 100
#define CONFIG_ESP32_REV_MIN_0 1
#define CONFIG_LOG_DEFAULT_LEVEL 1
#define CONFIG_TIMER_QUEUE_LENGTH 10
#define CONFIG_ESP32_REV_MIN 0
#define CONFIG_SUPPRESS_SELECT_DEBUG_OUTPUT 1
#define CONFIG_GATTS_SEND_SERVICE_CHANGE_MODE 0
#define CONFIG_MAKE_WARN_UNDEFINED_VARIABLES 1
@ -295,6 +298,7 @@
#define CONFIG_REDUCE_PHY_TX_POWER 1
#define CONFIG_BOOTLOADER_WDT_TIME_MS 9000
#define CONFIG_FREERTOS_CORETIMER_0 1
#define CONFIG_IDF_FIRMWARE_CHIP_ID 0x0000
#define CONFIG_PARTITION_TABLE_CUSTOM_FILENAME "partitions.csv"
#define CONFIG_MBEDTLS_HAVE_TIME 1
#define CONFIG_FREERTOS_CHECK_STACKOVERFLOW_CANARY 1
@ -336,6 +340,7 @@
#define CONFIG_MQTT_TRANSPORT_WEBSOCKET_SECURE 1
#define CONFIG_SPIFFS_PAGE_SIZE 256
#define CONFIG_MBEDTLS_ECP_DP_SECP192K1_ENABLED 1
#define CONFIG_ESP32_DPORT_WORKAROUND 1
#define CONFIG_PPP_MSCHAP_SUPPORT 1
#define CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0 1
#define CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT 2048
@ -355,3 +360,5 @@
#define CONFIG_ARDUHAL_LOG_DEFAULT_LEVEL_ERROR 1
#define CONFIG_ESP32_WIFI_IRAM_OPT 1
#define CONFIG_FATFS_API_ENCODING_ANSI_OEM 1
#define CONFIG_ARDUINO_IDF_COMMIT "d3e562907"
#define CONFIG_ARDUINO_IDF_BRANCH "release/v3.2"

View File

@ -27,24 +27,22 @@ typedef enum
*/
typedef struct
{
/******* fix start *******/
int w; // Width
int h; // Height
int c; // Channel
int n; // Number, to record filter's out_channels. input and output must be 1
int stride;
fptp_t *item;
/******* fix end *******/
int w; /*!< Width */
int h; /*!< Height */
int c; /*!< Channel */
int n; /*!< Number of filter, input and output must be 1 */
int stride; /*!< Step between lines */
fptp_t *item; /*!< Data */
} dl_matrix3d_t;
typedef struct
{
int w; // Width
int h; // Height
int c; // Channel
int n; // Number, to record filter's out_channels. input and output must be 1
int stride;
uc_t *item;
int w; /*!< Width */
int h; /*!< Height */
int c; /*!< Channel */
int n; /*!< Number of filter, input and output must be 1 */
int stride; /*!< Step between lines */
uc_t *item; /*!< Data */
} dl_matrix3du_t;
typedef struct

View File

@ -3,20 +3,21 @@
typedef int16_t qtp_t;
/*
* Matrix for 3d
* @Warning: the sequence of variables is fixed, cannot be modified, otherwise there will be errors in esp_dsp_dot_float
/**
* Matrix for input, filter, and output
* @Warning: the sequence of variables is fixed, cannot be modified, otherwise there will be errors in
* some handwrite xtensa instruction functions
*/
typedef struct
{
/******* fix start *******/
int w; // Width
int h; // Height
int c; // Channel
int n; // Number, to record filter's out_channels. input and output must be 1
int stride;
int exponent;
qtp_t *item;
int w; /*!< Width */
int h; /*!< Height */
int c; /*!< Channel */
int n; /*!< Number of filter, input and output must be 1 */
int stride; /*!< Step between lines */
int exponent; /*!< Exponent for quantization */
qtp_t *item; /*!< Data */
/******* fix end *******/
} dl_matrix3dq_t;
@ -32,21 +33,28 @@ typedef struct
#define DL_SHIFT_AUTO 32
#endif
/**
* Implementation of matrix relative operations
*/
typedef enum
{
DL_C_IMPL = 0,
DL_XTENSA_IMPL = 1
DL_C_IMPL = 0, /*!< ANSI C */
DL_XTENSA_IMPL = 1 /*!< Handwrite xtensa instruction */
} dl_conv_mode;
/**
* Configuration of mobilenet operation
*/
typedef struct
{
int stride_x;
int stride_y;
dl_padding_type padding;
dl_conv_mode mode;
int dilate_exponent;
int depthwise_exponent;
int compress_exponent;
int stride_x; /*!< Strides of width */
int stride_y; /*!< Strides of height */
dl_padding_type padding; /*!< Padding type */
dl_conv_mode mode; /*!< Implementation mode */
int dilate_exponent; /*!< Exponent of dilation filter */
int depthwise_exponent; /*!< Exponent of depthwise filter */
int compress_exponent; /*!< Exponent of compress filter */
} dl_matrix3dq_mobilenet_config_t;
//
@ -54,75 +62,166 @@ typedef struct
//
/*
* @brief Allocate a 3D matrix
* @brief Allocate a 3d quantised matrix
*
* @param n,w,h,c number, width, height, channel
* @return 3d matrix
* @param n Number of filters, for input and output, should be 1
* @param w Width of matrix
* @param h Height of matrix
* @param c Channel of matrix
* @param e Exponent of matrix data
* @return 3d quantized matrix
*/
dl_matrix3dq_t *dl_matrix3dq_alloc(int n, int w, int h, int c, int e);
/*
* @brief Free a 3D matrix
* @brief Free a 3d quantized matrix
*
* @param m matrix
* @param m 3d quantised matrix
*/
void dl_matrix3dq_free(dl_matrix3dq_t *m);
/**
* @brief Zero out the matrix
* Sets all entries in the matrix to 0.
*
* @param m Matrix to zero
*/
/**
* @brief Copy a range of items from an existing matrix to a preallocated matrix
*
* @param in Old matrix (with foreign data) to re-use. Passing NULL will allocate a new matrix.
* @param dst The resulting slice matrix
* @param src Old matrix to slice.
* @param x X-offset of the origin of the returned matrix within the sliced matrix
* @param y Y-offset of the origin of the returned matrix within the sliced matrix
* @param w Width of the resulting matrix
* @param h Height of the resulting matrix
* @return The resulting slice matrix
*/
void dl_matrix3dq_slice_copy(dl_matrix3dq_t *dst, dl_matrix3dq_t *src, int x, int y, int w, int h);
/**
* @brief Transform a fixed point matrix to a float point matrix
*
* @param m Quantized matrix
* @return Float point matrix
*/
dl_matrix3d_t *dl_matrix3d_from_matrixq(dl_matrix3dq_t *m);
/**
* @brief Transform a float point matrix to a fixed point matrix with pre-defined exponent
*
* @param m Float point matrix
* @param exponent Exponent for resulting matrix
* @return Fixed point matrix
*/
dl_matrix3dq_t *dl_matrixq_from_matrix3d_qmf(dl_matrix3d_t *m, int exponent);
/**
* @brief Transform a float point matrix to a fixed point matrix. The exponent is defined by the distribution of the input matrix.
*
* @param m Float point matrix
* @return Fixed point matrix
*/
dl_matrix3dq_t *dl_matrixq_from_matrix3d(dl_matrix3d_t *m);
qtp_t dl_matrix3dq_quant_range_exceeded_checking(int64_t value, char *location);
/**
* @brief Reform a quantized matrix with exponent
*
* @param out Preallocated resulting matrix
* @param in Input matrix
* @param exponent Exponent for resulting matrix
*/
void dl_matrix3dq_shift_exponent(dl_matrix3dq_t *out, dl_matrix3dq_t *in, int exponent);
/**
* @brief Do batch normalization for a quantized matrix
*
* @param m Input and output quantized matrix, data will be updated
* @param scale Scale of batch-norm
* @param offset Offset of batch-norm
*/
void dl_matrix3dq_batch_normalize(dl_matrix3dq_t *m, dl_matrix3dq_t *scale, dl_matrix3dq_t *offset);
/**
* @brief Add two quantized matrix with a pre-defined exponent
*
* @param in_1 Adder 1
* @param in_2 Adder 2
* @param exponent Exponent for resulting matrix
* @return Result of accumulation of two matrix
*/
dl_matrix3dq_t *dl_matrix3dq_add(dl_matrix3dq_t *in_1, dl_matrix3dq_t *in_2, int exponent);
//
// Activation
//
/**
* @brief Do relu for a quantized matrix
*
* @param in Input and output quantized matrix, data will be updated
*/
void dl_matrix3dq_relu(dl_matrix3dq_t *in);
/**
* @brief Do relu with clips for a quantized matrix
*
* @param in Input and output quantized matrix, data will be updated
* @param clip Float point value to limit the maximum data
*/
void dl_matrix3dq_relu_clip(dl_matrix3dq_t *in, fptp_t clip);
/**
* @brief Do leaky relu for a quantized matrix
*
* @param in Input and output quantized matrix, data will be updated
* @param alpha Float point value to multiply for those less than zero
* @param clip Float point value to limit the maximum data
*/
void dl_matrix3dq_leaky_relu(dl_matrix3dq_t *in, fptp_t alpha, fptp_t clip);
/**
* @brief Do prelu for a quantized matrix
*
* @param in Input and output quantized matrix, data will be updated
* @param alpha Quantized matrix to multiply for those less than zero
*/
void dl_matrix3dq_p_relu(dl_matrix3dq_t *in, dl_matrix3dq_t *alpha);
//
// Concat
//
/**
* @brief Concatenate two quantized matrix in channel
*
* @param in_1 Quantized matrix to be concatenated
* @param in_2 Quantized matrix to be concatenated
* @return Quantized matrix with the same width and height of in_1 and in_2, and with the sum of channel number of in_1 and in_2
*/
dl_matrix3dq_t *dl_matrix3dq_concat(dl_matrix3dq_t *in_1,
dl_matrix3dq_t *in_2);
/**
* @brief Concatenate four quantized matrix in channel
*
* @param in_1 Quantized matrix to be concatenated
* @param in_2 Quantized matrix to be concatenated
* @param in_3 Quantized matrix to be concatenated
* @param in_4 Quantized matrix to be concatenated
* @return Quantized matrix with the same width and height of all inputs, and with the sum of channel number of all inputs
*/
dl_matrix3dq_t *dl_matrix3dq_concat_4(dl_matrix3dq_t *in_1,
dl_matrix3dq_t *in_2,
dl_matrix3dq_t *in_3,
dl_matrix3dq_t *in_4);
/**
* @brief Concatenate four quantized matrix in channel
*
* @param in_1 Quantized matrix to be concatenated
* @param in_2 Quantized matrix to be concatenated
* @param in_3 Quantized matrix to be concatenated
* @param in_4 Quantized matrix to be concatenated
* @param in_5 Quantized matrix to be concatenated
* @param in_6 Quantized matrix to be concatenated
* @param in_7 Quantized matrix to be concatenated
* @param in_8 Quantized matrix to be concatenated
* @return Quantized matrix with the same width and height of all inputs, and with the sum of channel number of all inputs
*/
dl_matrix3dq_t *dl_matrix3dq_concat_8(dl_matrix3dq_t *in_1,
dl_matrix3dq_t *in_2,
dl_matrix3dq_t *in_3,
@ -135,16 +234,42 @@ dl_matrix3dq_t *dl_matrix3dq_concat_8(dl_matrix3dq_t *in_1,
//
// Conv 1x1
//
/**
* @brief Do 1x1 convolution with a quantized matrix
*
* @param out Preallocated quantized matrix, size (1, w, h, n)
* @param in Input matrix, size (1, w, h, c)
* @param filter 1x1 filter, size (n, 1, 1, c)
* @param mode Implementation mode
*/
void dl_matrix3dqq_conv_1x1(dl_matrix3dq_t *out,
dl_matrix3dq_t *in,
dl_matrix3dq_t *filter,
dl_conv_mode mode);
/**
* @brief Do 1x1 convolution with a quantized matrix, with relu activation
*
* @param out Preallocated quantized matrix, size (1, w, h, n)
* @param in Input matrix, size (1, w, h, c)
* @param filter 1x1 filter, size (n, 1, 1, c)
* @param mode Implementation mode
*/
void dl_matrix3dqq_conv_1x1_with_relu(dl_matrix3dq_t *out,
dl_matrix3dq_t *in,
dl_matrix3dq_t *filter,
dl_conv_mode mode);
/**
* @brief Do 1x1 convolution with a quantized matrix, with bias adding
*
* @param out Preallocated quantized matrix, size (1, w, h, n)
* @param in Input matrix, size (1, w, h, c)
* @param filter 1x1 filter, size (n, 1, 1, c)
* @param bias Bias, size (1, 1, 1, n)
* @param mode Implementation mode
* @param name Layer name to debug
*/
void dl_matrix3dqq_conv_1x1_with_bias(dl_matrix3dq_t *out,
dl_matrix3dq_t *in,
dl_matrix3dq_t *filter,
@ -152,23 +277,49 @@ void dl_matrix3dqq_conv_1x1_with_bias(dl_matrix3dq_t *out,
dl_conv_mode mode,
char *name);
void dl_matrix3dqq_conv_1x1_with_prelu(dl_matrix3dq_t *out,
dl_matrix3dq_t *in,
dl_matrix3dq_t *filter,
dl_matrix3dq_t *prelu,
dl_conv_mode mode);
/**
* @brief Do 1x1 convolution with a quantized matrix, with bias adding and relu activation
*
* @param out Preallocated quantized matrix, size (1, w, h, n)
* @param in Input matrix, size (1, w, h, c)
* @param filter 1x1 filter, size (n, 1, 1, c)
* @param bias Bias, size (1, 1, 1, n)
* @param mode Implementation mode
*/
void dl_matrix3dqq_conv_1x1_with_bias_relu(dl_matrix3dq_t *out,
dl_matrix3dq_t *in,
dl_matrix3dq_t *filter,
dl_matrix3dq_t *bias,
dl_conv_mode mode);
void dl_matrix3dqq_conv_1x1_with_prelu(dl_matrix3dq_t *out,
dl_matrix3dq_t *in,
dl_matrix3dq_t *filter,
dl_matrix3dq_t *prelu,
dl_conv_mode mode);
/**
* @brief Do 1x1 convolution with an 8-bit fixed point matrix
*
* @param out Preallocated quantized matrix, size (1, w, h, n)
* @param in Input matrix, size (1, w, h, c)
* @param filter 1x1 filter, size (n, 1, 1, c)
* @param mode Implementation mode
*/
void dl_matrix3duq_conv_1x1(dl_matrix3dq_t *out,
dl_matrix3du_t *in,
dl_matrix3dq_t *filter,
dl_conv_mode mode);
/**
* @brief Do 1x1 convolution with an 8-bit fixed point matrix, with bias adding
*
* @param out Preallocated quantized matrix, size (1, w, h, n)
* @param in Input matrix, size (1, w, h, c)
* @param filter 1x1 filter, size (n, 1, 1, c)
* @param bias Bias, size (1, 1, 1, n)
* @param mode Implementation mode
*/
void dl_matrix3duq_conv_1x1_with_bias(dl_matrix3dq_t *out,
dl_matrix3du_t *in,
dl_matrix3dq_t *filter,
@ -178,12 +329,32 @@ void dl_matrix3duq_conv_1x1_with_bias(dl_matrix3dq_t *out,
//
// Conv 3x3
//
/**
* @brief Do 3x3 convolution basic operation with a quantized matrix
*
* @param out Preallocated quantized matrix
* @param in Input matrix, size (1, w, h, c)
* @param filter 3x3 filter, size (n, 3, 3, c)
* @param stride_x Stride of width
* @param stride_y Stride of height
*/
void dl_matrix3dqq_conv_3x3_op(dl_matrix3dq_t *out,
dl_matrix3dq_t *in,
dl_matrix3dq_t *f,
dl_matrix3dq_t *filter,
int stride_x,
int stride_y);
/**
* @brief Do 3x3 convolution with a quantized matrix
*
* @param in Input matrix, size (1, w, h, c)
* @param filter 3x3 filter, size (n, 3, 3, c)
* @param stride_x Stride of width
* @param stride_y Stride of height
* @param padding Padding type, 0: valid, 1: same
* @param exponent Exponent for resulting matrix
* @return Resulting quantized matrix
*/
dl_matrix3dq_t *dl_matrix3dqq_conv_3x3(dl_matrix3dq_t *in,
dl_matrix3dq_t *filter,
int stride_x,
@ -191,6 +362,18 @@ dl_matrix3dq_t *dl_matrix3dqq_conv_3x3(dl_matrix3dq_t *in,
dl_padding_type padding,
int exponent);
/**
* @brief Do 3x3 convolution with a quantized matrix, with bias adding
*
* @param in Input matrix, size (1, w, h, c)
* @param filter 3x3 filter, size (n, 3, 3, c)
* @param bias Bias, size (1, 1, 1, n)
* @param stride_x Stride of width
* @param stride_y Stride of height
* @param padding Padding type, 0: valid, 1: same
* @param exponent Exponent for resulting matrix
* @return Resulting quantized matrix
*/
dl_matrix3dq_t *dl_matrix3dqq_conv_3x3_with_bias(dl_matrix3dq_t *in,
dl_matrix3dq_t *f,
dl_matrix3dq_t *bias,
@ -224,7 +407,7 @@ dl_matrix3dq_t *dl_matrix3duq_conv_3x3_with_bias_prelu(dl_matrix3du_t *in,
//
/**
* @brief Do a general CNN layer pass, dimension is (number, width, height, channel)
* @brief Do a general convolution layer pass, size is (number, width, height, channel)
*
* @param in Input image
* @param filter Weights of the neurons
@ -245,6 +428,19 @@ dl_matrix3dq_t *dl_matrix3dqq_conv_common(dl_matrix3dq_t *in,
int exponent,
dl_conv_mode mode);
/**
* @brief Do a general convolution layer pass for an 8-bit fixed point matrix, size is (number, width, height, channel)
*
* @param in Input image
* @param filter Weights of the neurons
* @param bias Bias for the CNN layer.
* @param stride_x The step length of the convolution window in x(width) direction
* @param stride_y The step length of the convolution window in y(height) direction
* @param padding One of VALID or SAME
* @param mode Do convolution using C implement or xtensa implement, 0 or 1, with respect.
* If ESP_PLATFORM is not defined, this value is not used.
* @return The result of CNN layer.
*/
dl_matrix3dq_t *dl_matrix3duq_conv_common(dl_matrix3du_t *in,
dl_matrix3dq_t *filter,
dl_matrix3dq_t *bias,
@ -257,6 +453,17 @@ dl_matrix3dq_t *dl_matrix3duq_conv_common(dl_matrix3du_t *in,
//
// Depthwise 3x3
//
/**
* @brief Do 3x3 depthwise convolution with an 8-bit fixed point matrix
*
* @param in Input matrix, size (1, w, h, c)
* @param filter 3x3 filter, size (1, 3, 3, c)
* @param stride_x Stride of width
* @param stride_y Stride of height
* @param padding Padding type, 0: valid, 1: same
* @param exponent Exponent for resulting matrix
* @return Resulting quantized matrix
*/
dl_matrix3dq_t *dl_matrix3duq_depthwise_conv_3x3(dl_matrix3du_t *in,
dl_matrix3dq_t *filter,
int stride_x,
@ -264,6 +471,17 @@ dl_matrix3dq_t *dl_matrix3duq_depthwise_conv_3x3(dl_matrix3du_t *in,
dl_padding_type padding,
int exponent);
/**
* @brief Do 3x3 depthwise convolution with a quantized matrix
*
* @param in Input matrix, size (1, w, h, c)
* @param filter 3x3 filter, size (1, 3, 3, c)
* @param stride_x Stride of width
* @param stride_y Stride of height
* @param padding Padding type, 0: valid, 1: same
* @param exponent Exponent for resulting matrix
* @return Resulting quantized matrix
*/
dl_matrix3dq_t *dl_matrix3dqq_depthwise_conv_3x3(dl_matrix3dq_t *in,
dl_matrix3dq_t *filter,
int stride_x,
@ -287,14 +505,45 @@ dl_matrix3dq_t *dl_matrix3dqq_depthwise_conv_3x3_3(dl_matrix3dq_t *in,
int exponent);
#endif
/**
* @brief Do 3x3 depthwise convolution with a quantized matrix, with bias adding
*
* @param in Input matrix, size (1, w, h, c)
* @param filter 3x3 filter, size (1, 3, 3, c)
* @param bias Bias, size (1, 1, 1, c)
* @param stride_x Stride of width
* @param stride_y Stride of height
* @param padding Padding type, 0: valid, 1: same
* @param exponent Exponent for resulting matrix
* @param relu Whether to use relu activation
* @return Resulting quantized matrix
*/
dl_matrix3dq_t *dl_matrix3dqq_depthwise_conv_3x3_with_bias(dl_matrix3dq_t *in,
dl_matrix3dq_t *f,
dl_matrix3dq_t *bias,
int stride_x,
int stride_y,
dl_padding_type padding,
int exponent,
int relu);
dl_matrix3dq_t *f,
dl_matrix3dq_t *bias,
int stride_x,
int stride_y,
dl_padding_type padding,
int exponent,
int relu);
/**
* @brief Do 3x3 depthwise convolution with a quantized matrix, with bias adding and stride 1
*
* @param in Input matrix, size (1, w, h, c)
* @param filter 3x3 filter, size (1, 3, 3, c)
* @param bias Bias, size (1, 1, 1, n)
* @param padding Padding type, 0: valid, 1: same
* @param exponent Exponent for resulting matrix
* @param relu Whether to use relu activation
* @return Resulting quantized matrix
*/
dl_matrix3dq_t *dl_matrix3dqq_depthwise_conv_3x3s1_with_bias(dl_matrix3dq_t *in,
dl_matrix3dq_t *f,
dl_matrix3dq_t *bias,
dl_padding_type padding,
int exponent,
int relu);
dl_matrix3dq_t *dl_matrix3dqq_depthwise_conv_3x3_with_prelu(dl_matrix3dq_t *in,
dl_matrix3dq_t *filter,
@ -304,12 +553,6 @@ dl_matrix3dq_t *dl_matrix3dqq_depthwise_conv_3x3_with_prelu(dl_matrix3dq_t *in,
dl_padding_type padding,
int exponent);
dl_matrix3dq_t *dl_matrix3dqq_depthwise_conv_3x3s1_with_bias(dl_matrix3dq_t *in,
dl_matrix3dq_t *f,
dl_matrix3dq_t *bias,
dl_padding_type padding,
int exponent,
int relu);
//
// Depthwise Common
@ -344,12 +587,28 @@ void dl_matrix3dqq_dot_product(dl_matrix3dq_t *out,
//
// FC
//
/**
* @brief Do fully connected layer forward.
*
* @param out Preallocated resulting matrix, size (1, 1, 1, h)
* @param in Input matrix, size (1, 1, 1, w)
* @param filter Filter matrix, size (1, w, h, 1)
* @param mode Implementation mode
*/
void dl_matrix3dqq_fc(dl_matrix3dq_t *out,
dl_matrix3dq_t *in,
dl_matrix3dq_t *filter,
dl_conv_mode mode);
/**
* @brief Do fully connected layer forward, with bias adding
*
* @param out Preallocated resulting matrix, size (1, 1, 1, h)
* @param in Input matrix, size (1, 1, 1, w)
* @param filter Filter matrix, size (1, w, h, 1)
* @param bias Bias matrix, size (1, 1, 1, h)
* @param mode Implementation mode
*/
void dl_matrix3dqq_fc_with_bias(dl_matrix3dq_t *out,
dl_matrix3dq_t *in,
dl_matrix3dq_t *filter,
@ -360,7 +619,28 @@ void dl_matrix3dqq_fc_with_bias(dl_matrix3dq_t *out,
//
// Mobilefaceblock
//
/**
* @brief Do mobilefacenet process with splited pointwise 1x1 convolution, the process sequence is 1x1 pointwise->bn->relu->3x3 depthwise->bn->relu->1x1 pointwise->bn
*
* @param in Input matrix, size (1, w, h, c)
* @param pw_1 Pointwise 1x1 filter, size (n1/2, 1, 1, c)
* @param pw_2 Pointwise 1x1 filter, size (n1/2, 1, 1, c)
* @param pw_bias Pointwise bias, size (1, 1, 1, n1)
* @param dw Depthwise 3x3 filter, size (1, 3, 3, n1)
* @param dw_bias Depthwise bias, size (1, 1, 1, n1)
* @param pw_linear_1 Pointwise 1x1 filter, size (n2/2, 1, 1, n1)
* @param pw_linear_2 Pointwise 1x1 filter, size (n2/2, 1, 1, n1)
* @param pw_linear_bias Pointwise bias, size (1, 1, 1, n2)
* @param pw_exponent Exponent for pointwise resulting matrix
* @param dw_exponent Exponent for depthwise resulting matrix
* @param pw_linear_exponent Exponent for pointwise resulting matrix
* @param stride_x Stride of width
* @param stride_y Stride of height
* @param padding Padding type, 0: valid, 1: same
* @param mode Implementation mode
* @param shortcut Whether has a shortcut at pointwise linear
* @return Resulting quantized matrix
*/
dl_matrix3dq_t *dl_matrix3dqq_mobilefaceblock_split(dl_matrix3dq_t *in,
dl_matrix3dq_t *pw_1,
dl_matrix3dq_t *pw_2,
@ -379,6 +659,26 @@ dl_matrix3dq_t *dl_matrix3dqq_mobilefaceblock_split(dl_matrix3dq_t *in,
dl_conv_mode mode,
int shortcut);
/**
* @brief Do mobilefacenet process, the process sequence is 1x1 pointwise->bn->relu->3x3 depthwise->bn->relu->1x1 pointwise->bn
*
* @param in Input matrix, size (1, w, h, c)
* @param pw Pointwise 1x1 filter, size (n1, 1, 1, c)
* @param pw_bias Pointwise bias, size (1, 1, 1, n1)
* @param dw Depthwise 3x3 filter, size (1, 3, 3, n1)
* @param dw_bias Depthwise bias, size (1, 1, 1, n1)
* @param pw_linear Pointwise 1x1 filter, size (n2, 1, 1, n1)
* @param pw_linear_bias Pointwise bias, size (1, 1, 1, n2)
* @param pw_exponent Exponent for pointwise resulting matrix
* @param dw_exponent Exponent for depthwise resulting matrix
* @param pw_linear_exponent Exponent for pointwise resulting matrix
* @param stride_x Stride of width
* @param stride_y Stride of height
* @param padding Padding type, 0: valid, 1: same
* @param mode Implementation mode
* @param shortcut Whether has a shortcut at pointwise linear
* @return Resulting quantized matrix
*/
dl_matrix3dq_t *dl_matrix3dqq_mobilefaceblock(dl_matrix3dq_t *in,
dl_matrix3dq_t *pw,
dl_matrix3dq_t *pw_bias,
@ -399,6 +699,19 @@ dl_matrix3dq_t *dl_matrix3dqq_mobilefaceblock(dl_matrix3dq_t *in,
// Mobilenet
//
/**
* @brief Do mobilenet process, the process sequence is 1x1 dilated->prelu->3x3 depthwise->prelu->1x1 compress->bias
*
* @param in Input matrix, size (1, w, h, c)
* @param dilate Pointwise 1x1 filter, size (n1, 1, 1, c)
* @param dilate_prelu Pointwise prelu, size (1, 1, 1, n1)
* @param depthwise Depthwise 3x3 filter, size (1, 3, 3, n1)
* @param depthwise_prelu Depthwise prelu, size (1, 1, 1, n1)
* @param compress Pointwise 1x1 filter, size (n2, 1, 1, n1)
* @param bias Pointwise bias, size (1, 1, 1, n2)
* @param config Mobilenet configuration
* @return Resulting quantized matrix
*/
dl_matrix3dq_t *dl_matrix3dqq_mobilenet(dl_matrix3dq_t *in,
dl_matrix3dq_t *dilate,
dl_matrix3dq_t *dilate_prelu,
@ -409,6 +722,19 @@ dl_matrix3dq_t *dl_matrix3dqq_mobilenet(dl_matrix3dq_t *in,
dl_matrix3dq_mobilenet_config_t config,
char *name);
/**
* @brief Do mobilenet process, the process sequence is 1x1 dilated->prelu->3x3 depthwise->prelu->1x1 compress->bias
*
* @param in Input matrix, 8-bit fixed point, size (1, w, h, c)
* @param dilate Pointwise 1x1 filter, size (n1, 1, 1, c)
* @param dilate_prelu Pointwise prelu, size (1, 1, 1, n1)
* @param depthwise Depthwise 3x3 filter, size (1, 3, 3, n1)
* @param depthwise_prelu Depthwise prelu, size (1, 1, 1, n1)
* @param compress Pointwise 1x1 filter, size (n2, 1, 1, n1)
* @param bias Pointwise bias, size (1, 1, 1, n2)
* @param config Mobilenet configuration
* @return Resulting quantized matrix
*/
dl_matrix3dq_t *dl_matrix3duq_mobilenet(dl_matrix3du_t *in,
dl_matrix3dq_t *dilate,
dl_matrix3dq_t *dilate_prelu,
@ -444,5 +770,10 @@ dl_error_type dl_matrix3duq_padding(dl_matrix3du_t **padded_in,
//
// Pooling
//
/**
* @brief Calculate average value of a feature map
*
* @param in Input matrix, size (1, w, h, c)
* @return Resulting matrix, size (1, 1, 1, c)
*/
dl_matrix3dq_t *dl_matrix3dq_global_pool(dl_matrix3dq_t *in);

View File

@ -9,23 +9,47 @@ extern "C"
#include "dl_lib_matrix3dq.h"
/**
* @brief
*
* @param in
* @return dl_matrix3d_t*
* @brief Forward the face recognition process with frmn model. Calculate in float.
*
* @param in Image matrix, rgb888 format, size is 56x56, normalized
* @return dl_matrix3d_t* Face ID feature vector, size is 512
*/
dl_matrix3d_t *frmn(dl_matrix3d_t *in);
/**
* @brief
*
* @param in
* @return dl_matrix3dq_t*
* @brief Forward the face recognition process with frmn model. Calculate in quantization.
*
* @param in Image matrix, rgb888 format, size is 56x56, normalized
* @param mode 0: C implement; 1: handwrite xtensa instruction implement
* @return Face ID feature vector, size is 512
*/
dl_matrix3dq_t *frmn_q(dl_matrix3dq_t *in, dl_conv_mode mode);
/**
* @brief Forward the face recognition process with frmn2 model. Calculate in quantization.
*
* @param in Image matrix, rgb888 format, size is 56x56, normalized
* @param mode 0: C implement; 1: handwrite xtensa instruction implement
* @return Face ID feature vector, size is 512
*/
dl_matrix3dq_t *frmn2_q(dl_matrix3dq_t *in, dl_conv_mode mode);
/**
* @brief Forward the face recognition process with frmn2p model. Calculate in quantization.
*
* @param in Image matrix, rgb888 format, size is 56x56, normalized
* @param mode 0: C implement; 1: handwrite xtensa instruction implement
* @return Face ID feature vector, size is 512
*/
dl_matrix3dq_t *frmn2p_q(dl_matrix3dq_t *in, dl_conv_mode mode);
/**
* @brief Forward the face recognition process with frmn2c model. Calculate in quantization.
*
* @param in Image matrix, rgb888 format, size is 56x56, normalized
* @param mode 0: C implement; 1: handwrite xtensa instruction implement
* @return Face ID feature vector, size is 512
*/
dl_matrix3dq_t *frmn2c_q(dl_matrix3dq_t *in, dl_conv_mode mode);
#if __cplusplus

View File

@ -30,18 +30,33 @@ extern "C"
#include "dl_lib_matrix3d.h"
#include "dl_lib_matrix3dq.h"
/**
* Detection results with MTMN.
*
*/
typedef struct
{
dl_matrix3d_t *category;
dl_matrix3d_t *offset;
dl_matrix3d_t *landmark;
dl_matrix3d_t *category; /*!< Classification result after softmax, channel is 2 */
dl_matrix3d_t *offset; /*!< Bounding box offset of 2 points: top-left and bottom-right, channel is 4 */
dl_matrix3d_t *landmark; /*!< Offsets of 5 landmarks:
* - Left eye
* - Mouth leftside
* - Nose
* - Right eye
* - Mouth rightside
*
* channel is 10
* */
} mtmn_net_t;
/**
* @brief Free a mtmn_net_t
*
* @param p A mtmn_net_t pointer
*
*/
void mtmn_net_t_free(mtmn_net_t *p);
/**

View File

@ -33,7 +33,7 @@ uint32_t esp_dport_access_sequence_reg_read(uint32_t reg);
//only call in case of panic().
void esp_dport_access_int_abort(void);
#if defined(BOOTLOADER_BUILD) || defined(CONFIG_FREERTOS_UNICORE) || !defined(ESP_PLATFORM)
#if defined(BOOTLOADER_BUILD) || !defined(CONFIG_ESP32_DPORT_WORKAROUND) || !defined(ESP_PLATFORM)
#define DPORT_STALL_OTHER_CPU_START()
#define DPORT_STALL_OTHER_CPU_END()
#define DPORT_INTERRUPT_DISABLE()
@ -41,7 +41,7 @@ void esp_dport_access_int_abort(void);
#else
#define DPORT_STALL_OTHER_CPU_START() esp_dport_access_stall_other_cpu_start()
#define DPORT_STALL_OTHER_CPU_END() esp_dport_access_stall_other_cpu_end()
#define DPORT_INTERRUPT_DISABLE() unsigned int intLvl = XTOS_SET_INTLEVEL(XCHAL_EXCM_LEVEL)
#define DPORT_INTERRUPT_DISABLE() unsigned int intLvl = XTOS_SET_INTLEVEL(CONFIG_ESP32_DPORT_DIS_INTERRUPT_LVL)
#define DPORT_INTERRUPT_RESTORE() XTOS_RESTORE_JUST_INTLEVEL(intLvl)
#endif

View File

@ -28,10 +28,60 @@ extern "C"
{
#endif
#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32))
#define __WINDOWS__
#endif
#ifdef __WINDOWS__
/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options:
CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols
CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default)
CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol
For *nix builds that support visibility attribute, you can define similar behavior by
setting default visibility to hidden by adding
-fvisibility=hidden (for gcc)
or
-xldscope=hidden (for sun cc)
to CFLAGS
then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does
*/
#define CJSON_CDECL __cdecl
#define CJSON_STDCALL __stdcall
/* export symbols by default, this is necessary for copy pasting the C and header file */
#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS)
#define CJSON_EXPORT_SYMBOLS
#endif
#if defined(CJSON_HIDE_SYMBOLS)
#define CJSON_PUBLIC(type) type CJSON_STDCALL
#elif defined(CJSON_EXPORT_SYMBOLS)
#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL
#elif defined(CJSON_IMPORT_SYMBOLS)
#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL
#endif
#else /* !__WINDOWS__ */
#define CJSON_CDECL
#define CJSON_STDCALL
#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY)
#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type
#else
#define CJSON_PUBLIC(type) type
#endif
#endif
/* project version */
#define CJSON_VERSION_MAJOR 1
#define CJSON_VERSION_MINOR 7
#define CJSON_VERSION_PATCH 1
#define CJSON_VERSION_PATCH 12
#include <stddef.h>
@ -74,55 +124,13 @@ typedef struct cJSON
typedef struct cJSON_Hooks
{
void *(*malloc_fn)(size_t sz);
void (*free_fn)(void *ptr);
/* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */
void *(CJSON_CDECL *malloc_fn)(size_t sz);
void (CJSON_CDECL *free_fn)(void *ptr);
} cJSON_Hooks;
typedef int cJSON_bool;
#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32))
#define __WINDOWS__
#endif
#ifdef __WINDOWS__
/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 2 define options:
CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols
CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default)
CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol
For *nix builds that support visibility attribute, you can define similar behavior by
setting default visibility to hidden by adding
-fvisibility=hidden (for gcc)
or
-xldscope=hidden (for sun cc)
to CFLAGS
then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does
*/
/* export symbols by default, this is necessary for copy pasting the C and header file */
#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS)
#define CJSON_EXPORT_SYMBOLS
#endif
#if defined(CJSON_HIDE_SYMBOLS)
#define CJSON_PUBLIC(type) type __stdcall
#elif defined(CJSON_EXPORT_SYMBOLS)
#define CJSON_PUBLIC(type) __declspec(dllexport) type __stdcall
#elif defined(CJSON_IMPORT_SYMBOLS)
#define CJSON_PUBLIC(type) __declspec(dllimport) type __stdcall
#endif
#else /* !WIN32 */
#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY)
#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type
#else
#define CJSON_PUBLIC(type) type
#endif
#endif
/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them.
* This is to prevent stack overflows. */
#ifndef CJSON_NESTING_LIMIT
@ -156,7 +164,7 @@ CJSON_PUBLIC(void) cJSON_Delete(cJSON *c);
/* Returns the number of items in an array (or object). */
CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */
/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */
CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);
/* Get item "string" from object. Case insensitive. */
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);

View File

@ -20,6 +20,14 @@
THE SOFTWARE.
*/
#ifndef cJSON_Utils__h
#define cJSON_Utils__h
#ifdef __cplusplus
extern "C"
{
#endif
#include "cJSON.h"
/* Implement RFC6901 (https://tools.ietf.org/html/rfc6901) JSON Pointer spec. */
@ -72,3 +80,9 @@ CJSON_PUBLIC(char *) cJSONUtils_FindPointerFromObjectTo(const cJSON * const obje
/* Sorts the members of the object into alphabetical order. */
CJSON_PUBLIC(void) cJSONUtils_SortObject(cJSON * const object);
CJSON_PUBLIC(void) cJSONUtils_SortObjectCaseSensitive(cJSON * const object);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -48,7 +48,7 @@ extern "C" {
// After completing read operations, use DPORT_STALL_OTHER_CPU_END().
// This method uses stall other CPU while reading DPORT registers.
// Useful for compatibility, as well as for large consecutive readings.
// This method is slower, but must be used if ROM functions or
// This method is slower, but must be used if ROM functions or
// other code is called which accesses DPORT without any other workaround.
// *) The pre-readable APB register before reading the DPORT register
// helps synchronize the operation of the two CPUs,
@ -73,7 +73,7 @@ extern "C" {
*/
static inline uint32_t IRAM_ATTR DPORT_REG_READ(uint32_t reg)
{
#if defined(BOOTLOADER_BUILD) || defined(CONFIG_FREERTOS_UNICORE) || !defined(ESP_PLATFORM)
#if defined(BOOTLOADER_BUILD) || !defined(CONFIG_ESP32_DPORT_WORKAROUND) || !defined(ESP_PLATFORM)
return _DPORT_REG_READ(reg);
#else
return esp_dport_access_reg_read(reg);
@ -106,7 +106,7 @@ static inline uint32_t IRAM_ATTR DPORT_REG_READ(uint32_t reg)
*/
static inline uint32_t IRAM_ATTR DPORT_SEQUENCE_REG_READ(uint32_t reg)
{
#if defined(BOOTLOADER_BUILD) || defined(CONFIG_FREERTOS_UNICORE) || !defined(ESP_PLATFORM)
#if defined(BOOTLOADER_BUILD) || !defined(CONFIG_ESP32_DPORT_WORKAROUND) || !defined(ESP_PLATFORM)
return _DPORT_REG_READ(reg);
#else
return esp_dport_access_sequence_reg_read(reg);
@ -166,7 +166,7 @@ static inline uint32_t IRAM_ATTR DPORT_SEQUENCE_REG_READ(uint32_t reg)
*/
static inline uint32_t IRAM_ATTR DPORT_READ_PERI_REG(uint32_t reg)
{
#if defined(BOOTLOADER_BUILD) || defined(CONFIG_FREERTOS_UNICORE) || !defined(ESP_PLATFORM)
#if defined(BOOTLOADER_BUILD) || !defined(CONFIG_ESP32_DPORT_WORKAROUND) || !defined(ESP_PLATFORM)
return _DPORT_REG_READ(reg);
#else
return esp_dport_access_reg_read(reg);

View File

@ -147,7 +147,7 @@
#define IS_DPORT_REG(_r) (((_r) >= DR_REG_DPORT_BASE) && (_r) <= DR_REG_DPORT_END)
#if !defined( BOOTLOADER_BUILD ) && !defined( CONFIG_FREERTOS_UNICORE ) && defined( ESP_PLATFORM )
#if !defined( BOOTLOADER_BUILD ) && defined( CONFIG_ESP32_DPORT_WORKAROUND ) && defined( ESP_PLATFORM )
#define ASSERT_IF_DPORT_REG(_r, OP) TRY_STATIC_ASSERT(!IS_DPORT_REG(_r), (Cannot use OP for DPORT registers use DPORT_##OP));
#else
#define ASSERT_IF_DPORT_REG(_r, OP)

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -2,6 +2,7 @@
# Automatically generated file; DO NOT EDIT.
# Espressif IoT Development Framework Configuration
#
CONFIG_IDF_FIRMWARE_CHIP_ID=0x0000
#
# SDK tool configuration
@ -272,6 +273,12 @@ CONFIG_FRMN2C_QUANT=
#
# ESP32-specific
#
CONFIG_ESP32_REV_MIN_0=y
CONFIG_ESP32_REV_MIN_1=
CONFIG_ESP32_REV_MIN_2=
CONFIG_ESP32_REV_MIN_3=
CONFIG_ESP32_REV_MIN=0
CONFIG_ESP32_DPORT_WORKAROUND=y
CONFIG_ESP32_DEFAULT_CPU_FREQ_80=
CONFIG_ESP32_DEFAULT_CPU_FREQ_160=
CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y
@ -386,6 +393,7 @@ CONFIG_DISABLE_BASIC_ROM_CONSOLE=
CONFIG_ESP_TIMER_PROFILING=
CONFIG_COMPATIBLE_PRE_V2_1_BOOTLOADERS=
CONFIG_ESP_ERR_TO_NAME_LOOKUP=y
CONFIG_ESP32_DPORT_DIS_INTERRUPT_LVL=5
#
# Wi-Fi