doctor64 / tuyaZigbee

Replacement firmwares for TuYa zigbee devices
Apache License 2.0
106 stars 17 forks source link

OTA not operational. #23

Open doctor64 opened 2 months ago

doctor64 commented 2 months ago

Trying to update ZBWS01A switch failed - after successful OTA download using z2m, after device restarts, still have previsous version of firmware. Additional analysis shows what update works when updating from original Tuya firmware to both ver 1.2 and ver 1.3 firmware, but unable to update from 1.2 to 1.3. Possible reason - original tuya firmware store received OTA image at address 0x70000. Telink zigbee sdk versions 3.6.8.5 and 3.6.8.6 use address 0x77000.

doctor64 commented 2 months ago

Confirmed. comm_cfg.h fromm zigbee SDK

#if (BOOT_LOADER_MODE)
    #define APP_IMAGE_ADDR                  0x8000

part of drv_nv.h from zigbee SDK 3.8.6.5

#if(FLASH_CAP_SIZE_1M || FLASH_CAP_SIZE_2M || FLASH_CAP_SIZE_4M)
    #define NV_BASE_ADDRESS             (0xE6000)
#else
    #define NV_BASE_ADDRESS             (0x6A000)
    #define NV_BASE_ADDRESS2            (0x7A000)
#endif

#define FLASH_ADDR_OF_APP_FW            APP_IMAGE_ADDR

    //1M   Flash: max size = (0xE6000 - 0x8000) / 2 = 444k
    //512k Flash: max size = (0x6A000 - 0x8000) / 2 = 196k
    #define FLASH_OTA_IMAGE_MAX_SIZE    ((NV_BASE_ADDRESS - FLASH_ADDR_OF_APP_FW) / 2)
    //1M   Flash: ota addr = 0x8000 + 444k = 0x77000
    //512k Flash: ota addr = 0x8000 + 196k = 0x39000
    #define FLASH_ADDR_OF_OTA_IMAGE     (FLASH_ADDR_OF_APP_FW + FLASH_OTA_IMAGE_MAX_SIZE)

drv_nv.h from tuya zigbee SDK

#define FLASH_ADDR_OF_APP_FW            APP_IMAGE_ADDR

    //1M   Flash: max size = (0xE6000 - 0x8000) / 2 = 416k
    //512k Flash: max size = (0x6A000 - 0x8000) / 2 = 196k
    #define FLASH_OTA_IMAGE_MAX_SIZE    ((NV_BASE_ADDRESS - FLASH_ADDR_OF_APP_FW) / 2)
    //1M   Flash: ota addr = 0x8000 + 416k = 0x70000
    //512k Flash: ota addr = 0x8000 + 196k = 0x39000
    #define FLASH_ADDR_OF_OTA_IMAGE     (FLASH_ADDR_OF_APP_FW + FLASH_OTA_IMAGE_MAX_SIZE)
doctor64 commented 2 months ago

I see few ways to fix: 1: I can change OTA flash addr in SDK. But, this solution will need to patch SDK sources, lose compatibility with devices with correct boot loader, etc. 2: Make new bootloader. But this will broke possibility in the future to flash back original tuya firmware over OTA, complicate build process and user will need to have programmer to flash bootloader and new firmware for first time. 2.1: (improved variant of 2) I can check boot loader version on firmware start, embed bootloader binary into main firmware, check on start and if bootloader is incorrect - flash new bootloader. As above plus additionally complicate code, and need to find a way to embed binary into main firmware image. Telink OTA does not have a way to update bootloader.

Any ideas/suggestion?

pvvx commented 2 months ago

Tuya uses firmware with a bootloader. If the custom firmware is transferred and removes the "bootloader", then the OTA file must contain the "bootloader" + "application" to restore the original firmware. The original FW is obtained by the sum of two bin files ("loader" + "application") combined into one.

doctor64 commented 2 months ago

Hmm, no. I checked - original tuya firmware on at least one device, switch ZBWS01A accept new custom firmware, put it to address 0x70000 and tuya bootloader successfully transfer image to 0x8000 and loads. Problem is, as I described, what Tuya firmware and bootloader use 0x70000 as address of OTA buffer, but zigbee SDK uses 0x77000, so next OTA update over custom firmware received firmware, but tuya bootloader cannot find it. I checked tuya zigbee sdk for telink and found some script which concatenate binaries for bootloader and application. But i can't find a code where it can be used.

pvvx commented 2 months ago

My situation is more complicated - it requires launching with BLE OTA or Zigbee. These are more than 4 launch address options. As a result, the loaded code, if the markup is not suitable, is always moved to the address space required for work. The chip starts code from addresses 0, 0x20000, 0x40000 at the “KNLT” label.

  1. Tuya BOOT moves the code to 0x08000.
  2. Your program moves to 0x40000 upon startup, erasing the BOOT mark.

Next, the usual OTA works in Zigbee, loading the code at 0 or 0x40000. The option remains when the OTA carries the BLE code, since when loading at 0x40000, a typical OTA will not start. The BLE code checks that it started from 0x40000. Then it moves to 0 or 0x20000.

This works with any TLSR825x chips with 512 KB Flash. 1 Megabyte is not required.

TelinkMiFlasher.html from the BLE option, if the OTA file size is more than 128 kilobytes (or the file has a Zigbee header), uses EXT OTA - downloads the code to address 0x40000. All this allows you to use any OTA firmware and perform a safe update.

The OTA FW must have a start address verification code and a move function. That is, the firmware needs to be prepared - add verification and movement code.

The OTA buffer address for Zigbee with BOOT option does not matter.

doctor64 commented 2 months ago

I'm still not sure about switching to architecture without boot loader. Yes, it's easier, but bootloader option allows more space for firmware on 1M chip variants. No bootloader architecture limits firmware size to 0x40000 - 256K. Architecture with bootloader allows 0x77000-0x8000 = 0x6F000, 444K on 1M flash chips. PS: Мы можем перейти на русский если удобнее

pvvx commented 2 months ago

На сегодня максимальный размер прошивки для батарейного устройства, что удалось создать, не превышает 160292 байт. Это BLE+Zigbee+LCD. Zigbee координатор с функцией управления (HCI) по соединению BLE и ретрансляцией термометра Zigbee в рекламу BLE укладывается в 212 килобайт. Больше всего сказываются ограничения в размере RAM и скорости работы данного CPU. Остатки объема Flash используются для записи истории измерений. Циклический буфер истории измерений обычно требует большой части линейного объема Flash. По этой причине желательно сжатая компоновка программного обеспечения включающая буфер OTA и настройки. Для 1МБ Flash (модуль ZTU) объем памяти замеров выходит в 51943 блоков (в блоке: температура, влажность, напряжение батареи, Unix Timestamp).

Загрузчик (boot) в TLSR825x не добавляет функциональности. XIP умеет работать с разных адресов - позиционировать Flash в нужные адреса для данных и исполняемого кода. Обычно boot применяют на чипах не умеющих работать с разных адресов Flash. Тогда для каждого OTA требуется перемещение прошивки. Для TLSR825x boot добавляет потребления энергии от батарейки и более ничего.

TLSR825x стартует с сегмента Flash кратного 0x20000, путем последовательного поиска заголовка с меткой “KNLT”. Код OTA записывается в адрес Flash кратный 0x20000, с пустой меткой. Проверяется контрольная сумма и тогда дописывается метка “KNLT”, а предыдущая стартовая метка обнуляется. В варианте BLE, при последующем старте новый буфер OTA очищается. В Zigbee очистка буфера OTA может быть произведена на ходу. Этим обеспечивается полностью безопасное обновление OTA. Данную функцию XIP и аппаратного старта без перемещения кода в Flash Telink специально реализовал в серии TLSR825x для ухода от BOOT.

pvvx commented 2 months ago

No bootloader architecture limits firmware size to 0x40000 - 256K. Architecture with bootloader allows 0x77000-0x8000 = 0x6F000, 444K on 1M flash chips.

Иногда Tuya в модули ZTU ставят чипы с 512КБ Flash. По этому рассчитывать на 444K для FW не приходится. Один из примеров.

uniquePWD commented 1 month ago

Any news on this?

doctor64 commented 1 month ago

Any news on this?

I implemented bootloader correctly working with OTA images. It is working, but still require a programmer to update bootloader. I'm need to find a way to update bootloader from OTA, because Telink Zugbee SDK does not have such functionality.