From f68de5128c6c6c12d2e90bd40de59cf37ac49098 Mon Sep 17 00:00:00 2001 From: songyanguang <345810377@qq.com> Date: Tue, 6 May 2025 18:32:46 +0800 Subject: [PATCH 01/15] ch32v208 add ota, need to debug --- .../arch/risc-v/ch32v208rbt6/Makefile | 5 +- .../XiZi_IIoT/arch/risc-v/ch32v208rbt6/boot.S | 4 + .../XiZi_IIoT/board/ch32v208rbt6/.defconfig | 349 ++++++++++++++++++ .../XiZi_IIoT/board/ch32v208rbt6/config.mk | 10 + .../board/ch32v208rbt6/link_application.ld | 225 +++++++++++ .../board/ch32v208rbt6/link_bootloader.ld | 224 +++++++++++ .../ch32v208rbt6/third_party_driver/Makefile | 4 + .../third_party_driver/ModuleConfig.c | 2 + .../third_party_driver/common/Makefile | 5 + .../third_party_driver/common/common.c | 65 ++++ .../third_party_driver/common/ymodem.c | 54 +++ .../third_party_driver/include/boot_for_ota.h | 34 ++ .../third_party_driver/include/common.h | 36 ++ .../include/flash_for_ota.h | 40 ++ .../third_party_driver/include/ymodem.h | 56 +++ .../third_party_driver/ota/Makefile | 3 + .../third_party_driver/ota/boot_for_ota.c | 133 +++++++ .../third_party_driver/ota/flash_for_ota.c | 258 +++++++++++++ Ubiquitous/XiZi_IIoT/script.sh | 6 + 19 files changed, 1512 insertions(+), 1 deletion(-) create mode 100644 Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig create mode 100644 Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/link_application.ld create mode 100644 Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/link_bootloader.ld create mode 100755 Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/common/Makefile create mode 100644 Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/common/common.c create mode 100644 Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/common/ymodem.c create mode 100644 Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/include/boot_for_ota.h create mode 100644 Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/include/common.h create mode 100644 Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/include/flash_for_ota.h create mode 100644 Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/include/ymodem.h create mode 100644 Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/Makefile create mode 100644 Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/boot_for_ota.c create mode 100644 Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/flash_for_ota.c create mode 100755 Ubiquitous/XiZi_IIoT/script.sh diff --git a/Ubiquitous/XiZi_IIoT/arch/risc-v/ch32v208rbt6/Makefile b/Ubiquitous/XiZi_IIoT/arch/risc-v/ch32v208rbt6/Makefile index ca8a90e5a..e63075d80 100644 --- a/Ubiquitous/XiZi_IIoT/arch/risc-v/ch32v208rbt6/Makefile +++ b/Ubiquitous/XiZi_IIoT/arch/risc-v/ch32v208rbt6/Makefile @@ -1,4 +1,7 @@ -SRC_FILES := boot.S interrupt.c tick.c switch.S prepare_rhwstack.c interrupt_switch.S ble_task_scheduler.S +SRC_FILES := boot.S interrupt.c tick.c switch.S prepare_rhwstack.c interrupt_switch.S +ifeq ($(CONFIG_BSP_USING_BLE),y) +SRC_FILES += ble_task_scheduler.S +endif SRC_DIR := Core User Debug # interrupt_switch.S include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiZi_IIoT/arch/risc-v/ch32v208rbt6/boot.S b/Ubiquitous/XiZi_IIoT/arch/risc-v/ch32v208rbt6/boot.S index 4fea969ad..871086a72 100644 --- a/Ubiquitous/XiZi_IIoT/arch/risc-v/ch32v208rbt6/boot.S +++ b/Ubiquitous/XiZi_IIoT/arch/risc-v/ch32v208rbt6/boot.S @@ -268,7 +268,11 @@ handle_reset: csrw mtvec, t0 jal SystemInit +#ifdef __BOOTLOADER /* BOOT */ + la t0, ota_entry +#else /* APP */ la t0, entry +#endif /* BOOT */ csrw mepc, t0 mret diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig new file mode 100644 index 000000000..2652dea46 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig @@ -0,0 +1,349 @@ +# +# Automatically generated file; DO NOT EDIT. +# XiZi_IIoT Project Configuration +# +CONFIG_BOARD_CH32V208RBT6=y +CONFIG_ARCH_RISCV=y + +# +# ch32v208rbt6 feature +# +CONFIG_BSP_USING_UART=y +CONFIG_BSP_USING_UART1=y +CONFIG_SERIAL_BUS_NAME_1="uart1" +CONFIG_SERIAL_DRV_NAME_1="uart1_drv" +CONFIG_SERIAL_1_DEVICE_NAME_0="uart1_dev1" +# CONFIG_BSP_USING_ETH is not set +# CONFIG_BSP_USING_ADC is not set +# CONFIG_BSP_USING_BLE is not set +# CONFIG_BSP_USING_CAN is not set +# CONFIG_BSP_USING_RS485 is not set +CONFIG_BSP_USING_LTE=y +CONFIG_LTE_BUS_NAME="lte" +CONFIG_LTE_DRV_NAME="lte_drv" +CONFIG_LTE_DEVICE_NAME_1="lte_dev1" + +# +# Hardware feature +# +CONFIG_RESOURCES_SERIAL=y +CONFIG_SERIAL_USING_DMA=y +CONFIG_SERIAL_RB_BUFSZ=128 + +# +# Kernel feature +# + +# +# separate compile(choose none for compile once) +# +# CONFIG_SEPARATE_COMPILE is not set +# CONFIG_COMPILER_APP is not set +# CONFIG_APP_STARTUP_FROM_SDCARD is not set +CONFIG_APP_STARTUP_FROM_FLASH=y +# CONFIG_COMPILER_KERNEL is not set + +# +# Memory Management +# +# CONFIG_KERNEL_MEMBLOCK is not set +CONFIG_MEM_ALIGN_SIZE=8 +# CONFIG_MEM_EXTERN_SRAM is not set +CONFIG_MM_PAGE_SIZE=4096 + +# +# Using small memory allocator +# +CONFIG_KERNEL_SMALL_MEM_ALLOC=y +CONFIG_SMALL_NUMBER_32B=64 +CONFIG_SMALL_NUMBER_64B=32 + +# +# Task feature +# +CONFIG_USER_APPLICATION=y +# CONFIG_TASK_ISOLATION is not set +# CONFIG_KERNEL_CAPABILITY is not set + +# +# Inter-Task communication +# +CONFIG_KERNEL_SEMAPHORE=y +CONFIG_KERNEL_MUTEX=y +CONFIG_KERNEL_EVENT=y +CONFIG_KERNEL_MESSAGEQUEUE=y +CONFIG_KERNEL_SOFTTIMER=y +CONFIG_SCHED_POLICY_RR_REMAINSLICE=y +# CONFIG_SCHED_POLICY_RR is not set +# CONFIG_SCHED_POLICY_FIFO is not set +# CONFIG_KTASK_PRIORITY_8 is not set +CONFIG_KTASK_PRIORITY_32=y +# CONFIG_KTASK_PRIORITY_256 is not set +CONFIG_KTASK_PRIORITY_MAX=32 +CONFIG_TICK_PER_SECOND=100 +CONFIG_KERNEL_STACK_OVERFLOW_CHECK=y +CONFIG_IDLE_KTASK_STACKSIZE=512 +CONFIG_ZOMBIE_KTASK_STACKSIZE=512 + +# +# Kernel Console +# +CONFIG_KERNEL_CONSOLE=y +CONFIG_KERNEL_BANNER=y +CONFIG_KERNEL_CONSOLEBUF_SIZE=128 + +# +# Kernel Hook +# +# CONFIG_KERNEL_HOOK is not set + +# +# Command shell +# +CONFIG_TOOL_SHELL=y +CONFIG_SHELL_ENTER_CR=y +CONFIG_SHELL_ENTER_LF=y +CONFIG_SHELL_ENTER_CR_AND_LF=y +# CONFIG_SHELL_ENTER_CRLF is not set + +# +# Set shell user control +# +CONFIG_SHELL_DEFAULT_USER="letter" +CONFIG_SHELL_DEFAULT_USER_PASSWORD="" +CONFIG_SHELL_LOCK_TIMEOUT=10000 + +# +# Set shell config param +# +CONFIG_SHELL_TASK_STACK_SIZE=1024 +CONFIG_SHELL_TASK_PRIORITY=20 +CONFIG_SHELL_MAX_NUMBER=5 +CONFIG_SHELL_PARAMETER_MAX_NUMBER=8 +CONFIG_SHELL_HISTORY_MAX_NUMBER=5 +CONFIG_SHELL_PRINT_BUFFER=128 +CONFIG_SHELL_HELP_SHOW_PERMISSION=y +# CONFIG_SHELL_HELP_LIST_USER is not set +CONFIG_SHELL_HELP_LIST_VAR=y +# CONFIG_SHELL_HELP_LIST_KEY is not set + +# +# Kernel data structure Manage +# +CONFIG_KERNEL_QUEUEMANAGE=y +CONFIG_KERNEL_WORKQUEUE=y +CONFIG_WORKQUEUE_KTASK_STACKSIZE=2048 +CONFIG_WORKQUEUE_KTASK_PRIORITY=23 +CONFIG_QUEUE_MAX=16 +CONFIG_KERNEL_WAITQUEUE=y +CONFIG_KERNEL_DATAQUEUE=y +# CONFIG_KERNEL_CIRCULAR_AREA is not set +# CONFIG_KERNEL_AVL_TREE is not set + +# +# Kernel components init +# +CONFIG_KERNEL_COMPONENTS_INIT=y +CONFIG_ENV_INIT_KTASK_STACK_SIZE=2048 +CONFIG_KERNEL_USER_MAIN=y +CONFIG_NAME_NUM_MAX=32 +# CONFIG_KERNEL_DEBUG is not set +# CONFIG_ARCH_SMP is not set + +# +# hash table config +# +CONFIG_ID_HTABLE_SIZE=16 +CONFIG_ID_NUM_MAX=128 +# CONFIG_KERNEL_TEST is not set + +# +# Kernel Lib +# +CONFIG_LIB=y +CONFIG_LIB_POSIX=y +CONFIG_LIB_NEWLIB=y +# CONFIG_LIB_MUSLLIB is not set +# CONFIG_LIB_OTHER is not set + +# +# C++ features +# +# CONFIG_LIB_CPLUSPLUS is not set + +# +# File system +# +CONFIG_FS_VFS=y +# CONFIG_VFS_USING_WORKDIR is not set +CONFIG_FS_VFS_DEVFS=y +# CONFIG_FS_VFS_FATFS is not set +# CONFIG_FS_CH376 is not set +# CONFIG_FS_LWEXT4 is not set + +# +# Tool feature +# + +# +# OTA function +# +CONFIG_TOOL_USING_OTA=y +# CONFIG_MCUBOOT_BOOTLOADER is not set +CONFIG_MCUBOOT_APPLICATION=y +CONFIG_OTA_BY_PLATFORM=y +# CONFIG_OTA_BY_TCPSERVER is not set + +# +# Flash area address and size configuration. +# +CONFIG_CHIP_FLAH_BASE=0x08000000 +CONFIG_XIUOS_FLAH_ADDRESS=0x60100000 +CONFIG_BAKUP_FLAH_ADDRESS=0x60300000 +CONFIG_DOWN_FLAH_ADDRESS=0x08038000 +CONFIG_FLAG_FLAH_ADDRESS=0x08077000 +CONFIG_APP_FLASH_SIZE=0x00100000 +CONFIG_OTA_RX_TIMEOUT=600 +CONFIG_OTA_FRAME_SIZE=2048 + +# +# APP_Framework +# + +# +# Framework +# +CONFIG_TRANSFORM_LAYER_ATTRIUBUTE=y +CONFIG_ADD_XIZI_FEATURES=y +# CONFIG_ADD_NUTTX_FEATURES is not set +# CONFIG_ADD_RTTHREAD_FEATURES is not set +# CONFIG_SUPPORT_SENSOR_FRAMEWORK is not set +CONFIG_SUPPORT_CONNECTION_FRAMEWORK=y +# CONFIG_CONNECTION_FRAMEWORK_DEBUG is not set +# CONFIG_CONNECTION_INDUSTRIAL_NETWORK is not set +# CONFIG_CONNECTION_INDUSTRIAL_FIELDBUS is not set +# CONFIG_CONNECTION_INDUSTRIAL_WLAN is not set +# CONFIG_CONNECTION_ADAPTER_LORA is not set +CONFIG_CONNECTION_ADAPTER_4G=y +CONFIG_ADAPTER_EC801E=y +CONFIG_ADAPTER_4G_EC801E="ec801e" +# CONFIG_ADAPTER_EC801E_DRIVER_EXTUART is not set +CONFIG_ADAPTER_EC801E_DRIVER="/dev/lte_dev1" +# CONFIG_ADAPTER_EC200T is not set +# CONFIG_ADAPTER_EC200A is not set +# CONFIG_ADAPTER_GM800TF is not set +# CONFIG_CONNECTION_ADAPTER_NB is not set +# CONFIG_CONNECTION_ADAPTER_WIFI is not set +# CONFIG_CONNECTION_ADAPTER_ETHERNET is not set +# CONFIG_CONNECTION_ADAPTER_BLUETOOTH is not set +# CONFIG_CONNECTION_ADAPTER_ZIGBEE is not set +# CONFIG_CONNECTION_ADAPTER_5G is not set +# CONFIG_SUPPORT_KNOWING_FRAMEWORK is not set +# CONFIG_SUPPORT_CONTROL_FRAMEWORK is not set + +# +# Security +# +# CONFIG_CRYPTO is not set +# CONFIG_MBEDTLS is not set + +# +# Applications +# + +# +# config stack size and priority of main task +# +CONFIG_MAIN_KTASK_STACK_SIZE=1024 +CONFIG_MAIN_KTASK_PRIORITY=16 + +# +# test app +# +# CONFIG_USER_TEST is not set + +# +# connection app +# +# CONFIG_APPLICATION_CONNECTION is not set + +# +# control app +# + +# +# knowing app +# +# CONFIG_APPLICATION_KNOWING is not set + +# +# sensor app +# +# CONFIG_APPLICATION_SENSOR is not set +# CONFIG_USING_EMBEDDED_DATABASE_APP is not set +# CONFIG_APP_USING_WEBNET is not set +# CONFIG_APPLICATION_WEBSERVER is not set + +# +# app lib +# +CONFIG_APP_SELECT_NEWLIB=y +# CONFIG_APP_SELECT_OTHER_LIB is not set + +# +# lib using cJSON +# +# CONFIG_LIB_USING_CJSON is not set + +# +# lib using queue +# +# CONFIG_LIB_USING_QUEUE is not set + +# +# lib using LVGL +# +# CONFIG_LIB_LV is not set + +# +# lvgl image display parameter settings +# +CONFIG_LVGL_WIDTH=320 +CONFIG_LVGL_HEIGHT=320 + +# +# lib using embedded_database +# +# CONFIG_USING_EMBEDDED_DATABASE is not set + +# +# lib using LoRaWan +# +# CONFIG_LIB_USING_LORAWAN is not set + +# +# lib using MQTT +# +CONFIG_LIB_USING_MQTT=y +CONFIG_XIUOS_PLATFORM=y +# CONFIG_ALIBABA_PLATFORM is not set + +# +# xiuos platform mqtt connection parameter configuration. +# +CONFIG_CLIENTID="D001" +CONFIG_USERNAME="xiuosiot" +CONFIG_PASSWORD="xiuosiot" +CONFIG_PLATFORM_SERVERIP="115.238.53.59" +CONFIG_PLATFORM_SERVERPORT="1883" +# CONFIG_USING_DOWNLOAD_JSON is not set + +# +# lib using JerryScript +# +# CONFIG_LIB_USING_JERRYSCRIPT is not set + +# +# lib using SQLite +# +# CONFIG_LIB_USING_SQLITE is not set diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/config.mk b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/config.mk index 7cd2dab34..bc895ea8f 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/config.mk +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/config.mk @@ -4,7 +4,14 @@ export MARCH := rv32imac_zicsr export CFLAGS := -march=$(MARCH) -mabi=ilp32 -msmall-data-limit=8 -msave-restore -Os -g export AFLAGS := -march=$(MARCH) -mabi=ilp32 -x assembler-with-cpp -ggdb + +ifeq ($(CONFIG_MCUBOOT_BOOTLOADER),y) +export LFLAGS := -march=$(MARCH) -mabi=ilp32 -nostartfiles -Wl,--gc-sections,-Map=XiZi-ch32v208vct6.map,-cref,-u,_start -T $(BSP_ROOT)/link_bootloader.ld +else ifeq ($(CONFIG_MCUBOOT_APPLICATION),y) +export LFLAGS := -march=$(MARCH) -mabi=ilp32 -nostartfiles -Wl,--gc-sections,-Map=XiZi-ch32v208vct6.map,-cref,-u,_start -T $(BSP_ROOT)/link_application.ld +else export LFLAGS := -march=$(MARCH) -mabi=ilp32 -nostartfiles -Wl,--gc-sections,-Map=XiZi-ch32v208vct6.map,-cref,-u,_start -T $(BSP_ROOT)/link.ld +endif # export CFLAGS := -march=$(MARCH) -mabi=ilp32 -msmall-data-limit=8 -msave-restore -Os -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -fno-common -g -std=gnu99 # export AFLAGS := -march=$(MARCH) -mabi=ilp32 -x assembler-with-cpp -ggdb @@ -17,6 +24,9 @@ export CXXFLAGS := -fmessage-length=0 -fsigned-char -ffunction-sections -fdata- export CROSS_COMPILE ?=/opt/riscv64-toolchain/bin/riscv64-unknown-elf- export DEFINES := -DHAVE_CCONFIG_H -DHAVE_SIGINFO +ifeq ($(CONFIG_MCUBOOT_BOOTLOADER),y) +export DEFINES += -D__BOOTLOADER +endif export LINK_WCH_NET := $(KERNEL_ROOT)/board/ch32v208rbt6/third_party_driver/ethernet/libwchnet.a export LINK_WCH_BLE := $(KERNEL_ROOT)/board/ch32v208rbt6/third_party_driver/ble/lib/libwchble.a diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/link_application.ld b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/link_application.ld new file mode 100644 index 000000000..9371cfc8e --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/link_application.ld @@ -0,0 +1,225 @@ +ENTRY( _start ) + +__stack_size = 2048; + +PROVIDE( _stack_size = __stack_size ); + + +MEMORY +{ +/* CH32V20x_D6 - CH32V203F6-CH32V203G6-CH32V203K6-CH32V203C6 */ +/* + FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 32K + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 10K +*/ + +/* CH32V20x_D6 - CH32V203K8-CH32V203C8-CH32V203G8-CH32V203F8 */ +/* + FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 64K + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K +*/ + +/* CH32V20x_D8 - CH32V203RB + CH32V20x_D8W - CH32V208x + FLASH + RAM supports the following configuration + FLASH-128K + RAM-64K + FLASH-144K + RAM-48K + FLASH-160K + RAM-32K +*/ + /*FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 448K*/ + FLASH (rx) : ORIGIN = 0x00038000, LENGTH = 248K + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 48K +} + + +SECTIONS +{ + + .init : + { + _sinit = .; + . = ALIGN(4); + KEEP(*(SORT_NONE(.init))) + . = ALIGN(4); + _einit = .; + } >FLASH AT>FLASH + + .vector : + { + *(.vector); + . = ALIGN(64); + } >FLASH AT>FLASH + + .highcode : + { + . = ALIGN(4); + *(.highcode); + *(.highcode.*); + . = ALIGN(4); + } >FLASH AT>FLASH + + .text : + { + . = ALIGN(4); + EXCLUDE_FILE (*wchble.a) *(.text .text*) + *(.text) + *(.text.*) + *(.rodata) + *(.rodata*) + *(.sdata2.*) + *(.glue_7) + *(.glue_7t) + *(.gnu.linkonce.t.*) + . = ALIGN(4); + + /* section information for shell */ + . = ALIGN(4); + _shell_command_start = .; + KEEP (*(shellCommand)) + _shell_command_end = .; + . = ALIGN(4); + + PROVIDE(__ctors_start__ = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE(__ctors_end__ = .); + + . = ALIGN(4); + __isrtbl_idx_start = .; + KEEP(*(.isrtbl.idx)) + __isrtbl_start = .; + KEEP(*(.isrtbl)) + __isrtbl_end = .; + . = ALIGN(4); + + PROVIDE(g_service_table_start = ABSOLUTE(.)); + KEEP(*(.g_service_table)) + PROVIDE(g_service_table_end = ABSOLUTE(.)); + + *(.gnu.linkonce.t.*) + } >FLASH AT>FLASH + + .fini : + { + KEEP(*(SORT_NONE(.fini))) + . = ALIGN(4); + } >FLASH AT>FLASH + + PROVIDE( _etext = . ); + PROVIDE( _eitcm = . ); + + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } >FLASH AT>FLASH + + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) + PROVIDE_HIDDEN (__init_array_end = .); + } >FLASH AT>FLASH + + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) + KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) + PROVIDE_HIDDEN (__fini_array_end = .); + } >FLASH AT>FLASH + + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } >FLASH AT>FLASH + + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } >FLASH AT>FLASH + + .dalign : + { + . = ALIGN(4); + PROVIDE(_data_vma = .); + } >RAM AT>FLASH + + .dlalign : + { + . = ALIGN(4); + PROVIDE(_data_lma = .); + } >FLASH AT>FLASH + + .data : + { + *(.gnu.linkonce.r.*) + *(.data .data.*) + *(.gnu.linkonce.d.*) + . = ALIGN(8); + PROVIDE( __global_pointer$ = . + 0x800 ); + *(.sdata .sdata.*) + *(.sdata2.*) + *(.gnu.linkonce.s.*) + . = ALIGN(8); + *(.srodata.cst16) + *(.srodata.cst8) + *(.srodata.cst4) + *(.srodata.cst2) + *(.srodata .srodata.*) + . = ALIGN(4); + PROVIDE( _edata = .); + } >RAM AT>FLASH + + .bss : + { + . = ALIGN(4); + PROVIDE( _sbss = .); + *(.sbss*) + *(.gnu.linkonce.sb.*) + *(.bss*) + *(.gnu.linkonce.b.*) + *(COMMON*) + . = ALIGN(4); + PROVIDE( _ebss = .); + } >RAM AT>FLASH + + PROVIDE( _end = _ebss); + PROVIDE( end = . ); + + .stack ORIGIN(RAM) + LENGTH(RAM) - __stack_size : + { + PROVIDE( _heap_end = . ); + . = ALIGN(4); + PROVIDE(_susrstack = . ); + . = . + __stack_size; + PROVIDE( _eusrstack = .); + } >RAM + +} + + + diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/link_bootloader.ld b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/link_bootloader.ld new file mode 100644 index 000000000..2ae093e9a --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/link_bootloader.ld @@ -0,0 +1,224 @@ +ENTRY( _start ) + +__stack_size = 2048; + +PROVIDE( _stack_size = __stack_size ); + + +MEMORY +{ +/* CH32V20x_D6 - CH32V203F6-CH32V203G6-CH32V203K6-CH32V203C6 */ +/* + FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 32K + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 10K +*/ + +/* CH32V20x_D6 - CH32V203K8-CH32V203C8-CH32V203G8-CH32V203F8 */ +/* + FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 64K + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K +*/ + +/* CH32V20x_D8 - CH32V203RB + CH32V20x_D8W - CH32V208x + FLASH + RAM supports the following configuration + FLASH-128K + RAM-64K + FLASH-144K + RAM-48K + FLASH-160K + RAM-32K +*/ + FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 224K + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K +} + + +SECTIONS +{ + + .init : + { + _sinit = .; + . = ALIGN(4); + KEEP(*(SORT_NONE(.init))) + . = ALIGN(4); + _einit = .; + } >FLASH AT>FLASH + + .vector : + { + *(.vector); + . = ALIGN(64); + } >FLASH AT>FLASH + + .highcode : + { + . = ALIGN(4); + *(.highcode); + *(.highcode.*); + . = ALIGN(4); + } >FLASH AT>FLASH + + .text : + { + . = ALIGN(4); + EXCLUDE_FILE (*wchble.a) *(.text .text*) + *(.text) + *(.text.*) + *(.rodata) + *(.rodata*) + *(.sdata2.*) + *(.glue_7) + *(.glue_7t) + *(.gnu.linkonce.t.*) + . = ALIGN(4); + + /* section information for shell */ + . = ALIGN(4); + _shell_command_start = .; + KEEP (*(shellCommand)) + _shell_command_end = .; + . = ALIGN(4); + + PROVIDE(__ctors_start__ = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE(__ctors_end__ = .); + + . = ALIGN(4); + __isrtbl_idx_start = .; + KEEP(*(.isrtbl.idx)) + __isrtbl_start = .; + KEEP(*(.isrtbl)) + __isrtbl_end = .; + . = ALIGN(4); + + PROVIDE(g_service_table_start = ABSOLUTE(.)); + KEEP(*(.g_service_table)) + PROVIDE(g_service_table_end = ABSOLUTE(.)); + + *(.gnu.linkonce.t.*) + } >FLASH AT>FLASH + + .fini : + { + KEEP(*(SORT_NONE(.fini))) + . = ALIGN(4); + } >FLASH AT>FLASH + + PROVIDE( _etext = . ); + PROVIDE( _eitcm = . ); + + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } >FLASH AT>FLASH + + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) + PROVIDE_HIDDEN (__init_array_end = .); + } >FLASH AT>FLASH + + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) + KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) + PROVIDE_HIDDEN (__fini_array_end = .); + } >FLASH AT>FLASH + + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } >FLASH AT>FLASH + + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } >FLASH AT>FLASH + + .dalign : + { + . = ALIGN(4); + PROVIDE(_data_vma = .); + } >RAM AT>FLASH + + .dlalign : + { + . = ALIGN(4); + PROVIDE(_data_lma = .); + } >FLASH AT>FLASH + + .data : + { + *(.gnu.linkonce.r.*) + *(.data .data.*) + *(.gnu.linkonce.d.*) + . = ALIGN(8); + PROVIDE( __global_pointer$ = . + 0x800 ); + *(.sdata .sdata.*) + *(.sdata2.*) + *(.gnu.linkonce.s.*) + . = ALIGN(8); + *(.srodata.cst16) + *(.srodata.cst8) + *(.srodata.cst4) + *(.srodata.cst2) + *(.srodata .srodata.*) + . = ALIGN(4); + PROVIDE( _edata = .); + } >RAM AT>FLASH + + .bss : + { + . = ALIGN(4); + PROVIDE( _sbss = .); + *(.sbss*) + *(.gnu.linkonce.sb.*) + *(.bss*) + *(.gnu.linkonce.b.*) + *(COMMON*) + . = ALIGN(4); + PROVIDE( _ebss = .); + } >RAM AT>FLASH + + PROVIDE( _end = _ebss); + PROVIDE( end = . ); + + .stack ORIGIN(RAM) + LENGTH(RAM) - __stack_size : + { + PROVIDE( _heap_end = . ); + . = ALIGN(4); + PROVIDE(_susrstack = . ); + . = . + __stack_size; + PROVIDE( _eusrstack = .); + } >RAM + +} + + + diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/Makefile b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/Makefile index e963f22e5..9a0b3b26e 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/Makefile +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/Makefile @@ -22,4 +22,8 @@ endif ifeq ($(CONFIG_BSP_USING_LTE),y) SRC_DIR += lte endif +ifeq ($(CONFIG_TOOL_USING_OTA),y) + SRC_DIR += ota + SRC_DIR += common +endif include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ModuleConfig.c b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ModuleConfig.c index d47601343..9645dfc55 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ModuleConfig.c +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ModuleConfig.c @@ -102,6 +102,7 @@ void CFG_READ(u32 StartAddr, u8 *Buffer, u32 Length) { } } +#ifdef BSP_USING_BLE /** * @brief 尝试使用配置通过4G连接到服务器,并且蓝牙响应连接状态报文。 * @param requestId 蓝牙请求报文ID @@ -531,6 +532,7 @@ void startParseBleRequestTask(uint8_t *request) { PrivTaskCreate(&parseBleRequestThread, &parseBleRequestTaskAttr, parseBleRequest, &parseBleRequestTaskArgs); PrivTaskStartup(&parseBleRequestThread); } +#endif /* BSP_USING_BLE */ /** * @brief 命令行显示配置信息 diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/common/Makefile b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/common/Makefile new file mode 100755 index 000000000..5fe2493d6 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/common/Makefile @@ -0,0 +1,5 @@ +ifeq ($(CONFIG_TOOL_USING_OTA),y) + SRC_FILES += common.c ymodem.c +endif + +include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/common/common.c b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/common/common.c new file mode 100644 index 000000000..93b9e905c --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/common/common.c @@ -0,0 +1,65 @@ + +/* +* Copyright (c) 2020 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +/** +* @file: common.c +* @brief: file common.c +* @version: 1.0 +* @author: AIIT XUOS Lab +* @date: 2023/3/24 +*/ + +#include +#include "common.h" + + +/** + * @brief UartConfig + * @param None + * @retval None + */ +void UartConfig(void) +{ +} + + +/** + * @brief Print a string on the HyperTerminal + * @param s: The string to be printed + * @retval None + */ +void Serial_PutString(uint8_t *s) +{ + KPrintf("%s", s); +} + +/** + * @brief Test to see if a key has been pressed on the HyperTerminal + * @param key: The key pressed + * @retval 1: Correct + * 0: Error + */ +uint32_t SerialKeyPressed(uint8_t *key) +{ + return 0; +} + +/** + * @brief Get a key from the HyperTerminal + * @param None + * @retval The Key Pressed + */ +uint8_t GetKey(void) +{ + return 0; +} diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/common/ymodem.c b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/common/ymodem.c new file mode 100644 index 000000000..fed17995b --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/common/ymodem.c @@ -0,0 +1,54 @@ +/* +* Copyright (c) 2020 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +/** +* @file: ymodem.c +* @brief: file ymodem.c +* @version: 1.0 +* @author: AIIT XUOS Lab +* @date: 2023/3/24 +*/ +#include +#include "ymodem.h" +#include "string.h" +#include "flash_for_ota.h" + +uint8_t tab_1024[1024] ={0}; +uint8_t FileName[FILE_NAME_LENGTH]; + + + +/******************************************************************************* +* 函 数 名: Ymodem_Receive +* 功能描述: 使用ymodem协议接收文件 +* 形 参: buf:数据buffer + addr:下载flash起始地址 + timeout:超时时间 +* 返 回 值: 文件的大小 +*******************************************************************************/ +int32_t Ymodem_Receive(uint8_t *buf, const uint32_t addr) +{ + int32_t size = 0; + return size; +} + +/******************************************************************************* +* 函 数 名: SerialDownload +* 功能描述: 通过串口下载文件 +* 形 参: addr:存储文件的flash起始地址 +* 返 回 值: 文件的大小 +*******************************************************************************/ +int32_t SerialDownload(const uint32_t addr) +{ + int32_t Size = 0; + return Size; +} diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/include/boot_for_ota.h b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/include/boot_for_ota.h new file mode 100644 index 000000000..eabc70c47 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/include/boot_for_ota.h @@ -0,0 +1,34 @@ +/* +* Copyright (c) 2020 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +/** +* @file boot_for_ota.h +* @brief support bootloader function +* @version 2.0 +* @author AIIT XUOS Lab +* @date 2023-11-20 +*/ + +#ifndef __BOOT_FOR_OTA_H__ +#define __BOOT_FOR_OTA_H__ + +#define IMAGE_IAP_START_ADD 0x08000000 +#define IMAGE_IAP_SIZE 224 * 1024 +#define IMAGE_A_START_ADD (IMAGE_IAP_START_ADD + IMAGE_IAP_SIZE) + +void mcuboot_bord_init(void); +void mcuboot_reset(void); +void mcuboot_jump(void); +void mcuboot_delay(uint32_t ms); + +#endif + diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/include/common.h b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/include/common.h new file mode 100644 index 000000000..216d8e2b9 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/include/common.h @@ -0,0 +1,36 @@ +/* +* Copyright (c) 2020 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +/** +* @file: common.h +* @brief: file common.h +* @version: 1.0 +* @author: AIIT XUOS Lab +* @date: 2023/3/24 +*/ + +#ifndef _COMMON_H +#define _COMMON_H + +#include + +enum { + kStatus_Success = 0, +}; + +void UartConfig(void); +uint32_t SerialKeyPressed(uint8_t *key); +uint8_t GetKey(void); +void SerialPutChar(uint8_t c); +void Serial_PutString(uint8_t *s); + +#endif diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/include/flash_for_ota.h b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/include/flash_for_ota.h new file mode 100644 index 000000000..79aed412f --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/include/flash_for_ota.h @@ -0,0 +1,40 @@ +/* +* Copyright (c) 2020 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + + +/** +* @file flash_for_ota.h +* @brief support flash function +* @version 2.0 +* @author AIIT XUOS Lab +* @date 2023-11-20 +*/ + +#ifndef __FLASH_FOR_OTA_H__ +#define __FLASH_FOR_OTA_H__ + +#include "common.h" + +#define FLASH_PAGE_FAST_SIZE 256 +#define FLASH_BLOCK_SIZE 4096 + +typedef int32_t status_t; + +void FLASH_Init(void); +void FLASH_DeInit(void); +status_t Flash_Erase(uint32_t start_addr, uint32_t imageSize); +status_t Flash_Write(uint32_t WriteAddr, uint8_t *pBuffer, uint32_t NumByteToWrite); +status_t Flash_Read(uint32_t addr, uint8_t *buf, uint32_t len); +status_t Flash_Copy(uint32_t srcAddr,uint32_t dstAddr, uint32_t imageSize); + +#endif + diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/include/ymodem.h b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/include/ymodem.h new file mode 100644 index 000000000..d40b826fe --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/include/ymodem.h @@ -0,0 +1,56 @@ +/* +* Copyright (c) 2020 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +/** +* @file: ymodem.h +* @brief: file ymodem.h +* @version: 1.0 +* @author: AIIT XUOS Lab +* @date: 2023/3/24 +*/ + + +#ifndef _YMODEM_H_ +#define _YMODEM_H_ + +#include + +#define PACKET_SEQNO_INDEX (1) +#define PACKET_SEQNO_COMP_INDEX (2) + +#define PACKET_HEADER (3) +#define PACKET_TRAILER (2) +#define PACKET_OVERHEAD (PACKET_HEADER + PACKET_TRAILER) +#define PACKET_SIZE (128) +#define PACKET_1K_SIZE (1024) + +#define FILE_NAME_LENGTH (256) +#define FILE_SIZE_LENGTH (16) + +#define SOH (0x01) /* start of 128-byte data packet */ +#define STX (0x02) /* start of 1024-byte data packet */ +#define EOT (0x04) /* end of transmission */ +#define ACK (0x06) /* acknowledge */ +#define NAK (0x15) /* negative acknowledge */ +#define CA (0x18) /* two of these in succession aborts transfer */ +#define CRC16 (0x43) /* 'C' == 0x43, request 16-bit CRC */ + +#define ABORT1 (0x41) /* 'A' == 0x41, abort by user */ +#define ABORT2 (0x61) /* 'a' == 0x61, abort by user */ + +#define NAK_TIMEOUT (0x100000) +#define MAX_ERRORS (5) + +int32_t SerialDownload(const uint32_t addr); +int32_t Ymodem_Receive(uint8_t *buf, const uint32_t addr); + +#endif diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/Makefile b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/Makefile new file mode 100644 index 000000000..982ca9cbc --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/Makefile @@ -0,0 +1,3 @@ +SRC_FILES := flash_for_ota.c boot_for_ota.c + +include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/boot_for_ota.c b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/boot_for_ota.c new file mode 100644 index 000000000..1c8ae1190 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/boot_for_ota.c @@ -0,0 +1,133 @@ +/* +* Copyright (c) 2020 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +/** +* @file boot_for_ota.c +* @brief support bootloader function +* @version 2.0 +* @author AIIT XUOS Lab +* @date 2023-11-20 +*/ + +#include +#include +#include "boot_for_ota.h" +#include "flash_for_ota.h" + +#include "board.h" + +#include +#include +#include +#include + +#include "HAL.h" +#include "adc.h" +#include "ch32v20x.h" +#include "connect_ble.h" +#include "connect_can.h" +#include "connect_ether.h" +#include "connect_lte.h" +#include "connect_rs485.h" +#include "connect_uart.h" +#include "core_riscv.h" +#include "config.h" +#include "xsconfig.h" + + +#ifdef TOOL_USING_OTA + +#define jumpApp ((void (*)(void))((int *)(IMAGE_A_START_ADD-0x08000000))) + + +static uint32_t _SysTick_Config(uint32_t ticks) { + // SystemCoreClockUpdate(); + NVIC_SetPriority(SysTicK_IRQn, 0x01); + NVIC_SetPriority(Software_IRQn, 0xf0); + NVIC_EnableIRQ(SysTicK_IRQn); + NVIC_EnableIRQ(Software_IRQn); + SysTick->CTLR = 0; + SysTick->SR = 0; + SysTick->CNT = 0; + SysTick->CMP = ticks - 1; + SysTick->CTLR = 0xF; + return 0; +} + +void mcuboot_bord_init(void) +{ + DISABLE_INTERRUPT(); + /* system irq table must be inited before initialization of Hardware irq */ + SysInitIsrManager(); + +// InitBoardHardware(); +// XiUOSStartup(); + + Delay_Init(); + USART_Printf_Init(115200); + /* System Tick Configuration */ + extern uint32_t SystemCoreClock; + _SysTick_Config(SystemCoreClock / TICK_PER_SECOND); + /* initialize memory system */ + InitBoardMemory(MEMORY_START_ADDRESS, (void *)MEMORY_END_ADDRESS); + +#ifdef BSP_USING_UART + InitHwUart(); + InstallConsole("uart1", SERIAL_DRV_NAME_1, SERIAL_1_DEVICE_NAME_0); + KPrintf("\nboot console init completed.\n"); + KPrintf("boot compiled on: %s at %s\n", __DATE__, __TIME__); +#endif + + void readRomConfiguration(void); + readRomConfiguration(); // 读取配置信息到外部变量CFG中 + + KPrintf("boot board initialization......\n"); + + /* + BOARD_ConfigMPU(); + BOARD_InitPins(); + BOARD_BootClockRUN(); + UartConfig(); + SysTick_Config(SystemCoreClock / TICK_PER_SECOND);*/ +} + +void mcuboot_reset(void) +{ + /* + __set_FAULTMASK(1); + NVIC_SystemReset();*/ +} + +void mcuboot_jump(void) +{ + KPrintf("boot jumpApp\n"); + jumpApp(); + /* + uint32_t addr = XIUOS_FLAH_ADDRESS; + + SCB->VTOR = addr; + asm volatile("LDR R0, %0" : : "m"(addr)); + asm volatile("LDR R0, [R0]"); + asm volatile("MOV SP, R0"); + + addr += 4; + asm volatile("LDR R0, %0" : : "m"(addr)); + asm volatile("LDR R0, [R0]"); + asm volatile("BX R0");*/ +} + +void mcuboot_delay(uint32_t ms) +{ +/* ImxrtMsDelay(ms);*/ +} + +#endif \ No newline at end of file diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/flash_for_ota.c b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/flash_for_ota.c new file mode 100644 index 000000000..263063d92 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/flash_for_ota.c @@ -0,0 +1,258 @@ +/* +* Copyright (c) 2020 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +/** +* @file flash_for_ota.c +* @brief support flash function +* @version 2.0 +* @author AIIT XUOS Lab +* @date 2023-11-20 +*/ + +#include +#include +#include "flash_for_ota.h" +#include "ch32v20x_flash.h" + +#if 0 +uint8_t NorFlash_BUFFER[4096]; //4K buffer cache +uint8_t buffer[FLASH_PAGE_SIZE]; //256 bytes buffer cache +#endif + + + +/******************************************************************************* +* 函 数 名: FLASH_Init +* 功能描述: Flash接口初始化,需在进行Flash相关操作前进行调用 +* 形 参: 无 +* 返 回 值: 无 +*******************************************************************************/ +void FLASH_Init(void) +{ + #if 0 + /* Update LUT Table for Status, Write Enable, Erase and Program */ + ROM_FLEXSPI_NorFlash_UpdateLut(0, NOR_CMD_LUT_SEQ_IDX_READSTATUS, (const uint32_t *)FlashLookupTable.ReadStatus_Seq, 10U); + /* Use 30MHz Flexspi clock for safe operation */ + flexspi_clock_config(0, kFLEXSPISerialClk_30MHz, kFLEXSPIClk_DDR); + extern flexspi_nor_config_t Qspiflash_config; + flexspi_config_mcr1(0, &Qspiflash_config.memConfig); + flexspi_configure_dll(0, &Qspiflash_config.memConfig); + ROM_FLEXSPI_NorFlash_ClearCache(0); + #endif +} + + +/******************************************************************************* +* 函 数 名: FLASH_DeInit +* 功能描述: Flash接口反初始化,需在完成Flash相关操作后进行调用 +* 形 参: 无 +* 返 回 值: 无 +*******************************************************************************/ +void FLASH_DeInit(void) +{ + #if 0 + lookuptable_t clearlut; + memset(&clearlut, 0, sizeof(lookuptable_t)); + ROM_FLEXSPI_NorFlash_UpdateLut(0, NOR_CMD_LUT_SEQ_IDX_READSTATUS, (const uint32_t *)FlashLookupTable.ReadStatus_Seq, 10U); + /* Use 30MHz Flexspi clock for safe operation */ + flexspi_clock_config(0, kFLEXSPISerialClk_30MHz, kFLEXSPIClk_DDR); + #endif +} + +/******************************************************************************* +* 函 数 名: Flash_Erase +* 功能描述: 以扇区为擦除单位擦除Flash指定长度的空间,最终擦除的字节可能大于imageSize +* 形 参: start_addr:擦除区域起始地址 + imageSize:要擦除的字节数 +* 返 回 值: 如果函数执行成功,状态值为 kStatus_Success,否则状态值为其他错误码 +*******************************************************************************/ +status_t Flash_Erase(uint32_t start_addr, uint32_t imageSize) +{ + uint16_t i; + uint32_t pageNum = (imageSize%FLASH_PAGE_FAST_SIZE != 0)? (imageSize/FLASH_PAGE_FAST_SIZE + 1):(imageSize/FLASH_PAGE_FAST_SIZE); + + KPrintf("Flash_Erase start_addr=0x%x imageSize=0x%x\n", start_addr, imageSize); + KPrintf("Flash_Erase pageNum=%d\n", pageNum); + FLASH_Unlock_Fast(); + for(i = 0; i < pageNum; i++) + { + FLASH_ErasePage_Fast(start_addr + (i * FLASH_PAGE_FAST_SIZE)); + } + FLASH_Lock_Fast(); + + return (status_t)kStatus_Success; +} + +/******************************************************************************* +* 函 数 名: Flash_Write +* 功能描述: 写入W25QXX在指定地址开始写入指定长度的数据 +* 形 参: pBuffer:数据存储区 + WriteAddr:开始写入的地址 + NumByteToWrite:要写入的字节数(最大65535) +* 返 回 值: 如果函数执行成功,状态值为 kStatus_Success,否则状态值为其他错误码 +* 注 释: 该函数带擦除操作 +*******************************************************************************/ +status_t Flash_Write(uint32_t WriteAddr, uint8_t *pBuffer, uint32_t NumByteToWrite) +{ + uint8_t page_count; + uint32_t pageNum = (NumByteToWrite%FLASH_PAGE_FAST_SIZE != 0)? (NumByteToWrite/FLASH_PAGE_FAST_SIZE + 1):(NumByteToWrite/FLASH_PAGE_FAST_SIZE); + + FLASH_Unlock_Fast(); + for(page_count = 0; page_count < pageNum; page_count++) + { + FLASH_ProgramPage_Fast(WriteAddr + (page_count * FLASH_PAGE_FAST_SIZE), (uint32_t *)&pBuffer[page_count * FLASH_PAGE_FAST_SIZE]); + } + FLASH_Lock_Fast(); + + return (status_t)kStatus_Success; + +} + +/******************************************************************************* +* 函 数 名: Flash_Read +* 功能描述: 读Flash内容 +* 形 参: addr:读取区域起始地址 + buf:数据存储区 + len:要读取的字节数 +* 返 回 值: 如果函数执行成功,状态值为 kStatus_Success,否则状态值为其他错误码 +*******************************************************************************/ +status_t Flash_Read(uint32_t addr, uint8_t *buf, uint32_t len) +{ + uint32_t i; + for(i=0;i APP_FLASH_SIZE) + { + return (status_t)kStatus_Fail; + } + + status = Flash_Erase(dstAddr,imageSize); + if(status != kStatus_Success) + { + KPrintf("Erase flash 0x%08x failure !\r\n",dstAddr); + return status; + } + + PageNum = imageSize/FLASH_PAGE_SIZE; + Remain = imageSize%FLASH_PAGE_SIZE; + + for(i=0;i=SECTOR_SIZE) + { + status = Flash_Write(WriteAddr,dataBuff,dataLen); + if(status != kStatus_Success) + { + return status; + } + packetNum = 0; + dataLen = 0; + } + *FlashAddress += DataLength; + } + else + { + status = Flash_Write(WriteAddr,dataBuff,dataLen); + if(status != kStatus_Success) + { + return status; + } + packetNum = 0; + dataLen = 0; + } + return (status_t)kStatus_Success;; + #endif + return 0; +} diff --git a/Ubiquitous/XiZi_IIoT/script.sh b/Ubiquitous/XiZi_IIoT/script.sh new file mode 100755 index 000000000..2da11a0bd --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/script.sh @@ -0,0 +1,6 @@ +#! /bin/env sh +export CROSS_COMPILE=/home/syg/data/ch32v208/xpack-riscv-none-elf-gcc-11.3.0-1/bin/riscv-none-elf- +make BOARD=ch32v208rbt6 distclean +make BOARD=ch32v208rbt6 menuconfig +make BOARD=ch32v208rbt6 + From 07126e6bd1d65e9a78c864167c766e3431ebcb3a Mon Sep 17 00:00:00 2001 From: songyanguang <345810377@qq.com> Date: Fri, 9 May 2025 16:22:34 +0800 Subject: [PATCH 02/15] Add .defconfig_boot --- .../risc-v/ch32v208rbt6/User/ch32v20x_it.c | 2 + .../XiZi_IIoT/board/ch32v208rbt6/.defconfig | 6 +- .../board/ch32v208rbt6/.defconfig_app | 349 ++++++++++++++++++ .../board/ch32v208rbt6/.defconfig_boot | 322 ++++++++++++++++ .../board/ch32v208rbt6/link_application.ld | 4 +- .../board/ch32v208rbt6/link_bootloader.ld | 2 +- .../third_party_driver/include/boot_for_ota.h | 2 +- .../third_party_driver/lte/test/lte_test.c | 1 - .../third_party_driver/ota/boot_for_ota.c | 2 +- .../third_party_driver/ota/flash_for_ota.c | 12 +- .../XiZi_IIoT/kernel/memory/byte_manage.c | 2 + 11 files changed, 690 insertions(+), 14 deletions(-) create mode 100644 Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig_app create mode 100644 Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig_boot diff --git a/Ubiquitous/XiZi_IIoT/arch/risc-v/ch32v208rbt6/User/ch32v20x_it.c b/Ubiquitous/XiZi_IIoT/arch/risc-v/ch32v208rbt6/User/ch32v20x_it.c index a2b6beb74..3e93bdcbd 100644 --- a/Ubiquitous/XiZi_IIoT/arch/risc-v/ch32v208rbt6/User/ch32v20x_it.c +++ b/Ubiquitous/XiZi_IIoT/arch/risc-v/ch32v208rbt6/User/ch32v20x_it.c @@ -54,10 +54,12 @@ void HardFault_Handler(void) KPrintf("mepc :%08x\r\n", __get_MEPC()); KPrintf("mcause:%08x\r\n", __get_MCAUSE()); KPrintf("mtval :%08x\r\n", __get_MTVAL()); +#ifdef TOOL_SHELL extern void ShowTask(void); extern void ShowMemory(void); ShowTask(); ShowMemory(); +#endif while (1) ; diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig index 2652dea46..0f73b9a99 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig @@ -198,9 +198,9 @@ CONFIG_OTA_BY_PLATFORM=y # Flash area address and size configuration. # CONFIG_CHIP_FLAH_BASE=0x08000000 -CONFIG_XIUOS_FLAH_ADDRESS=0x60100000 -CONFIG_BAKUP_FLAH_ADDRESS=0x60300000 -CONFIG_DOWN_FLAH_ADDRESS=0x08038000 +CONFIG_XIUOS_FLAH_ADDRESS=0x0801c000 +CONFIG_BAKUP_FLAH_ADDRESS=0x0801c000 +CONFIG_DOWN_FLAH_ADDRESS=0x0801c000 CONFIG_FLAG_FLAH_ADDRESS=0x08077000 CONFIG_APP_FLASH_SIZE=0x00100000 CONFIG_OTA_RX_TIMEOUT=600 diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig_app b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig_app new file mode 100644 index 000000000..0f73b9a99 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig_app @@ -0,0 +1,349 @@ +# +# Automatically generated file; DO NOT EDIT. +# XiZi_IIoT Project Configuration +# +CONFIG_BOARD_CH32V208RBT6=y +CONFIG_ARCH_RISCV=y + +# +# ch32v208rbt6 feature +# +CONFIG_BSP_USING_UART=y +CONFIG_BSP_USING_UART1=y +CONFIG_SERIAL_BUS_NAME_1="uart1" +CONFIG_SERIAL_DRV_NAME_1="uart1_drv" +CONFIG_SERIAL_1_DEVICE_NAME_0="uart1_dev1" +# CONFIG_BSP_USING_ETH is not set +# CONFIG_BSP_USING_ADC is not set +# CONFIG_BSP_USING_BLE is not set +# CONFIG_BSP_USING_CAN is not set +# CONFIG_BSP_USING_RS485 is not set +CONFIG_BSP_USING_LTE=y +CONFIG_LTE_BUS_NAME="lte" +CONFIG_LTE_DRV_NAME="lte_drv" +CONFIG_LTE_DEVICE_NAME_1="lte_dev1" + +# +# Hardware feature +# +CONFIG_RESOURCES_SERIAL=y +CONFIG_SERIAL_USING_DMA=y +CONFIG_SERIAL_RB_BUFSZ=128 + +# +# Kernel feature +# + +# +# separate compile(choose none for compile once) +# +# CONFIG_SEPARATE_COMPILE is not set +# CONFIG_COMPILER_APP is not set +# CONFIG_APP_STARTUP_FROM_SDCARD is not set +CONFIG_APP_STARTUP_FROM_FLASH=y +# CONFIG_COMPILER_KERNEL is not set + +# +# Memory Management +# +# CONFIG_KERNEL_MEMBLOCK is not set +CONFIG_MEM_ALIGN_SIZE=8 +# CONFIG_MEM_EXTERN_SRAM is not set +CONFIG_MM_PAGE_SIZE=4096 + +# +# Using small memory allocator +# +CONFIG_KERNEL_SMALL_MEM_ALLOC=y +CONFIG_SMALL_NUMBER_32B=64 +CONFIG_SMALL_NUMBER_64B=32 + +# +# Task feature +# +CONFIG_USER_APPLICATION=y +# CONFIG_TASK_ISOLATION is not set +# CONFIG_KERNEL_CAPABILITY is not set + +# +# Inter-Task communication +# +CONFIG_KERNEL_SEMAPHORE=y +CONFIG_KERNEL_MUTEX=y +CONFIG_KERNEL_EVENT=y +CONFIG_KERNEL_MESSAGEQUEUE=y +CONFIG_KERNEL_SOFTTIMER=y +CONFIG_SCHED_POLICY_RR_REMAINSLICE=y +# CONFIG_SCHED_POLICY_RR is not set +# CONFIG_SCHED_POLICY_FIFO is not set +# CONFIG_KTASK_PRIORITY_8 is not set +CONFIG_KTASK_PRIORITY_32=y +# CONFIG_KTASK_PRIORITY_256 is not set +CONFIG_KTASK_PRIORITY_MAX=32 +CONFIG_TICK_PER_SECOND=100 +CONFIG_KERNEL_STACK_OVERFLOW_CHECK=y +CONFIG_IDLE_KTASK_STACKSIZE=512 +CONFIG_ZOMBIE_KTASK_STACKSIZE=512 + +# +# Kernel Console +# +CONFIG_KERNEL_CONSOLE=y +CONFIG_KERNEL_BANNER=y +CONFIG_KERNEL_CONSOLEBUF_SIZE=128 + +# +# Kernel Hook +# +# CONFIG_KERNEL_HOOK is not set + +# +# Command shell +# +CONFIG_TOOL_SHELL=y +CONFIG_SHELL_ENTER_CR=y +CONFIG_SHELL_ENTER_LF=y +CONFIG_SHELL_ENTER_CR_AND_LF=y +# CONFIG_SHELL_ENTER_CRLF is not set + +# +# Set shell user control +# +CONFIG_SHELL_DEFAULT_USER="letter" +CONFIG_SHELL_DEFAULT_USER_PASSWORD="" +CONFIG_SHELL_LOCK_TIMEOUT=10000 + +# +# Set shell config param +# +CONFIG_SHELL_TASK_STACK_SIZE=1024 +CONFIG_SHELL_TASK_PRIORITY=20 +CONFIG_SHELL_MAX_NUMBER=5 +CONFIG_SHELL_PARAMETER_MAX_NUMBER=8 +CONFIG_SHELL_HISTORY_MAX_NUMBER=5 +CONFIG_SHELL_PRINT_BUFFER=128 +CONFIG_SHELL_HELP_SHOW_PERMISSION=y +# CONFIG_SHELL_HELP_LIST_USER is not set +CONFIG_SHELL_HELP_LIST_VAR=y +# CONFIG_SHELL_HELP_LIST_KEY is not set + +# +# Kernel data structure Manage +# +CONFIG_KERNEL_QUEUEMANAGE=y +CONFIG_KERNEL_WORKQUEUE=y +CONFIG_WORKQUEUE_KTASK_STACKSIZE=2048 +CONFIG_WORKQUEUE_KTASK_PRIORITY=23 +CONFIG_QUEUE_MAX=16 +CONFIG_KERNEL_WAITQUEUE=y +CONFIG_KERNEL_DATAQUEUE=y +# CONFIG_KERNEL_CIRCULAR_AREA is not set +# CONFIG_KERNEL_AVL_TREE is not set + +# +# Kernel components init +# +CONFIG_KERNEL_COMPONENTS_INIT=y +CONFIG_ENV_INIT_KTASK_STACK_SIZE=2048 +CONFIG_KERNEL_USER_MAIN=y +CONFIG_NAME_NUM_MAX=32 +# CONFIG_KERNEL_DEBUG is not set +# CONFIG_ARCH_SMP is not set + +# +# hash table config +# +CONFIG_ID_HTABLE_SIZE=16 +CONFIG_ID_NUM_MAX=128 +# CONFIG_KERNEL_TEST is not set + +# +# Kernel Lib +# +CONFIG_LIB=y +CONFIG_LIB_POSIX=y +CONFIG_LIB_NEWLIB=y +# CONFIG_LIB_MUSLLIB is not set +# CONFIG_LIB_OTHER is not set + +# +# C++ features +# +# CONFIG_LIB_CPLUSPLUS is not set + +# +# File system +# +CONFIG_FS_VFS=y +# CONFIG_VFS_USING_WORKDIR is not set +CONFIG_FS_VFS_DEVFS=y +# CONFIG_FS_VFS_FATFS is not set +# CONFIG_FS_CH376 is not set +# CONFIG_FS_LWEXT4 is not set + +# +# Tool feature +# + +# +# OTA function +# +CONFIG_TOOL_USING_OTA=y +# CONFIG_MCUBOOT_BOOTLOADER is not set +CONFIG_MCUBOOT_APPLICATION=y +CONFIG_OTA_BY_PLATFORM=y +# CONFIG_OTA_BY_TCPSERVER is not set + +# +# Flash area address and size configuration. +# +CONFIG_CHIP_FLAH_BASE=0x08000000 +CONFIG_XIUOS_FLAH_ADDRESS=0x0801c000 +CONFIG_BAKUP_FLAH_ADDRESS=0x0801c000 +CONFIG_DOWN_FLAH_ADDRESS=0x0801c000 +CONFIG_FLAG_FLAH_ADDRESS=0x08077000 +CONFIG_APP_FLASH_SIZE=0x00100000 +CONFIG_OTA_RX_TIMEOUT=600 +CONFIG_OTA_FRAME_SIZE=2048 + +# +# APP_Framework +# + +# +# Framework +# +CONFIG_TRANSFORM_LAYER_ATTRIUBUTE=y +CONFIG_ADD_XIZI_FEATURES=y +# CONFIG_ADD_NUTTX_FEATURES is not set +# CONFIG_ADD_RTTHREAD_FEATURES is not set +# CONFIG_SUPPORT_SENSOR_FRAMEWORK is not set +CONFIG_SUPPORT_CONNECTION_FRAMEWORK=y +# CONFIG_CONNECTION_FRAMEWORK_DEBUG is not set +# CONFIG_CONNECTION_INDUSTRIAL_NETWORK is not set +# CONFIG_CONNECTION_INDUSTRIAL_FIELDBUS is not set +# CONFIG_CONNECTION_INDUSTRIAL_WLAN is not set +# CONFIG_CONNECTION_ADAPTER_LORA is not set +CONFIG_CONNECTION_ADAPTER_4G=y +CONFIG_ADAPTER_EC801E=y +CONFIG_ADAPTER_4G_EC801E="ec801e" +# CONFIG_ADAPTER_EC801E_DRIVER_EXTUART is not set +CONFIG_ADAPTER_EC801E_DRIVER="/dev/lte_dev1" +# CONFIG_ADAPTER_EC200T is not set +# CONFIG_ADAPTER_EC200A is not set +# CONFIG_ADAPTER_GM800TF is not set +# CONFIG_CONNECTION_ADAPTER_NB is not set +# CONFIG_CONNECTION_ADAPTER_WIFI is not set +# CONFIG_CONNECTION_ADAPTER_ETHERNET is not set +# CONFIG_CONNECTION_ADAPTER_BLUETOOTH is not set +# CONFIG_CONNECTION_ADAPTER_ZIGBEE is not set +# CONFIG_CONNECTION_ADAPTER_5G is not set +# CONFIG_SUPPORT_KNOWING_FRAMEWORK is not set +# CONFIG_SUPPORT_CONTROL_FRAMEWORK is not set + +# +# Security +# +# CONFIG_CRYPTO is not set +# CONFIG_MBEDTLS is not set + +# +# Applications +# + +# +# config stack size and priority of main task +# +CONFIG_MAIN_KTASK_STACK_SIZE=1024 +CONFIG_MAIN_KTASK_PRIORITY=16 + +# +# test app +# +# CONFIG_USER_TEST is not set + +# +# connection app +# +# CONFIG_APPLICATION_CONNECTION is not set + +# +# control app +# + +# +# knowing app +# +# CONFIG_APPLICATION_KNOWING is not set + +# +# sensor app +# +# CONFIG_APPLICATION_SENSOR is not set +# CONFIG_USING_EMBEDDED_DATABASE_APP is not set +# CONFIG_APP_USING_WEBNET is not set +# CONFIG_APPLICATION_WEBSERVER is not set + +# +# app lib +# +CONFIG_APP_SELECT_NEWLIB=y +# CONFIG_APP_SELECT_OTHER_LIB is not set + +# +# lib using cJSON +# +# CONFIG_LIB_USING_CJSON is not set + +# +# lib using queue +# +# CONFIG_LIB_USING_QUEUE is not set + +# +# lib using LVGL +# +# CONFIG_LIB_LV is not set + +# +# lvgl image display parameter settings +# +CONFIG_LVGL_WIDTH=320 +CONFIG_LVGL_HEIGHT=320 + +# +# lib using embedded_database +# +# CONFIG_USING_EMBEDDED_DATABASE is not set + +# +# lib using LoRaWan +# +# CONFIG_LIB_USING_LORAWAN is not set + +# +# lib using MQTT +# +CONFIG_LIB_USING_MQTT=y +CONFIG_XIUOS_PLATFORM=y +# CONFIG_ALIBABA_PLATFORM is not set + +# +# xiuos platform mqtt connection parameter configuration. +# +CONFIG_CLIENTID="D001" +CONFIG_USERNAME="xiuosiot" +CONFIG_PASSWORD="xiuosiot" +CONFIG_PLATFORM_SERVERIP="115.238.53.59" +CONFIG_PLATFORM_SERVERPORT="1883" +# CONFIG_USING_DOWNLOAD_JSON is not set + +# +# lib using JerryScript +# +# CONFIG_LIB_USING_JERRYSCRIPT is not set + +# +# lib using SQLite +# +# CONFIG_LIB_USING_SQLITE is not set diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig_boot b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig_boot new file mode 100644 index 000000000..72bbe113e --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig_boot @@ -0,0 +1,322 @@ +# +# Automatically generated file; DO NOT EDIT. +# XiZi_IIoT Project Configuration +# +CONFIG_BOARD_CH32V208RBT6=y +CONFIG_ARCH_RISCV=y + +# +# ch32v208rbt6 feature +# +CONFIG_BSP_USING_UART=y +CONFIG_BSP_USING_UART1=y +CONFIG_SERIAL_BUS_NAME_1="uart1" +CONFIG_SERIAL_DRV_NAME_1="uart1_drv" +CONFIG_SERIAL_1_DEVICE_NAME_0="uart1_dev1" +# CONFIG_BSP_USING_ETH is not set +# CONFIG_BSP_USING_ADC is not set +# CONFIG_BSP_USING_BLE is not set +# CONFIG_BSP_USING_CAN is not set +# CONFIG_BSP_USING_RS485 is not set +CONFIG_BSP_USING_LTE=y +CONFIG_LTE_BUS_NAME="lte" +CONFIG_LTE_DRV_NAME="lte_drv" +CONFIG_LTE_DEVICE_NAME_1="lte_dev1" + +# +# Hardware feature +# +CONFIG_RESOURCES_SERIAL=y +CONFIG_SERIAL_USING_DMA=y +CONFIG_SERIAL_RB_BUFSZ=128 + +# +# Kernel feature +# + +# +# separate compile(choose none for compile once) +# +# CONFIG_SEPARATE_COMPILE is not set +# CONFIG_COMPILER_APP is not set +# CONFIG_APP_STARTUP_FROM_SDCARD is not set +CONFIG_APP_STARTUP_FROM_FLASH=y +# CONFIG_COMPILER_KERNEL is not set + +# +# Memory Management +# +# CONFIG_KERNEL_MEMBLOCK is not set +CONFIG_MEM_ALIGN_SIZE=8 +# CONFIG_MEM_EXTERN_SRAM is not set +CONFIG_MM_PAGE_SIZE=4096 + +# +# Using small memory allocator +# +CONFIG_KERNEL_SMALL_MEM_ALLOC=y +CONFIG_SMALL_NUMBER_32B=64 +CONFIG_SMALL_NUMBER_64B=32 + +# +# Task feature +# +CONFIG_USER_APPLICATION=y +# CONFIG_TASK_ISOLATION is not set +# CONFIG_KERNEL_CAPABILITY is not set + +# +# Inter-Task communication +# +CONFIG_KERNEL_SEMAPHORE=y +CONFIG_KERNEL_MUTEX=y +CONFIG_KERNEL_EVENT=y +CONFIG_KERNEL_MESSAGEQUEUE=y +CONFIG_KERNEL_SOFTTIMER=y +CONFIG_SCHED_POLICY_RR_REMAINSLICE=y +# CONFIG_SCHED_POLICY_RR is not set +# CONFIG_SCHED_POLICY_FIFO is not set +# CONFIG_KTASK_PRIORITY_8 is not set +CONFIG_KTASK_PRIORITY_32=y +# CONFIG_KTASK_PRIORITY_256 is not set +CONFIG_KTASK_PRIORITY_MAX=32 +CONFIG_TICK_PER_SECOND=100 +CONFIG_KERNEL_STACK_OVERFLOW_CHECK=y +CONFIG_IDLE_KTASK_STACKSIZE=512 +CONFIG_ZOMBIE_KTASK_STACKSIZE=512 + +# +# Kernel Console +# +CONFIG_KERNEL_CONSOLE=y +CONFIG_KERNEL_BANNER=y +CONFIG_KERNEL_CONSOLEBUF_SIZE=128 + +# +# Kernel Hook +# +# CONFIG_KERNEL_HOOK is not set + +# +# Command shell +# +# CONFIG_TOOL_SHELL is not set + +# +# Kernel data structure Manage +# +CONFIG_KERNEL_QUEUEMANAGE=y +CONFIG_KERNEL_WORKQUEUE=y +CONFIG_WORKQUEUE_KTASK_STACKSIZE=2048 +CONFIG_WORKQUEUE_KTASK_PRIORITY=23 +CONFIG_QUEUE_MAX=16 +CONFIG_KERNEL_WAITQUEUE=y +CONFIG_KERNEL_DATAQUEUE=y +# CONFIG_KERNEL_CIRCULAR_AREA is not set +# CONFIG_KERNEL_AVL_TREE is not set + +# +# Kernel components init +# +CONFIG_KERNEL_COMPONENTS_INIT=y +CONFIG_ENV_INIT_KTASK_STACK_SIZE=2048 +CONFIG_KERNEL_USER_MAIN=y +CONFIG_NAME_NUM_MAX=32 +# CONFIG_KERNEL_DEBUG is not set +# CONFIG_ARCH_SMP is not set + +# +# hash table config +# +CONFIG_ID_HTABLE_SIZE=16 +CONFIG_ID_NUM_MAX=128 +# CONFIG_KERNEL_TEST is not set + +# +# Kernel Lib +# +CONFIG_LIB=y +CONFIG_LIB_POSIX=y +CONFIG_LIB_NEWLIB=y +# CONFIG_LIB_MUSLLIB is not set +# CONFIG_LIB_OTHER is not set + +# +# C++ features +# +# CONFIG_LIB_CPLUSPLUS is not set + +# +# File system +# +CONFIG_FS_VFS=y +# CONFIG_VFS_USING_WORKDIR is not set +CONFIG_FS_VFS_DEVFS=y +# CONFIG_FS_VFS_FATFS is not set +# CONFIG_FS_CH376 is not set +# CONFIG_FS_LWEXT4 is not set + +# +# Tool feature +# + +# +# OTA function +# +CONFIG_TOOL_USING_OTA=y +CONFIG_MCUBOOT_BOOTLOADER=y +# CONFIG_MCUBOOT_APPLICATION is not set + +# +# Flash area address and size configuration. +# +CONFIG_CHIP_FLAH_BASE=0x08000000 +CONFIG_XIUOS_FLAH_ADDRESS=0x0801c000 +CONFIG_BAKUP_FLAH_ADDRESS=0x0801c000 +CONFIG_DOWN_FLAH_ADDRESS=0x0801c000 +CONFIG_FLAG_FLAH_ADDRESS=0x08077000 +CONFIG_APP_FLASH_SIZE=0x00100000 +CONFIG_OTA_RX_TIMEOUT=600 +CONFIG_OTA_FRAME_SIZE=2048 + +# +# APP_Framework +# + +# +# Framework +# +CONFIG_TRANSFORM_LAYER_ATTRIUBUTE=y +CONFIG_ADD_XIZI_FEATURES=y +# CONFIG_ADD_NUTTX_FEATURES is not set +# CONFIG_ADD_RTTHREAD_FEATURES is not set +# CONFIG_SUPPORT_SENSOR_FRAMEWORK is not set +CONFIG_SUPPORT_CONNECTION_FRAMEWORK=y +# CONFIG_CONNECTION_FRAMEWORK_DEBUG is not set +# CONFIG_CONNECTION_INDUSTRIAL_NETWORK is not set +# CONFIG_CONNECTION_INDUSTRIAL_FIELDBUS is not set +# CONFIG_CONNECTION_INDUSTRIAL_WLAN is not set +# CONFIG_CONNECTION_ADAPTER_LORA is not set +CONFIG_CONNECTION_ADAPTER_4G=y +CONFIG_ADAPTER_EC801E=y +CONFIG_ADAPTER_4G_EC801E="ec801e" +# CONFIG_ADAPTER_EC801E_DRIVER_EXTUART is not set +CONFIG_ADAPTER_EC801E_DRIVER="/dev/lte_dev1" +# CONFIG_ADAPTER_EC200T is not set +# CONFIG_ADAPTER_EC200A is not set +# CONFIG_ADAPTER_GM800TF is not set +# CONFIG_CONNECTION_ADAPTER_NB is not set +# CONFIG_CONNECTION_ADAPTER_WIFI is not set +# CONFIG_CONNECTION_ADAPTER_ETHERNET is not set +# CONFIG_CONNECTION_ADAPTER_BLUETOOTH is not set +# CONFIG_CONNECTION_ADAPTER_ZIGBEE is not set +# CONFIG_CONNECTION_ADAPTER_5G is not set +# CONFIG_SUPPORT_KNOWING_FRAMEWORK is not set +# CONFIG_SUPPORT_CONTROL_FRAMEWORK is not set + +# +# Security +# +# CONFIG_CRYPTO is not set +# CONFIG_MBEDTLS is not set + +# +# Applications +# + +# +# config stack size and priority of main task +# +CONFIG_MAIN_KTASK_STACK_SIZE=1024 +CONFIG_MAIN_KTASK_PRIORITY=16 + +# +# test app +# +# CONFIG_USER_TEST is not set + +# +# connection app +# +# CONFIG_APPLICATION_CONNECTION is not set + +# +# control app +# + +# +# knowing app +# +# CONFIG_APPLICATION_KNOWING is not set + +# +# sensor app +# +# CONFIG_APPLICATION_SENSOR is not set +# CONFIG_USING_EMBEDDED_DATABASE_APP is not set +# CONFIG_APP_USING_WEBNET is not set +# CONFIG_APPLICATION_WEBSERVER is not set + +# +# app lib +# +CONFIG_APP_SELECT_NEWLIB=y +# CONFIG_APP_SELECT_OTHER_LIB is not set + +# +# lib using cJSON +# +# CONFIG_LIB_USING_CJSON is not set + +# +# lib using queue +# +# CONFIG_LIB_USING_QUEUE is not set + +# +# lib using LVGL +# +# CONFIG_LIB_LV is not set + +# +# lvgl image display parameter settings +# +CONFIG_LVGL_WIDTH=320 +CONFIG_LVGL_HEIGHT=320 + +# +# lib using embedded_database +# +# CONFIG_USING_EMBEDDED_DATABASE is not set + +# +# lib using LoRaWan +# +# CONFIG_LIB_USING_LORAWAN is not set + +# +# lib using MQTT +# +CONFIG_LIB_USING_MQTT=y +CONFIG_XIUOS_PLATFORM=y +# CONFIG_ALIBABA_PLATFORM is not set + +# +# xiuos platform mqtt connection parameter configuration. +# +CONFIG_CLIENTID="D001" +CONFIG_USERNAME="xiuosiot" +CONFIG_PASSWORD="xiuosiot" +CONFIG_PLATFORM_SERVERIP="115.238.53.59" +CONFIG_PLATFORM_SERVERPORT="1883" +# CONFIG_USING_DOWNLOAD_JSON is not set + +# +# lib using JerryScript +# +# CONFIG_LIB_USING_JERRYSCRIPT is not set + +# +# lib using SQLite +# +# CONFIG_LIB_USING_SQLITE is not set diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/link_application.ld b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/link_application.ld index 9371cfc8e..2a03937ef 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/link_application.ld +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/link_application.ld @@ -27,8 +27,8 @@ MEMORY FLASH-160K + RAM-32K */ /*FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 448K*/ - FLASH (rx) : ORIGIN = 0x00038000, LENGTH = 248K - RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 48K + FLASH (rx) : ORIGIN = 0x0001c000, LENGTH = 364K + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K } diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/link_bootloader.ld b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/link_bootloader.ld index 2ae093e9a..216f29a3f 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/link_bootloader.ld +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/link_bootloader.ld @@ -26,7 +26,7 @@ MEMORY FLASH-144K + RAM-48K FLASH-160K + RAM-32K */ - FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 224K + FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 112K RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K } diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/include/boot_for_ota.h b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/include/boot_for_ota.h index eabc70c47..ce846e67a 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/include/boot_for_ota.h +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/include/boot_for_ota.h @@ -22,7 +22,7 @@ #define __BOOT_FOR_OTA_H__ #define IMAGE_IAP_START_ADD 0x08000000 -#define IMAGE_IAP_SIZE 224 * 1024 +#define IMAGE_IAP_SIZE (112 * 1024) #define IMAGE_A_START_ADD (IMAGE_IAP_START_ADD + IMAGE_IAP_SIZE) void mcuboot_bord_init(void); diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/lte/test/lte_test.c b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/lte/test/lte_test.c index ecee4de23..878550bd0 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/lte/test/lte_test.c +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/lte/test/lte_test.c @@ -21,7 +21,6 @@ #include "ch32v20x_usart.h" #include "connect_uart.h" #include "debug.h" -#include "shell.h" #include "string.h" #define TRANSPARENT_TRANSMISSION_MODE 0 diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/boot_for_ota.c b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/boot_for_ota.c index 1c8ae1190..1270cb2ca 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/boot_for_ota.c +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/boot_for_ota.c @@ -90,7 +90,7 @@ void mcuboot_bord_init(void) void readRomConfiguration(void); readRomConfiguration(); // 读取配置信息到外部变量CFG中 - KPrintf("boot board initialization......\n"); + KPrintf("mcuboot board initialization......\n"); /* BOARD_ConfigMPU(); diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/flash_for_ota.c b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/flash_for_ota.c index 263063d92..81ee0ef65 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/flash_for_ota.c +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/flash_for_ota.c @@ -77,17 +77,17 @@ void FLASH_DeInit(void) *******************************************************************************/ status_t Flash_Erase(uint32_t start_addr, uint32_t imageSize) { - uint16_t i; + uint32_t page_count; uint32_t pageNum = (imageSize%FLASH_PAGE_FAST_SIZE != 0)? (imageSize/FLASH_PAGE_FAST_SIZE + 1):(imageSize/FLASH_PAGE_FAST_SIZE); KPrintf("Flash_Erase start_addr=0x%x imageSize=0x%x\n", start_addr, imageSize); - KPrintf("Flash_Erase pageNum=%d\n", pageNum); FLASH_Unlock_Fast(); - for(i = 0; i < pageNum; i++) + for(page_count = 0; page_count < pageNum; page_count++) { - FLASH_ErasePage_Fast(start_addr + (i * FLASH_PAGE_FAST_SIZE)); + FLASH_ErasePage_Fast(start_addr + (page_count * FLASH_PAGE_FAST_SIZE)); } FLASH_Lock_Fast(); + KPrintf("Flash_Erase start_addr=0x%x success\n", start_addr); return (status_t)kStatus_Success; } @@ -103,15 +103,17 @@ status_t Flash_Erase(uint32_t start_addr, uint32_t imageSize) *******************************************************************************/ status_t Flash_Write(uint32_t WriteAddr, uint8_t *pBuffer, uint32_t NumByteToWrite) { - uint8_t page_count; + uint32_t page_count; uint32_t pageNum = (NumByteToWrite%FLASH_PAGE_FAST_SIZE != 0)? (NumByteToWrite/FLASH_PAGE_FAST_SIZE + 1):(NumByteToWrite/FLASH_PAGE_FAST_SIZE); + KPrintf("Flash_Write start_addr=0x%x imageSize=0x%x\n", WriteAddr, NumByteToWrite); FLASH_Unlock_Fast(); for(page_count = 0; page_count < pageNum; page_count++) { FLASH_ProgramPage_Fast(WriteAddr + (page_count * FLASH_PAGE_FAST_SIZE), (uint32_t *)&pBuffer[page_count * FLASH_PAGE_FAST_SIZE]); } FLASH_Lock_Fast(); + KPrintf("Flash_Write start_addr=0x%x success\n", WriteAddr); return (status_t)kStatus_Success; diff --git a/Ubiquitous/XiZi_IIoT/kernel/memory/byte_manage.c b/Ubiquitous/XiZi_IIoT/kernel/memory/byte_manage.c index a672b643b..80ce5e7cd 100644 --- a/Ubiquitous/XiZi_IIoT/kernel/memory/byte_manage.c +++ b/Ubiquitous/XiZi_IIoT/kernel/memory/byte_manage.c @@ -660,8 +660,10 @@ void *x_malloc(x_size_t size) KPrintf("dynamic_buddy_end:%d\n", ByteManager.dynamic_buddy_manager.dynamic_buddy_end); KPrintf("dynamic_buddy_start:%d\n", ByteManager.dynamic_buddy_manager.dynamic_buddy_start); KPrintf("active_memory:%d\n", ByteManager.dynamic_buddy_manager.active_memory); +#ifdef TOOL_SHELL extern int ShowTask(); ShowTask(); +#endif return NONE; } #endif From a3771bed071124579dcda3e1dae7d3490b612f9a Mon Sep 17 00:00:00 2001 From: songyanguang <345810377@qq.com> Date: Fri, 9 May 2025 16:48:40 +0800 Subject: [PATCH 03/15] Fixed a compilation issue --- Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/board.c | 2 ++ Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.c | 3 +-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/board.c b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/board.c index be89bb33d..04d16c862 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/board.c +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/board.c @@ -72,12 +72,14 @@ void readRomConfiguration(void) { extern pmodule_cfg CFG; // 指向配置信息的指针 /* 从EEPROM中读取网络配置信息 */ + KPrintf("%s PAGE_WRITE_START_ADDR=%08x\n", __func__, PAGE_WRITE_START_ADDR); CFG_READ(PAGE_WRITE_START_ADDR, Configbuf, MODULE_CFG_LEN); /* 如果存储在EEPROM中的网络配置信息无效,或者WCHNET还没有被主机配置过,通过默认配置信息初始化WCHNET */ if ((CFG->cfgFlag[0] != checkcode1) || (CFG->cfgFlag[1] != checkcode2)) { CFG_ERASE(PAGE_WRITE_START_ADDR, FLASH_PAGE_SIZE); CFG_WRITE(PAGE_WRITE_START_ADDR, (u8 *)&defaultConfiguration, MODULE_CFG_LEN); + KPrintf("%s NVIC_SystemReset\n", __func__); NVIC_SystemReset(); // 复位ch32v208 } diff --git a/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.c b/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.c index 619686935..515c6e629 100644 --- a/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.c +++ b/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.c @@ -22,7 +22,6 @@ #include #include #include -#include "shell.h" #include "boot_for_ota.h" #include "ymodem.h" #include "ota.h" @@ -1451,4 +1450,4 @@ void ota_entry(void) BootLoaderJumpApp(); } } -} \ No newline at end of file +} From cd121f49f9f63bcde03abe27b7dd428fc7c8d606 Mon Sep 17 00:00:00 2001 From: songyanguang <345810377@qq.com> Date: Fri, 9 May 2025 18:21:36 +0800 Subject: [PATCH 04/15] OTA info addresses need to be aligned --- .../Framework/connection/4g/ec801e/ec801e.c | 2 + APP_Framework/lib/mqtt/platform_mqtt.c | 5 + .../XiZi_IIoT/board/ch32v208rbt6/board.c | 2 +- .../third_party_driver/ota/boot_for_ota.c | 2 +- .../third_party_driver/ota/flash_for_ota.c | 8 +- .../XiZi_IIoT/tool/bootloader/ota/ota.c | 97 ++++++++++--------- 6 files changed, 65 insertions(+), 51 deletions(-) diff --git a/APP_Framework/Framework/connection/4g/ec801e/ec801e.c b/APP_Framework/Framework/connection/4g/ec801e/ec801e.c index b1794f40b..afbd895a0 100644 --- a/APP_Framework/Framework/connection/4g/ec801e/ec801e.c +++ b/APP_Framework/Framework/connection/4g/ec801e/ec801e.c @@ -200,6 +200,8 @@ static int Ec801eConnect(struct Adapter *adapter, enum NetRoleType net_role, con int try = 0; uint8_t ec801e_cmd[64]; + ADAPTER_DEBUG("%s enter\n", __func__); + AtSetReplyEndChar(adapter->agent, 0x4F, 0x4B); /*step1: serial write "+++", quit transparent mode*/ diff --git a/APP_Framework/lib/mqtt/platform_mqtt.c b/APP_Framework/lib/mqtt/platform_mqtt.c index ccaf15e1d..41fc624c0 100644 --- a/APP_Framework/lib/mqtt/platform_mqtt.c +++ b/APP_Framework/lib/mqtt/platform_mqtt.c @@ -46,6 +46,8 @@ int AdapterNetActive(void) { int ret = 0; uint32_t baud_rate = BAUD_RATE_115200; + + KPrintf("%s enter\n", __func__); adapter = AdapterDeviceFindByName(ADAPTER_4G_NAME); adapter->socket.socket_id = 0; @@ -66,12 +68,14 @@ int AdapterNetActive(void) { goto out; } + KPrintf("%s success\n", __func__); out: if (ret < 0) { AdapterDeviceClose(adapter); } + KPrintf("%s fail\n", __func__); return ret; } @@ -112,6 +116,7 @@ bool MQTT_Connect(void) { uint8_t TryConnect_time = 10; //尝试登录次数 + KPrintf("%s enter\n", __func__); memset(&Platform_mqtt,0,sizeof(Platform_mqtt)); #ifdef XIUOS_PLATFORM sprintf(Platform_mqtt.ClientID,"%s",CLIENTID); //客户端ID存入缓冲区 diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/board.c b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/board.c index 04d16c862..4607c0f9d 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/board.c +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/board.c @@ -79,7 +79,7 @@ void readRomConfiguration(void) { if ((CFG->cfgFlag[0] != checkcode1) || (CFG->cfgFlag[1] != checkcode2)) { CFG_ERASE(PAGE_WRITE_START_ADDR, FLASH_PAGE_SIZE); CFG_WRITE(PAGE_WRITE_START_ADDR, (u8 *)&defaultConfiguration, MODULE_CFG_LEN); - KPrintf("%s NVIC_SystemReset\n", __func__); + KPrintf("%s NVIC_SystemReset\n\n", __func__); NVIC_SystemReset(); // 复位ch32v208 } diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/boot_for_ota.c b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/boot_for_ota.c index 1270cb2ca..68d229a6e 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/boot_for_ota.c +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/boot_for_ota.c @@ -109,7 +109,7 @@ void mcuboot_reset(void) void mcuboot_jump(void) { - KPrintf("boot jumpApp\n"); + KPrintf("boot jumpApp\n\n"); jumpApp(); /* uint32_t addr = XIUOS_FLAH_ADDRESS; diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/flash_for_ota.c b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/flash_for_ota.c index 81ee0ef65..25d69c17a 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/flash_for_ota.c +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/flash_for_ota.c @@ -80,14 +80,14 @@ status_t Flash_Erase(uint32_t start_addr, uint32_t imageSize) uint32_t page_count; uint32_t pageNum = (imageSize%FLASH_PAGE_FAST_SIZE != 0)? (imageSize/FLASH_PAGE_FAST_SIZE + 1):(imageSize/FLASH_PAGE_FAST_SIZE); - KPrintf("Flash_Erase start_addr=0x%x imageSize=0x%x\n", start_addr, imageSize); + KPrintf("Flash_Erase start_addr=%08x imageSize=0x%x\n", start_addr, imageSize); FLASH_Unlock_Fast(); for(page_count = 0; page_count < pageNum; page_count++) { FLASH_ErasePage_Fast(start_addr + (page_count * FLASH_PAGE_FAST_SIZE)); } FLASH_Lock_Fast(); - KPrintf("Flash_Erase start_addr=0x%x success\n", start_addr); + KPrintf("Flash_Erase start_addr=%08x success\n", start_addr); return (status_t)kStatus_Success; } @@ -106,14 +106,14 @@ status_t Flash_Write(uint32_t WriteAddr, uint8_t *pBuffer, uint32_t NumByteToWri uint32_t page_count; uint32_t pageNum = (NumByteToWrite%FLASH_PAGE_FAST_SIZE != 0)? (NumByteToWrite/FLASH_PAGE_FAST_SIZE + 1):(NumByteToWrite/FLASH_PAGE_FAST_SIZE); - KPrintf("Flash_Write start_addr=0x%x imageSize=0x%x\n", WriteAddr, NumByteToWrite); + KPrintf("Flash_Write start_addr=%08x pBuffer=%p imageSize=0x%x\n", WriteAddr, pBuffer, NumByteToWrite); FLASH_Unlock_Fast(); for(page_count = 0; page_count < pageNum; page_count++) { FLASH_ProgramPage_Fast(WriteAddr + (page_count * FLASH_PAGE_FAST_SIZE), (uint32_t *)&pBuffer[page_count * FLASH_PAGE_FAST_SIZE]); } FLASH_Lock_Fast(); - KPrintf("Flash_Write start_addr=0x%x success\n", WriteAddr); + KPrintf("Flash_Write start_addr=%08x success\n", WriteAddr); return (status_t)kStatus_Success; diff --git a/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.c b/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.c index 515c6e629..2acb19ed3 100644 --- a/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.c +++ b/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.c @@ -104,6 +104,7 @@ static const uint32_t crc32tab[] = { 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d }; +__attribute__((aligned(8))) ota_info_t g_ota_info; /******************************************************************************* * 函 数 名: calculate_crc32 @@ -197,19 +198,19 @@ static status_t UpdateOTAFlag(ota_info_t *ptr) static void InitialVersion(void) { int32_t size; - ota_info_t ota_info; + ota_info_t *p_ota_info = &g_ota_info; - memset(&ota_info, 0, sizeof(ota_info_t)); + memset(p_ota_info, 0, sizeof(ota_info_t)); size = mcuboot.download_by_serial(XIUOS_FLAH_ADDRESS); if(size > 0) { - ota_info.os.size = size; - ota_info.os.crc32 = calculate_crc32(XIUOS_FLAH_ADDRESS, size); + p_ota_info->os.size = size; + p_ota_info->os.crc32 = calculate_crc32(XIUOS_FLAH_ADDRESS, size); - strncpy(ota_info.os.version,"001.000.000",sizeof(ota_info.os.version)); - strncpy(ota_info.os.description, "The initial firmware.", sizeof(ota_info.os.description)); + strncpy(p_ota_info->os.version,"001.000.000",sizeof(p_ota_info->os.version)); + strncpy(p_ota_info->os.description, "The initial firmware.", sizeof(p_ota_info->os.description)); - UpdateOTAFlag(&ota_info); + UpdateOTAFlag(p_ota_info); } } @@ -458,21 +459,26 @@ static void Update(void) *******************************************************************************/ static void BootLoaderJumpApp(void) { - ota_info_t ota_info; + ota_info_t *p_ota_info = &g_ota_info; mcuboot.flash_init(); - memset(&ota_info, 0, sizeof(ota_info_t)); - mcuboot.op_flash_read(FLAG_FLAH_ADDRESS, (void*)&ota_info, sizeof(ota_info_t)); + memset(p_ota_info, 0, sizeof(ota_info_t)); + mcuboot.op_flash_read(FLAG_FLAH_ADDRESS, (void*)p_ota_info, sizeof(ota_info_t)); - if(ota_info.lastjumpflag == JUMP_FAILED_FLAG) + if(p_ota_info->lastjumpflag == JUMP_FAILED_FLAG) { mcuboot.print_string("\r\n------Jump to app partition failed,start version rollback!------\r\n"); - BackupVersion(); +#ifdef BOARD_CH32V208RBT6 + p_ota_info->lastjumpflag = JUMP_SUCCESS_FLAG; + UpdateOTAFlag(p_ota_info); +#else + BackupVersion(); +#endif } else { - ota_info.lastjumpflag = JUMP_FAILED_FLAG; - UpdateOTAFlag(&ota_info); + p_ota_info->lastjumpflag = JUMP_FAILED_FLAG; + UpdateOTAFlag(p_ota_info); } mcuboot.flash_deinit(); mcuboot.op_jump(); @@ -882,18 +888,19 @@ static void mqttCloudInteraction(void* parameter) int datalen; int ret = 0; int freecnt = 0; - ota_info_t ota_info; + ota_info_t *p_ota_info = &g_ota_info; uint32_t heart_time = 0; uint32_t flashdestination = DOWN_FLAH_ADDRESS; uint8_t topicdatabuff[2][64]; char *ptr1, *ptr2; uint16_t payloadLen; + KPrintf("%s enter\n", __func__); mcuboot.flash_init(); - memset(&ota_info, 0, sizeof(ota_info_t)); - mcuboot.op_flash_read(FLAG_FLAH_ADDRESS, (void*)&ota_info, sizeof(ota_info_t)); - ota_info.status = OTA_STATUS_DOWNLOADING; - UpdateOTAFlag(&ota_info); + memset(p_ota_info, 0, sizeof(ota_info_t)); + mcuboot.op_flash_read(FLAG_FLAH_ADDRESS, (void*)p_ota_info, sizeof(ota_info_t)); + p_ota_info->status = OTA_STATUS_DOWNLOADING; + UpdateOTAFlag(p_ota_info); memset(topicdatabuff,0,sizeof(topicdatabuff)); sprintf(topicdatabuff[0],"ota/%s/update",CLIENTID); sprintf(topicdatabuff[1],"ota/%s/files",CLIENTID); @@ -959,20 +966,20 @@ reconnect: { KPrintf("File size is larger than partition size,the partition size is %dk.\n",APP_FLASH_SIZE/1024); ret = -1; - ota_info.status = OTA_STATUS_ERROR; - memset(ota_info.error_message,0,sizeof(ota_info.error_message)); - strncpy(ota_info.error_message, "File size is larger than partition size!",sizeof(ota_info.error_message)); - UpdateOTAFlag(&ota_info); + p_ota_info->status = OTA_STATUS_ERROR; + memset(p_ota_info->error_message,0,sizeof(p_ota_info->error_message)); + strncpy(p_ota_info->error_message, "File size is larger than partition size!",sizeof(p_ota_info->error_message)); + UpdateOTAFlag(p_ota_info); break; } if(mcuboot.op_flash_erase(DOWN_FLAH_ADDRESS,platform_ota.size) != kStatus_Success) { KPrintf("Failed to erase download partition!\n"); ret = -1; - ota_info.status = OTA_STATUS_ERROR; - memset(ota_info.error_message,0,sizeof(ota_info.error_message)); - strncpy(ota_info.error_message, "Failed to erase download partition!",sizeof(ota_info.error_message)); - UpdateOTAFlag(&ota_info); + p_ota_info->status = OTA_STATUS_ERROR; + memset(p_ota_info->error_message,0,sizeof(p_ota_info->error_message)); + strncpy(p_ota_info->error_message, "Failed to erase download partition!",sizeof(p_ota_info->error_message)); + UpdateOTAFlag(p_ota_info); break; } platform_ota.counter = (platform_ota.size%FRAME_LEN != 0)? (platform_ota.size/FRAME_LEN + 1):(platform_ota.size/FRAME_LEN); @@ -984,10 +991,10 @@ reconnect: { KPrintf("Failed to get ota information!\n"); ret = -1; - ota_info.status = OTA_STATUS_ERROR; - memset(ota_info.error_message,0,sizeof(ota_info.error_message)); - strncpy(ota_info.error_message, "Failed to get ota information!",sizeof(ota_info.error_message)); - UpdateOTAFlag(&ota_info); + p_ota_info->status = OTA_STATUS_ERROR; + memset(p_ota_info->error_message,0,sizeof(p_ota_info->error_message)); + strncpy(p_ota_info->error_message, "Failed to get ota information!",sizeof(p_ota_info->error_message)); + UpdateOTAFlag(p_ota_info); break; } } @@ -1001,10 +1008,10 @@ reconnect: { KPrintf("current frame[%d] flash failed.\n",platform_ota.num-1); ret = -1; - ota_info.status = OTA_STATUS_ERROR; - memset(ota_info.error_message,0,sizeof(ota_info.error_message)); - sprintf(ota_info.error_message,"current frame[%d] flash failed.",platform_ota.num-1); - UpdateOTAFlag(&ota_info); + p_ota_info->status = OTA_STATUS_ERROR; + memset(p_ota_info->error_message,0,sizeof(p_ota_info->error_message)); + sprintf(p_ota_info->error_message,"current frame[%d] flash failed.",platform_ota.num-1); + UpdateOTAFlag(p_ota_info); break; } else @@ -1084,21 +1091,21 @@ reconnect: // 新版本固件接收完毕,写入描述信息 if(0 == ret) { - ota_info.down.size = platform_ota.size; - ota_info.down.crc32 = calculate_crc32(DOWN_FLAH_ADDRESS, platform_ota.size); + p_ota_info->down.size = platform_ota.size; + p_ota_info->down.crc32 = calculate_crc32(DOWN_FLAH_ADDRESS, platform_ota.size); - memset(ota_info.down.version,0,sizeof(ota_info.down.version)); - strncpy(ota_info.down.version, platform_ota.version, sizeof(ota_info.down.version)); + memset(p_ota_info->down.version,0,sizeof(p_ota_info->down.version)); + strncpy(p_ota_info->down.version, platform_ota.version, sizeof(p_ota_info->down.version)); - memset(ota_info.down.description,0,sizeof(ota_info.down.description)); - strncpy(ota_info.down.description, "MQTT OTA bin.",sizeof(ota_info.down.description)); + memset(p_ota_info->down.description,0,sizeof(p_ota_info->down.description)); + strncpy(p_ota_info->down.description, "MQTT OTA bin.",sizeof(p_ota_info->down.description)); - ota_info.status = OTA_STATUS_READY; + p_ota_info->status = OTA_STATUS_READY; - memset(ota_info.error_message,0,sizeof(ota_info.error_message)); - strncpy(ota_info.error_message, "No error message!",sizeof(ota_info.error_message)); + memset(p_ota_info->error_message,0,sizeof(p_ota_info->error_message)); + strncpy(p_ota_info->error_message, "No error message!",sizeof(p_ota_info->error_message)); - UpdateOTAFlag(&ota_info); + UpdateOTAFlag(p_ota_info); KPrintf("firmware file transfer successful,start reboot!\n"); } else From 33523335e2986c8e47309e6bb2050767c0179063 Mon Sep 17 00:00:00 2001 From: songyanguang <345810377@qq.com> Date: Mon, 12 May 2025 16:50:37 +0800 Subject: [PATCH 05/15] Modify app address, for AT cmd --- .../Framework/connection/4g/ec801e/ec801e.c | 15 +++++++++++++-- APP_Framework/Framework/connection/adapter.c | 2 +- .../Framework/connection/adapter_agent.c | 1 + APP_Framework/lib/mqtt/platform_mqtt.c | 2 +- .../XiZi_IIoT/board/ch32v208rbt6/.defconfig_boot | 5 +++++ .../board/ch32v208rbt6/link_application.ld | 2 +- .../board/ch32v208rbt6/link_bootloader.ld | 2 +- .../board/ch32v208rbt6/third_party_driver/Kconfig | 3 +++ .../third_party_driver/include/boot_for_ota.h | 2 +- .../ch32v208rbt6/third_party_driver/lte/Makefile | 4 +++- .../third_party_driver/uart/connect_uart.c | 2 +- 11 files changed, 31 insertions(+), 9 deletions(-) diff --git a/APP_Framework/Framework/connection/4g/ec801e/ec801e.c b/APP_Framework/Framework/connection/4g/ec801e/ec801e.c index afbd895a0..c777d3ce4 100644 --- a/APP_Framework/Framework/connection/4g/ec801e/ec801e.c +++ b/APP_Framework/Framework/connection/4g/ec801e/ec801e.c @@ -200,15 +200,26 @@ static int Ec801eConnect(struct Adapter *adapter, enum NetRoleType net_role, con int try = 0; uint8_t ec801e_cmd[64]; - ADAPTER_DEBUG("%s enter\n", __func__); + printf("%s enter\n", __func__); AtSetReplyEndChar(adapter->agent, 0x4F, 0x4B); /*step1: serial write "+++", quit transparent mode*/ PrivTaskDelay(1500); //before +++ command, wait at least 1s - ATOrderSend(adapter->agent, REPLY_TIME_OUT, NULL, "+++"); + ATOrderSend(adapter->agent, REPLY_TIME_OUT, NULL, EC801E_AT_MODE_CMD); PrivTaskDelay(1500); //after +++ command, wait at least 1s + for(try = 0; try < TRY_TIMES; try++){ + ret = AtCmdConfigAndCheck(adapter->agent, EC801E_ATI_CMD, EC801E_OK_REPLY); + if (ret == 0) { + break; + } + } + if (ret < 0) { + goto out; + } + PrivTaskDelay(300); + /*step2: serial write "AT+CPIN?", check SIM status*/ for(try = 0; try < TRY_TIMES; try++){ ret = AtCmdConfigAndCheck(adapter->agent, EC801E_GET_CPIN_CMD, EC801E_READY_REPLY); diff --git a/APP_Framework/Framework/connection/adapter.c b/APP_Framework/Framework/connection/adapter.c index 8b4d9ad59..c49a5ce5e 100644 --- a/APP_Framework/Framework/connection/adapter.c +++ b/APP_Framework/Framework/connection/adapter.c @@ -407,7 +407,7 @@ int AdapterDeviceConnect(struct Adapter *adapter, enum NetRoleType net_role, con if (NULL == ip_done->connect) return -1; - + printf("AdapterDeviceConnect to connect ip=%s port=%s\n", ip, port); return ip_done->connect(adapter, net_role, ip, port, ip_type); } else { printf("AdapterDeviceConnect net_protocol %d not support\n", adapter->net_protocol); diff --git a/APP_Framework/Framework/connection/adapter_agent.c b/APP_Framework/Framework/connection/adapter_agent.c index 4e2702d15..878137939 100755 --- a/APP_Framework/Framework/connection/adapter_agent.c +++ b/APP_Framework/Framework/connection/adapter_agent.c @@ -589,6 +589,7 @@ static void *ATAgentReceiveProcess(void *param) memset(reply->reply_buffer, 0, reply->reply_max_len); memcpy(reply->reply_buffer, agent->maintain_buffer, agent->maintain_len); reply->reply_len = agent->maintain_len; + printf("%s reply->reply_buffer=%s\n", __func__, reply->reply_buffer); } else { diff --git a/APP_Framework/lib/mqtt/platform_mqtt.c b/APP_Framework/lib/mqtt/platform_mqtt.c index 41fc624c0..7ded64209 100644 --- a/APP_Framework/lib/mqtt/platform_mqtt.c +++ b/APP_Framework/lib/mqtt/platform_mqtt.c @@ -74,8 +74,8 @@ out: if (ret < 0) { AdapterDeviceClose(adapter); + KPrintf("%s fail\n", __func__); } - KPrintf("%s fail\n", __func__); return ret; } diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig_boot b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig_boot index 72bbe113e..da2c92c42 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig_boot +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig_boot @@ -22,6 +22,7 @@ CONFIG_BSP_USING_LTE=y CONFIG_LTE_BUS_NAME="lte" CONFIG_LTE_DRV_NAME="lte_drv" CONFIG_LTE_DEVICE_NAME_1="lte_dev1" +# CONFIG_LTE_TEST is not set # # Hardware feature @@ -101,6 +102,8 @@ CONFIG_KERNEL_CONSOLEBUF_SIZE=128 # Command shell # # CONFIG_TOOL_SHELL is not set +# CONFIG_SHELL_ENTER_CR_AND_LF is not set +# CONFIG_SHELL_ENTER_CRLF is not set # # Kernel data structure Manage @@ -166,6 +169,8 @@ CONFIG_FS_VFS_DEVFS=y CONFIG_TOOL_USING_OTA=y CONFIG_MCUBOOT_BOOTLOADER=y # CONFIG_MCUBOOT_APPLICATION is not set +# CONFIG_OTA_BY_PLATFORM is not set +# CONFIG_OTA_BY_TCPSERVER is not set # # Flash area address and size configuration. diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/link_application.ld b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/link_application.ld index 2a03937ef..8071e4897 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/link_application.ld +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/link_application.ld @@ -27,7 +27,7 @@ MEMORY FLASH-160K + RAM-32K */ /*FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 448K*/ - FLASH (rx) : ORIGIN = 0x0001c000, LENGTH = 364K + FLASH (rx) : ORIGIN = 0x00010000, LENGTH = 412K RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K } diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/link_bootloader.ld b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/link_bootloader.ld index 216f29a3f..9758c9ff8 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/link_bootloader.ld +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/link_bootloader.ld @@ -26,7 +26,7 @@ MEMORY FLASH-144K + RAM-48K FLASH-160K + RAM-32K */ - FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 112K + FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 64K RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K } diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/Kconfig b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/Kconfig index 9d68ab25a..b81a76455 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/Kconfig +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/Kconfig @@ -109,5 +109,8 @@ menuconfig BSP_USING_LTE config LTE_DEVICE_NAME_1 string "lte bus device 1 name" default "lte_dev1" + config LTE_TEST + bool "Enable lte test" + default y endif \ No newline at end of file diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/include/boot_for_ota.h b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/include/boot_for_ota.h index ce846e67a..83724a265 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/include/boot_for_ota.h +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/include/boot_for_ota.h @@ -22,7 +22,7 @@ #define __BOOT_FOR_OTA_H__ #define IMAGE_IAP_START_ADD 0x08000000 -#define IMAGE_IAP_SIZE (112 * 1024) +#define IMAGE_IAP_SIZE (64 * 1024) #define IMAGE_A_START_ADD (IMAGE_IAP_START_ADD + IMAGE_IAP_SIZE) void mcuboot_bord_init(void); diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/lte/Makefile b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/lte/Makefile index 928cf6a4f..1cbdde10e 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/lte/Makefile +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/lte/Makefile @@ -1,5 +1,7 @@ # SRC_FILES := connect_uart.c test_uart.c -SRC_DIR := test +ifeq ($(CONFIG_LTE_TEST),y) + SRC_DIR := test +endif SRC_FILES := connect_lte.c include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/uart/connect_uart.c b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/uart/connect_uart.c index d34c308e6..347782908 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/uart/connect_uart.c +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/uart/connect_uart.c @@ -221,7 +221,7 @@ static int SerialGetChar(struct SerialHardwareDevice *serial_dev) { if (RESET != USART_GetFlagStatus((USART_TypeDef *)serial_cfg->hw_cfg.serial_register_base, USART_FLAG_RXNE)) { ch = USART_ReceiveData((USART_TypeDef *)serial_cfg->hw_cfg.serial_register_base) & 0xff; } -#ifdef BSP_USING_LTE +#ifdef LTE_TEST #define TRANSPARENT_TRANSMISSION_MODE 0 // 数据透传模式 #define COMMAND_LINE_MODE 1 // 命令行模式 /* lte模式下,实现DBG串口和MAIN串口的数据转发 */ From 77ef32cbb950d164e6e761b5a9f4578a07befd82 Mon Sep 17 00:00:00 2001 From: songyanguang <345810377@qq.com> Date: Wed, 14 May 2025 16:11:31 +0800 Subject: [PATCH 06/15] Use different flash functions in the non-zero wait area and the zero wait area. --- .../XiZi_IIoT/board/ch32v208rbt6/.defconfig | 10 +++-- .../board/ch32v208rbt6/.defconfig_app | 7 ++-- .../board/ch32v208rbt6/.defconfig_boot | 9 ++-- .../XiZi_IIoT/board/ch32v208rbt6/board.c | 4 +- .../board/ch32v208rbt6/link_application.ld | 2 +- .../board/ch32v208rbt6/link_bootloader.ld | 3 +- .../third_party_driver/common/ymodem.c | 3 +- .../third_party_driver/include/boot_for_ota.h | 2 +- .../third_party_driver/ota/boot_for_ota.c | 19 ++------- .../third_party_driver/ota/flash_for_ota.c | 41 +++++++++++++++++-- Ubiquitous/XiZi_IIoT/kernel/thread/init.c | 2 + Ubiquitous/XiZi_IIoT/tool/bootloader/Kconfig | 8 ++-- 12 files changed, 72 insertions(+), 38 deletions(-) diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig index 0f73b9a99..fe069bec6 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig @@ -22,6 +22,7 @@ CONFIG_BSP_USING_LTE=y CONFIG_LTE_BUS_NAME="lte" CONFIG_LTE_DRV_NAME="lte_drv" CONFIG_LTE_DEVICE_NAME_1="lte_dev1" +# CONFIG_LTE_TEST is not set # # Hardware feature @@ -193,14 +194,15 @@ CONFIG_TOOL_USING_OTA=y CONFIG_MCUBOOT_APPLICATION=y CONFIG_OTA_BY_PLATFORM=y # CONFIG_OTA_BY_TCPSERVER is not set +# CONFIG_OTA_BY_NONE is not set # # Flash area address and size configuration. # CONFIG_CHIP_FLAH_BASE=0x08000000 -CONFIG_XIUOS_FLAH_ADDRESS=0x0801c000 -CONFIG_BAKUP_FLAH_ADDRESS=0x0801c000 -CONFIG_DOWN_FLAH_ADDRESS=0x0801c000 +CONFIG_XIUOS_FLAH_ADDRESS=0x08030000 +CONFIG_BAKUP_FLAH_ADDRESS=0x08030000 +CONFIG_DOWN_FLAH_ADDRESS=0x08030000 CONFIG_FLAG_FLAH_ADDRESS=0x08077000 CONFIG_APP_FLASH_SIZE=0x00100000 CONFIG_OTA_RX_TIMEOUT=600 @@ -219,7 +221,7 @@ CONFIG_ADD_XIZI_FEATURES=y # CONFIG_ADD_RTTHREAD_FEATURES is not set # CONFIG_SUPPORT_SENSOR_FRAMEWORK is not set CONFIG_SUPPORT_CONNECTION_FRAMEWORK=y -# CONFIG_CONNECTION_FRAMEWORK_DEBUG is not set +CONFIG_CONNECTION_FRAMEWORK_DEBUG=y # CONFIG_CONNECTION_INDUSTRIAL_NETWORK is not set # CONFIG_CONNECTION_INDUSTRIAL_FIELDBUS is not set # CONFIG_CONNECTION_INDUSTRIAL_WLAN is not set diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig_app b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig_app index 0f73b9a99..cf461813a 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig_app +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig_app @@ -22,6 +22,7 @@ CONFIG_BSP_USING_LTE=y CONFIG_LTE_BUS_NAME="lte" CONFIG_LTE_DRV_NAME="lte_drv" CONFIG_LTE_DEVICE_NAME_1="lte_dev1" +# CONFIG_LTE_TEST is not set # # Hardware feature @@ -198,9 +199,9 @@ CONFIG_OTA_BY_PLATFORM=y # Flash area address and size configuration. # CONFIG_CHIP_FLAH_BASE=0x08000000 -CONFIG_XIUOS_FLAH_ADDRESS=0x0801c000 -CONFIG_BAKUP_FLAH_ADDRESS=0x0801c000 -CONFIG_DOWN_FLAH_ADDRESS=0x0801c000 +CONFIG_XIUOS_FLAH_ADDRESS=0x08030000 +CONFIG_BAKUP_FLAH_ADDRESS=0x08030000 +CONFIG_DOWN_FLAH_ADDRESS=0x08030000 CONFIG_FLAG_FLAH_ADDRESS=0x08077000 CONFIG_APP_FLASH_SIZE=0x00100000 CONFIG_OTA_RX_TIMEOUT=600 diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig_boot b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig_boot index da2c92c42..1257f41b5 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig_boot +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig_boot @@ -169,16 +169,17 @@ CONFIG_FS_VFS_DEVFS=y CONFIG_TOOL_USING_OTA=y CONFIG_MCUBOOT_BOOTLOADER=y # CONFIG_MCUBOOT_APPLICATION is not set -# CONFIG_OTA_BY_PLATFORM is not set +CONFIG_OTA_BY_PLATFORM=y # CONFIG_OTA_BY_TCPSERVER is not set +# CONFIG_OTA_BY_NONE is not set # # Flash area address and size configuration. # CONFIG_CHIP_FLAH_BASE=0x08000000 -CONFIG_XIUOS_FLAH_ADDRESS=0x0801c000 -CONFIG_BAKUP_FLAH_ADDRESS=0x0801c000 -CONFIG_DOWN_FLAH_ADDRESS=0x0801c000 +CONFIG_XIUOS_FLAH_ADDRESS=0x08030000 +CONFIG_BAKUP_FLAH_ADDRESS=0x08030000 +CONFIG_DOWN_FLAH_ADDRESS=0x08030000 CONFIG_FLAG_FLAH_ADDRESS=0x08077000 CONFIG_APP_FLASH_SIZE=0x00100000 CONFIG_OTA_RX_TIMEOUT=600 diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/board.c b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/board.c index 4607c0f9d..76bf4c672 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/board.c +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/board.c @@ -72,12 +72,14 @@ void readRomConfiguration(void) { extern pmodule_cfg CFG; // 指向配置信息的指针 /* 从EEPROM中读取网络配置信息 */ - KPrintf("%s PAGE_WRITE_START_ADDR=%08x\n", __func__, PAGE_WRITE_START_ADDR); + KPrintf("%s PAGE_READ_START_ADDR=%08x\n", __func__, PAGE_WRITE_START_ADDR); CFG_READ(PAGE_WRITE_START_ADDR, Configbuf, MODULE_CFG_LEN); /* 如果存储在EEPROM中的网络配置信息无效,或者WCHNET还没有被主机配置过,通过默认配置信息初始化WCHNET */ if ((CFG->cfgFlag[0] != checkcode1) || (CFG->cfgFlag[1] != checkcode2)) { + KPrintf("%s PAGE_ERASE_START_ADDR=%08x\n", __func__, PAGE_WRITE_START_ADDR); CFG_ERASE(PAGE_WRITE_START_ADDR, FLASH_PAGE_SIZE); + KPrintf("%s PAGE_WRITE_START_ADDR=%08x\n", __func__, PAGE_WRITE_START_ADDR); CFG_WRITE(PAGE_WRITE_START_ADDR, (u8 *)&defaultConfiguration, MODULE_CFG_LEN); KPrintf("%s NVIC_SystemReset\n\n", __func__); NVIC_SystemReset(); // 复位ch32v208 diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/link_application.ld b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/link_application.ld index 8071e4897..1360a8058 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/link_application.ld +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/link_application.ld @@ -27,7 +27,7 @@ MEMORY FLASH-160K + RAM-32K */ /*FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 448K*/ - FLASH (rx) : ORIGIN = 0x00010000, LENGTH = 412K + FLASH (rx) : ORIGIN = 0x00030000, LENGTH = 284K RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K } diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/link_bootloader.ld b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/link_bootloader.ld index 9758c9ff8..05872500f 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/link_bootloader.ld +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/link_bootloader.ld @@ -26,7 +26,8 @@ MEMORY FLASH-144K + RAM-48K FLASH-160K + RAM-32K */ - FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 64K + /*FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 64K*/ + FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 192K RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K } diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/common/ymodem.c b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/common/ymodem.c index fed17995b..a5faacc06 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/common/ymodem.c +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/common/ymodem.c @@ -21,6 +21,7 @@ #include "ymodem.h" #include "string.h" #include "flash_for_ota.h" +#include "boot_for_ota.h" uint8_t tab_1024[1024] ={0}; uint8_t FileName[FILE_NAME_LENGTH]; @@ -49,6 +50,6 @@ int32_t Ymodem_Receive(uint8_t *buf, const uint32_t addr) *******************************************************************************/ int32_t SerialDownload(const uint32_t addr) { - int32_t Size = 0; + int32_t Size = IMAGE_IAP_SIZE; return Size; } diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/include/boot_for_ota.h b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/include/boot_for_ota.h index 83724a265..aa4af07f7 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/include/boot_for_ota.h +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/include/boot_for_ota.h @@ -22,7 +22,7 @@ #define __BOOT_FOR_OTA_H__ #define IMAGE_IAP_START_ADD 0x08000000 -#define IMAGE_IAP_SIZE (64 * 1024) +#define IMAGE_IAP_SIZE (192 * 1024) #define IMAGE_A_START_ADD (IMAGE_IAP_START_ADD + IMAGE_IAP_SIZE) void mcuboot_bord_init(void); diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/boot_for_ota.c b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/boot_for_ota.c index 68d229a6e..303be7c37 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/boot_for_ota.c +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/boot_for_ota.c @@ -102,27 +102,14 @@ void mcuboot_bord_init(void) void mcuboot_reset(void) { - /* - __set_FAULTMASK(1); - NVIC_SystemReset();*/ + KPrintf("%s NVIC_SystemReset\n\n", __func__); + NVIC_SystemReset(); } void mcuboot_jump(void) { - KPrintf("boot jumpApp\n\n"); + KPrintf("%s jumpApp\n\n", __func__); jumpApp(); - /* - uint32_t addr = XIUOS_FLAH_ADDRESS; - - SCB->VTOR = addr; - asm volatile("LDR R0, %0" : : "m"(addr)); - asm volatile("LDR R0, [R0]"); - asm volatile("MOV SP, R0"); - - addr += 4; - asm volatile("LDR R0, %0" : : "m"(addr)); - asm volatile("LDR R0, [R0]"); - asm volatile("BX R0");*/ } void mcuboot_delay(uint32_t ms) diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/flash_for_ota.c b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/flash_for_ota.c index 25d69c17a..506108feb 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/flash_for_ota.c +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/flash_for_ota.c @@ -75,11 +75,12 @@ void FLASH_DeInit(void) imageSize:要擦除的字节数 * 返 回 值: 如果函数执行成功,状态值为 kStatus_Success,否则状态值为其他错误码 *******************************************************************************/ +#ifdef MCUBOOT_BOOTLOADER status_t Flash_Erase(uint32_t start_addr, uint32_t imageSize) { uint32_t page_count; uint32_t pageNum = (imageSize%FLASH_PAGE_FAST_SIZE != 0)? (imageSize/FLASH_PAGE_FAST_SIZE + 1):(imageSize/FLASH_PAGE_FAST_SIZE); - + KPrintf("Flash_Erase start_addr=%08x imageSize=0x%x\n", start_addr, imageSize); FLASH_Unlock_Fast(); for(page_count = 0; page_count < pageNum; page_count++) @@ -91,7 +92,25 @@ status_t Flash_Erase(uint32_t start_addr, uint32_t imageSize) return (status_t)kStatus_Success; } +#else +status_t Flash_Erase(uint32_t start_addr, uint32_t imageSize) +{ +/* + uint32_t page_count; + uint32_t pageNum = (imageSize%FLASH_BLOCK_SIZE != 0)? (imageSize/FLASH_BLOCK_SIZE + 1):(imageSize/FLASH_BLOCK_SIZE); + KPrintf("Flash_Erase start_addr=%08x pageNum=0x%x\n", start_addr, imageSize); + FLASH_Unlock(); + for(page_count = 0; page_count < pageNum; page_count++) + { + FLASH_ErasePage(start_addr + (page_count * FLASH_BLOCK_SIZE)); + } + FLASH_Lock(); + KPrintf("Flash_Erase start_addr=%08x success\n", start_addr); +*/ + return (status_t)kStatus_Success; +} +#endif /******************************************************************************* * 函 数 名: Flash_Write * 功能描述: 写入W25QXX在指定地址开始写入指定长度的数据 @@ -101,12 +120,13 @@ status_t Flash_Erase(uint32_t start_addr, uint32_t imageSize) * 返 回 值: 如果函数执行成功,状态值为 kStatus_Success,否则状态值为其他错误码 * 注 释: 该函数带擦除操作 *******************************************************************************/ +#ifdef MCUBOOT_BOOTLOADER status_t Flash_Write(uint32_t WriteAddr, uint8_t *pBuffer, uint32_t NumByteToWrite) { uint32_t page_count; uint32_t pageNum = (NumByteToWrite%FLASH_PAGE_FAST_SIZE != 0)? (NumByteToWrite/FLASH_PAGE_FAST_SIZE + 1):(NumByteToWrite/FLASH_PAGE_FAST_SIZE); - KPrintf("Flash_Write start_addr=%08x pBuffer=%p imageSize=0x%x\n", WriteAddr, pBuffer, NumByteToWrite); + KPrintf("Flash_Write start_addr=%08x pBuffer=%p NumByteToWrite=0x%x\n", WriteAddr, pBuffer, NumByteToWrite); FLASH_Unlock_Fast(); for(page_count = 0; page_count < pageNum; page_count++) { @@ -116,9 +136,24 @@ status_t Flash_Write(uint32_t WriteAddr, uint8_t *pBuffer, uint32_t NumByteToWri KPrintf("Flash_Write start_addr=%08x success\n", WriteAddr); return (status_t)kStatus_Success; - } +#else +status_t Flash_Write(uint32_t WriteAddr, uint8_t *pBuffer, uint32_t NumByteToWrite) +{ + uint32_t addr; + uint32_t *p_buff = (uint32_t *)pBuffer; + KPrintf("Flash_Write start_addr=%08x pBuffer=%p NumByteToWrite=0x%x\n", WriteAddr, pBuffer, NumByteToWrite); + FLASH_Unlock(); + for (addr = WriteAddr; addr < WriteAddr + NumByteToWrite; addr += 4, p_buff++) { + FLASH_ProgramWord(addr, *p_buff); + } + FLASH_Lock(); + KPrintf("Flash_Write start_addr=%08x success\n", WriteAddr); + + return (status_t)kStatus_Success; +} +#endif /******************************************************************************* * 函 数 名: Flash_Read * 功能描述: 读Flash内容 diff --git a/Ubiquitous/XiZi_IIoT/kernel/thread/init.c b/Ubiquitous/XiZi_IIoT/kernel/thread/init.c index 262424430..33769addc 100644 --- a/Ubiquitous/XiZi_IIoT/kernel/thread/init.c +++ b/Ubiquitous/XiZi_IIoT/kernel/thread/init.c @@ -256,8 +256,10 @@ KPrintf("%s %d\n", __func__, __LINE__); #endif KPrintf("%s %d\n", __func__, __LINE__); +#ifdef TOOL_SHELL extern long ShowTask(void); ShowTask(); +#endif StartupOsAssign(); return 0; } diff --git a/Ubiquitous/XiZi_IIoT/tool/bootloader/Kconfig b/Ubiquitous/XiZi_IIoT/tool/bootloader/Kconfig index 98ab6c804..45fe943b6 100644 --- a/Ubiquitous/XiZi_IIoT/tool/bootloader/Kconfig +++ b/Ubiquitous/XiZi_IIoT/tool/bootloader/Kconfig @@ -16,7 +16,7 @@ menu "OTA function" bool "Config as application." endchoice - if MCUBOOT_APPLICATION + #if MCUBOOT_APPLICATION choice prompt "The way of OTA firmware upgrade." default OTA_BY_PLATFORM @@ -29,9 +29,11 @@ menu "OTA function" bool "Through the public network TCP server." select SUPPORT_CONNECTION_FRAMEWORK select CONNECTION_ADAPTER_4G - endchoice - endif + config OTA_BY_NONE + bool "Not download firmware." + endchoice + #endif menu "Flash area address and size configuration." config CHIP_FLAH_BASE From a20a2d532702a9a60ab2bd5c337571fd9583cad6 Mon Sep 17 00:00:00 2001 From: songyanguang <345810377@qq.com> Date: Tue, 3 Jun 2025 11:27:21 +0800 Subject: [PATCH 07/15] Key functions are assigned to FLASH_FAST --- .../XiZi_IIoT/board/ch32v208rbt6/.defconfig | 41 ++++----------- .../board/ch32v208rbt6/link_application.ld | 29 +++++------ .../board/ch32v208rbt6/link_bootloader.ld | 45 +++++++++------- .../third_party_driver/common/ymodem.c | 2 +- .../third_party_driver/include/boot_for_ota.h | 2 +- .../third_party_driver/ota/boot_for_ota.c | 16 +----- .../XiZi_IIoT/tool/bootloader/ota/ota.c | 51 +++++++++++++++++++ .../XiZi_IIoT/tool/bootloader/ota/ota.h | 1 + 8 files changed, 106 insertions(+), 81 deletions(-) diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig index fe069bec6..aeb27bbd0 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig @@ -101,33 +101,10 @@ CONFIG_KERNEL_CONSOLEBUF_SIZE=128 # # Command shell # -CONFIG_TOOL_SHELL=y -CONFIG_SHELL_ENTER_CR=y -CONFIG_SHELL_ENTER_LF=y -CONFIG_SHELL_ENTER_CR_AND_LF=y +# CONFIG_TOOL_SHELL is not set +# CONFIG_SHELL_ENTER_CR_AND_LF is not set # CONFIG_SHELL_ENTER_CRLF is not set -# -# Set shell user control -# -CONFIG_SHELL_DEFAULT_USER="letter" -CONFIG_SHELL_DEFAULT_USER_PASSWORD="" -CONFIG_SHELL_LOCK_TIMEOUT=10000 - -# -# Set shell config param -# -CONFIG_SHELL_TASK_STACK_SIZE=1024 -CONFIG_SHELL_TASK_PRIORITY=20 -CONFIG_SHELL_MAX_NUMBER=5 -CONFIG_SHELL_PARAMETER_MAX_NUMBER=8 -CONFIG_SHELL_HISTORY_MAX_NUMBER=5 -CONFIG_SHELL_PRINT_BUFFER=128 -CONFIG_SHELL_HELP_SHOW_PERMISSION=y -# CONFIG_SHELL_HELP_LIST_USER is not set -CONFIG_SHELL_HELP_LIST_VAR=y -# CONFIG_SHELL_HELP_LIST_KEY is not set - # # Kernel data structure Manage # @@ -190,8 +167,8 @@ CONFIG_FS_VFS_DEVFS=y # OTA function # CONFIG_TOOL_USING_OTA=y -# CONFIG_MCUBOOT_BOOTLOADER is not set -CONFIG_MCUBOOT_APPLICATION=y +CONFIG_MCUBOOT_BOOTLOADER=y +# CONFIG_MCUBOOT_APPLICATION is not set CONFIG_OTA_BY_PLATFORM=y # CONFIG_OTA_BY_TCPSERVER is not set # CONFIG_OTA_BY_NONE is not set @@ -200,9 +177,9 @@ CONFIG_OTA_BY_PLATFORM=y # Flash area address and size configuration. # CONFIG_CHIP_FLAH_BASE=0x08000000 -CONFIG_XIUOS_FLAH_ADDRESS=0x08030000 -CONFIG_BAKUP_FLAH_ADDRESS=0x08030000 -CONFIG_DOWN_FLAH_ADDRESS=0x08030000 +CONFIG_XIUOS_FLAH_ADDRESS=0x08008000 +CONFIG_BAKUP_FLAH_ADDRESS=0x08008000 +CONFIG_DOWN_FLAH_ADDRESS=0x08008000 CONFIG_FLAG_FLAH_ADDRESS=0x08077000 CONFIG_APP_FLASH_SIZE=0x00100000 CONFIG_OTA_RX_TIMEOUT=600 @@ -221,7 +198,7 @@ CONFIG_ADD_XIZI_FEATURES=y # CONFIG_ADD_RTTHREAD_FEATURES is not set # CONFIG_SUPPORT_SENSOR_FRAMEWORK is not set CONFIG_SUPPORT_CONNECTION_FRAMEWORK=y -CONFIG_CONNECTION_FRAMEWORK_DEBUG=y +# CONFIG_CONNECTION_FRAMEWORK_DEBUG is not set # CONFIG_CONNECTION_INDUSTRIAL_NETWORK is not set # CONFIG_CONNECTION_INDUSTRIAL_FIELDBUS is not set # CONFIG_CONNECTION_INDUSTRIAL_WLAN is not set @@ -336,7 +313,7 @@ CONFIG_XIUOS_PLATFORM=y CONFIG_CLIENTID="D001" CONFIG_USERNAME="xiuosiot" CONFIG_PASSWORD="xiuosiot" -CONFIG_PLATFORM_SERVERIP="115.238.53.59" +CONFIG_PLATFORM_SERVERIP="47.115.50.232" CONFIG_PLATFORM_SERVERPORT="1883" # CONFIG_USING_DOWNLOAD_JSON is not set diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/link_application.ld b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/link_application.ld index 1360a8058..18c3c6609 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/link_application.ld +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/link_application.ld @@ -26,8 +26,7 @@ MEMORY FLASH-144K + RAM-48K FLASH-160K + RAM-32K */ - /*FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 448K*/ - FLASH (rx) : ORIGIN = 0x00030000, LENGTH = 284K + FLASH (rx) : ORIGIN = 0x00008000, LENGTH = 288K RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K } @@ -44,19 +43,19 @@ SECTIONS _einit = .; } >FLASH AT>FLASH - .vector : - { - *(.vector); - . = ALIGN(64); - } >FLASH AT>FLASH - - .highcode : - { - . = ALIGN(4); - *(.highcode); - *(.highcode.*); - . = ALIGN(4); - } >FLASH AT>FLASH + .vector : + { + *(.vector); + . = ALIGN(64); + } >FLASH AT>FLASH + + .highcode : + { + . = ALIGN(4); + *(.highcode); + *(.highcode.*); + . = ALIGN(4); + } >FLASH AT>FLASH .text : { diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/link_bootloader.ld b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/link_bootloader.ld index 05872500f..4a61e9995 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/link_bootloader.ld +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/link_bootloader.ld @@ -26,15 +26,14 @@ MEMORY FLASH-144K + RAM-48K FLASH-160K + RAM-32K */ - /*FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 64K*/ - FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 192K + FLASH_FAST (rx) : ORIGIN = 0x00000000, LENGTH = 32K + FLASH (rx) : ORIGIN = 0x00048000, LENGTH = 156K RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K } SECTIONS { - .init : { _sinit = .; @@ -42,22 +41,34 @@ SECTIONS KEEP(*(SORT_NONE(.init))) . = ALIGN(4); _einit = .; - } >FLASH AT>FLASH + } >FLASH_FAST AT>FLASH_FAST - .vector : - { - *(.vector); - . = ALIGN(64); - } >FLASH AT>FLASH - - .highcode : - { - . = ALIGN(4); - *(.highcode); - *(.highcode.*); + .vector : + { + *(.vector); + . = ALIGN(64); + } >FLASH_FAST AT>FLASH_FAST + + .highcode : + { + . = ALIGN(4); + *(.highcode); + *(.highcode.*); . = ALIGN(4); - } >FLASH AT>FLASH - + } >FLASH_FAST AT>FLASH_FAST + + .text.fast : + { + . = ALIGN(4); + *(.text.fast) + *arch/risc-v/ch32v208rbt6*.o(.text) + *board/ch32v208rbt6/third_party_driver/Peripheral/src/ch32v20x_flash.o(.text) + *board/ch32v208rbt6/third_party_driver/Peripheral/src/ch32v20x_usart.o(.text) + *board/ch32v208rbt6/third_party_driver/lte/connect_lte.o(.text) + *kernel/thread*.o(.text) + . = ALIGN(4); + } >FLASH_FAST AT>FLASH_FAST + .text : { . = ALIGN(4); diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/common/ymodem.c b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/common/ymodem.c index a5faacc06..078ba3296 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/common/ymodem.c +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/common/ymodem.c @@ -50,6 +50,6 @@ int32_t Ymodem_Receive(uint8_t *buf, const uint32_t addr) *******************************************************************************/ int32_t SerialDownload(const uint32_t addr) { - int32_t Size = IMAGE_IAP_SIZE; + int32_t Size = 1; //TODO: 208 does not support serial download return Size; } diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/include/boot_for_ota.h b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/include/boot_for_ota.h index aa4af07f7..7b422a082 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/include/boot_for_ota.h +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/include/boot_for_ota.h @@ -22,7 +22,7 @@ #define __BOOT_FOR_OTA_H__ #define IMAGE_IAP_START_ADD 0x08000000 -#define IMAGE_IAP_SIZE (192 * 1024) +#define IMAGE_IAP_SIZE (32 * 1024) #define IMAGE_A_START_ADD (IMAGE_IAP_START_ADD + IMAGE_IAP_SIZE) void mcuboot_bord_init(void); diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/boot_for_ota.c b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/boot_for_ota.c index 303be7c37..54abbf904 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/boot_for_ota.c +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/boot_for_ota.c @@ -65,13 +65,6 @@ static uint32_t _SysTick_Config(uint32_t ticks) { void mcuboot_bord_init(void) { - DISABLE_INTERRUPT(); - /* system irq table must be inited before initialization of Hardware irq */ - SysInitIsrManager(); - -// InitBoardHardware(); -// XiUOSStartup(); - Delay_Init(); USART_Printf_Init(115200); /* System Tick Configuration */ @@ -90,14 +83,7 @@ void mcuboot_bord_init(void) void readRomConfiguration(void); readRomConfiguration(); // 读取配置信息到外部变量CFG中 - KPrintf("mcuboot board initialization......\n"); - - /* - BOARD_ConfigMPU(); - BOARD_InitPins(); - BOARD_BootClockRUN(); - UartConfig(); - SysTick_Config(SystemCoreClock / TICK_PER_SECOND);*/ + KPrintf("mcuboot board init done.\n"); } void mcuboot_reset(void) diff --git a/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.c b/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.c index 2acb19ed3..da0c3846c 100644 --- a/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.c +++ b/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.c @@ -188,6 +188,19 @@ static status_t UpdateOTAFlag(ota_info_t *ptr) return status; } +/******************************************************************************* +* 函 数 名: GetOTAFlagStatus +* 功能描述: 获取OTA Flag区域的Status信息 +* 形 参: +* 返 回 值: +*******************************************************************************/ +static uint32_t GetOTAFlagStatus(void) +{ + ota_info_t ota_info; + memset(&ota_info, 0, sizeof(ota_info_t)); + mcuboot.op_flash_read(FLAG_FLAH_ADDRESS, (void*)&ota_info, sizeof(ota_info_t)); + return ota_info.status; +} /******************************************************************************* * 函 数 名: InitialVersion @@ -899,12 +912,27 @@ static void mqttCloudInteraction(void* parameter) mcuboot.flash_init(); memset(p_ota_info, 0, sizeof(ota_info_t)); mcuboot.op_flash_read(FLAG_FLAH_ADDRESS, (void*)p_ota_info, sizeof(ota_info_t)); +#ifdef MCUBOOT_BOOTLOADER + p_ota_info->status = OTA_STATUS_BOOT_DOWNLOAD; +#else p_ota_info->status = OTA_STATUS_DOWNLOADING; +#endif UpdateOTAFlag(p_ota_info); memset(topicdatabuff,0,sizeof(topicdatabuff)); sprintf(topicdatabuff[0],"ota/%s/update",CLIENTID); sprintf(topicdatabuff[1],"ota/%s/files",CLIENTID); +#if 1 //debug + if((AdapterNetActive() == 0) ) + { + KPrintf("mqttCloudInteraction write OTA flag and reboot\n"); + p_ota_info->status = OTA_STATUS_BOOT_DOWNLOAD; + UpdateOTAFlag(p_ota_info); + MdelayKTask(2000); + mcuboot.op_reset(); + } +#endif + reconnect: if((AdapterNetActive() == 0) && MQTT_Connect() && MQTT_SubscribeTopic(topicdatabuff[0]) && MQTT_SubscribeTopic(topicdatabuff[1])) { @@ -1408,6 +1436,11 @@ void ota_entry(void) uint32_t ret; uint32_t timeout = 1000; + if(XIUOS_FLAH_ADDRESS == DOWN_FLAH_ADDRESS) { + DISABLE_INTERRUPT(); + SysInitIsrManager(); + } + mcuboot.board_init(); mcuboot.print_string("Please press 'space' key into menu in 5s !!!\r\n"); @@ -1453,6 +1486,24 @@ void ota_entry(void) //10s内不按下空格键默然进行升级,升级完成后跳转 else { + if(XIUOS_FLAH_ADDRESS == DOWN_FLAH_ADDRESS) + { + if(OTA_STATUS_BOOT_DOWNLOAD == GetOTAFlagStatus()) + { +#ifdef BSP_USING_LTE + mcuboot.print_string("ota_entry to InitHwLte\r\n"); + extern int InitHwLte(void); + InitHwLte(); +#endif + mcuboot.print_string("ota_entry to XiUOSStartup\r\n"); + extern int XiUOSStartup(void); + XiUOSStartup(); + } + else + { + BootLoaderJumpApp(); + } + } Update(); BootLoaderJumpApp(); } diff --git a/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.h b/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.h index dceb32266..4f8e13ec8 100644 --- a/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.h +++ b/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.h @@ -34,6 +34,7 @@ typedef enum { OTA_STATUS_DOWNLOADED, //固件下载完成 OTA_STATUS_UPDATING, //正在进行OTA升级 OTA_STATUS_BACKUP, //正在版本回退 + OTA_STATUS_BOOT_DOWNLOAD,//boot阶段下载固件 OTA_STATUS_ERROR, //出现错误,升级失败 } ota_status_t; From 1703db93cbb9561522a572f6ebddd06d47d8bb7b Mon Sep 17 00:00:00 2001 From: songyanguang <345810377@qq.com> Date: Sun, 8 Jun 2025 19:42:00 -0700 Subject: [PATCH 08/15] Modify the order for serial configure and semaphore --- APP_Framework/lib/mqtt/platform_mqtt.c | 5 ++- .../XiZi_IIoT/board/ch32v208rbt6/.defconfig | 8 ++-- .../board/ch32v208rbt6/link_bootloader.ld | 2 +- .../XiZi_IIoT/resources/serial/dev_serial.c | 42 +++++++++---------- .../XiZi_IIoT/tool/bootloader/ota/ota.c | 35 +++++++++------- 5 files changed, 50 insertions(+), 42 deletions(-) diff --git a/APP_Framework/lib/mqtt/platform_mqtt.c b/APP_Framework/lib/mqtt/platform_mqtt.c index 7ded64209..c3fcfcbf5 100644 --- a/APP_Framework/lib/mqtt/platform_mqtt.c +++ b/APP_Framework/lib/mqtt/platform_mqtt.c @@ -117,6 +117,7 @@ bool MQTT_Connect(void) uint8_t TryConnect_time = 10; //尝试登录次数 KPrintf("%s enter\n", __func__); + memset(&Platform_mqtt,0,sizeof(Platform_mqtt)); #ifdef XIUOS_PLATFORM sprintf(Platform_mqtt.ClientID,"%s",CLIENTID); //客户端ID存入缓冲区 @@ -183,7 +184,7 @@ bool MQTT_Connect(void) MQTT_Send(Platform_mqtt.Pack_buff,Platform_mqtt.Fixed_len + Platform_mqtt.Variable_len + Platform_mqtt.Payload_len); MdelayKTask(50); MQTT_Recv(mqtt_rxbuf, 4); - if(mqtt_rxbuf[0] == parket_connetAck[0] && mqtt_rxbuf[1] == parket_connetAck[1]) //连接成功 + if(mqtt_rxbuf[0] == parket_connetAck[0] && mqtt_rxbuf[1] == parket_connetAck[1] && mqtt_rxbuf[2] == parket_connetAck[2] && mqtt_rxbuf[3] == parket_connetAck[3]) //连接成功 { return true; } @@ -215,6 +216,8 @@ bool MQTT_SubscribeTopic(uint8_t *topic_name) { uint8_t TrySub_time = 10; //尝试订阅次数 + KPrintf("%s topic_name=%s\n", __func__, topic_name); + Platform_mqtt.Fixed_len = 1; //SUBSCRIBE报文,固定报头长度暂定为1 Platform_mqtt.Variable_len = 2;//SUBSCRIBE报文,可变报头长度=2,2为字节报文标识符 Platform_mqtt.Payload_len = 0; //SUBSCRIBE报文,负载数据长度暂定为0 diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig index aeb27bbd0..bdb14bc55 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig @@ -102,8 +102,6 @@ CONFIG_KERNEL_CONSOLEBUF_SIZE=128 # Command shell # # CONFIG_TOOL_SHELL is not set -# CONFIG_SHELL_ENTER_CR_AND_LF is not set -# CONFIG_SHELL_ENTER_CRLF is not set # # Kernel data structure Manage @@ -167,8 +165,8 @@ CONFIG_FS_VFS_DEVFS=y # OTA function # CONFIG_TOOL_USING_OTA=y -CONFIG_MCUBOOT_BOOTLOADER=y -# CONFIG_MCUBOOT_APPLICATION is not set +# CONFIG_MCUBOOT_BOOTLOADER is not set +CONFIG_MCUBOOT_APPLICATION=y CONFIG_OTA_BY_PLATFORM=y # CONFIG_OTA_BY_TCPSERVER is not set # CONFIG_OTA_BY_NONE is not set @@ -311,7 +309,7 @@ CONFIG_XIUOS_PLATFORM=y # xiuos platform mqtt connection parameter configuration. # CONFIG_CLIENTID="D001" -CONFIG_USERNAME="xiuosiot" +CONFIG_USERNAME="ch32v208" CONFIG_PASSWORD="xiuosiot" CONFIG_PLATFORM_SERVERIP="47.115.50.232" CONFIG_PLATFORM_SERVERPORT="1883" diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/link_bootloader.ld b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/link_bootloader.ld index 4a61e9995..023a03265 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/link_bootloader.ld +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/link_bootloader.ld @@ -27,7 +27,7 @@ MEMORY FLASH-160K + RAM-32K */ FLASH_FAST (rx) : ORIGIN = 0x00000000, LENGTH = 32K - FLASH (rx) : ORIGIN = 0x00048000, LENGTH = 156K + FLASH (rx) : ORIGIN = 0x00050000, LENGTH = 156K RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K } diff --git a/Ubiquitous/XiZi_IIoT/resources/serial/dev_serial.c b/Ubiquitous/XiZi_IIoT/resources/serial/dev_serial.c index c1f52b96e..d6cacaaf8 100644 --- a/Ubiquitous/XiZi_IIoT/resources/serial/dev_serial.c +++ b/Ubiquitous/XiZi_IIoT/resources/serial/dev_serial.c @@ -444,6 +444,27 @@ static uint32 SerialDevOpen(void *dev) return ERROR; } + serial_dev->haldev.dev_sem = KSemaphoreCreate(0); + if (serial_dev->haldev.dev_sem < 0) + { + KPrintf("SerialDevOpen create sem failed .\n"); + + if (serial_dev->serial_fifo.serial_rx->serial_rx_buffer) + { + x_free(serial_dev->serial_fifo.serial_rx->serial_rx_buffer); + } + if (serial_dev->serial_fifo.serial_rx) + { + x_free(serial_dev->serial_fifo.serial_rx); + } + if (serial_dev->serial_fifo.serial_tx) + { + x_free(serial_dev->serial_fifo.serial_tx); + } + + return ERROR; + } + if (NONE == serial_dev->serial_fifo.serial_rx) { if (SIGN_OPER_INT_RX & serial_dev_param->serial_set_mode) @@ -596,27 +617,6 @@ static uint32 SerialDevOpen(void *dev) #endif } - serial_dev->haldev.dev_sem = KSemaphoreCreate(0); - if (serial_dev->haldev.dev_sem < 0) - { - KPrintf("SerialDevOpen create sem failed .\n"); - - if (serial_dev->serial_fifo.serial_rx->serial_rx_buffer) - { - x_free(serial_dev->serial_fifo.serial_rx->serial_rx_buffer); - } - if (serial_dev->serial_fifo.serial_rx) - { - x_free(serial_dev->serial_fifo.serial_rx); - } - if (serial_dev->serial_fifo.serial_tx) - { - x_free(serial_dev->serial_fifo.serial_tx); - } - - return ERROR; - } - return EOK; } diff --git a/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.c b/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.c index da0c3846c..827134bf3 100644 --- a/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.c +++ b/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.c @@ -450,6 +450,12 @@ static void Update(void) /*进行新版本的升级*/ else { + if(XIUOS_FLAH_ADDRESS == DOWN_FLAH_ADDRESS) + { + mcuboot.flash_deinit(); + return; + } + if(UpdateNewApplication() == true) /*如果实际发生了flash搬移,操作完成后再重启一次*/ { mcuboot.flash_deinit(); @@ -912,9 +918,7 @@ static void mqttCloudInteraction(void* parameter) mcuboot.flash_init(); memset(p_ota_info, 0, sizeof(ota_info_t)); mcuboot.op_flash_read(FLAG_FLAH_ADDRESS, (void*)p_ota_info, sizeof(ota_info_t)); -#ifdef MCUBOOT_BOOTLOADER - p_ota_info->status = OTA_STATUS_BOOT_DOWNLOAD; -#else +#ifndef MCUBOOT_BOOTLOADER p_ota_info->status = OTA_STATUS_DOWNLOADING; #endif UpdateOTAFlag(p_ota_info); @@ -922,17 +926,6 @@ static void mqttCloudInteraction(void* parameter) sprintf(topicdatabuff[0],"ota/%s/update",CLIENTID); sprintf(topicdatabuff[1],"ota/%s/files",CLIENTID); -#if 1 //debug - if((AdapterNetActive() == 0) ) - { - KPrintf("mqttCloudInteraction write OTA flag and reboot\n"); - p_ota_info->status = OTA_STATUS_BOOT_DOWNLOAD; - UpdateOTAFlag(p_ota_info); - MdelayKTask(2000); - mcuboot.op_reset(); - } -#endif - reconnect: if((AdapterNetActive() == 0) && MQTT_Connect() && MQTT_SubscribeTopic(topicdatabuff[0]) && MQTT_SubscribeTopic(topicdatabuff[1])) { @@ -988,6 +981,19 @@ reconnect: if(sscanf(ptr2,"{\"fileSize\":%d,\"version\":\"%11s\",\"fileId\":%d,\"md5\"",&platform_ota.size,platform_ota.version,&platform_ota.streamId)==3) { KPrintf("OTA firmware information:file size is %d,file id is %d,file version is %s!\r\n",platform_ota.size,platform_ota.streamId,platform_ota.version); +#ifndef MCUBOOT_BOOTLOADER + if(XIUOS_FLAH_ADDRESS == DOWN_FLAH_ADDRESS) + { + KPrintf("mqttCloudInteraction write OTA flag and reboot\n"); + p_ota_info->status = OTA_STATUS_BOOT_DOWNLOAD; + UpdateOTAFlag(p_ota_info); + MQTT_Disconnect(); + mcuboot.flash_deinit(); + MdelayKTask(2000); + mcuboot.op_reset(); + } +#endif + KPrintf("------Start the firmware file transfer!------\r\n"); KPrintf("---------------------------------------------\r\n"); if(platform_ota.size > APP_FLASH_SIZE) @@ -1501,6 +1507,7 @@ void ota_entry(void) } else { + Update(); BootLoaderJumpApp(); } } From 2c647495af54842bdffae3c8a59cb41019b6c681 Mon Sep 17 00:00:00 2001 From: songyanguang <345810377@qq.com> Date: Tue, 17 Jun 2025 17:10:46 +0800 Subject: [PATCH 09/15] Modify ota boot config --- .../Framework/connection/adapter_agent.c | 1 - .../XiZi_IIoT/board/ch32v208rbt6/.defconfig | 8 ++-- .../board/ch32v208rbt6/.defconfig_app | 13 +++--- .../board/ch32v208rbt6/.defconfig_boot | 16 ++++---- .../board/ch32v208rbt6/link_bootloader.ld | 1 + .../third_party_driver/ota/flash_for_ota.c | 40 ------------------- .../XiZi_IIoT/tool/bootloader/ota/ota.c | 2 +- 7 files changed, 20 insertions(+), 61 deletions(-) diff --git a/APP_Framework/Framework/connection/adapter_agent.c b/APP_Framework/Framework/connection/adapter_agent.c index 878137939..4e2702d15 100755 --- a/APP_Framework/Framework/connection/adapter_agent.c +++ b/APP_Framework/Framework/connection/adapter_agent.c @@ -589,7 +589,6 @@ static void *ATAgentReceiveProcess(void *param) memset(reply->reply_buffer, 0, reply->reply_max_len); memcpy(reply->reply_buffer, agent->maintain_buffer, agent->maintain_len); reply->reply_len = agent->maintain_len; - printf("%s reply->reply_buffer=%s\n", __func__, reply->reply_buffer); } else { diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig index bdb14bc55..06a963ac8 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig @@ -29,7 +29,7 @@ CONFIG_LTE_DEVICE_NAME_1="lte_dev1" # CONFIG_RESOURCES_SERIAL=y CONFIG_SERIAL_USING_DMA=y -CONFIG_SERIAL_RB_BUFSZ=128 +CONFIG_SERIAL_RB_BUFSZ=2048 # # Kernel feature @@ -165,8 +165,8 @@ CONFIG_FS_VFS_DEVFS=y # OTA function # CONFIG_TOOL_USING_OTA=y -# CONFIG_MCUBOOT_BOOTLOADER is not set -CONFIG_MCUBOOT_APPLICATION=y +CONFIG_MCUBOOT_BOOTLOADER=y +# CONFIG_MCUBOOT_APPLICATION is not set CONFIG_OTA_BY_PLATFORM=y # CONFIG_OTA_BY_TCPSERVER is not set # CONFIG_OTA_BY_NONE is not set @@ -181,7 +181,7 @@ CONFIG_DOWN_FLAH_ADDRESS=0x08008000 CONFIG_FLAG_FLAH_ADDRESS=0x08077000 CONFIG_APP_FLASH_SIZE=0x00100000 CONFIG_OTA_RX_TIMEOUT=600 -CONFIG_OTA_FRAME_SIZE=2048 +CONFIG_OTA_FRAME_SIZE=1024 # # APP_Framework diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig_app b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig_app index cf461813a..d14fce06d 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig_app +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig_app @@ -194,18 +194,19 @@ CONFIG_TOOL_USING_OTA=y CONFIG_MCUBOOT_APPLICATION=y CONFIG_OTA_BY_PLATFORM=y # CONFIG_OTA_BY_TCPSERVER is not set +# CONFIG_OTA_BY_NONE is not set # # Flash area address and size configuration. # CONFIG_CHIP_FLAH_BASE=0x08000000 -CONFIG_XIUOS_FLAH_ADDRESS=0x08030000 -CONFIG_BAKUP_FLAH_ADDRESS=0x08030000 -CONFIG_DOWN_FLAH_ADDRESS=0x08030000 +CONFIG_XIUOS_FLAH_ADDRESS=0x08008000 +CONFIG_BAKUP_FLAH_ADDRESS=0x08008000 +CONFIG_DOWN_FLAH_ADDRESS=0x08008000 CONFIG_FLAG_FLAH_ADDRESS=0x08077000 CONFIG_APP_FLASH_SIZE=0x00100000 CONFIG_OTA_RX_TIMEOUT=600 -CONFIG_OTA_FRAME_SIZE=2048 +CONFIG_OTA_FRAME_SIZE=1024 # # APP_Framework @@ -333,9 +334,9 @@ CONFIG_XIUOS_PLATFORM=y # xiuos platform mqtt connection parameter configuration. # CONFIG_CLIENTID="D001" -CONFIG_USERNAME="xiuosiot" +CONFIG_USERNAME="ch32v208" CONFIG_PASSWORD="xiuosiot" -CONFIG_PLATFORM_SERVERIP="115.238.53.59" +CONFIG_PLATFORM_SERVERIP="47.115.50.232" CONFIG_PLATFORM_SERVERPORT="1883" # CONFIG_USING_DOWNLOAD_JSON is not set diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig_boot b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig_boot index 1257f41b5..06a963ac8 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig_boot +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig_boot @@ -29,7 +29,7 @@ CONFIG_LTE_DEVICE_NAME_1="lte_dev1" # CONFIG_RESOURCES_SERIAL=y CONFIG_SERIAL_USING_DMA=y -CONFIG_SERIAL_RB_BUFSZ=128 +CONFIG_SERIAL_RB_BUFSZ=2048 # # Kernel feature @@ -102,8 +102,6 @@ CONFIG_KERNEL_CONSOLEBUF_SIZE=128 # Command shell # # CONFIG_TOOL_SHELL is not set -# CONFIG_SHELL_ENTER_CR_AND_LF is not set -# CONFIG_SHELL_ENTER_CRLF is not set # # Kernel data structure Manage @@ -177,13 +175,13 @@ CONFIG_OTA_BY_PLATFORM=y # Flash area address and size configuration. # CONFIG_CHIP_FLAH_BASE=0x08000000 -CONFIG_XIUOS_FLAH_ADDRESS=0x08030000 -CONFIG_BAKUP_FLAH_ADDRESS=0x08030000 -CONFIG_DOWN_FLAH_ADDRESS=0x08030000 +CONFIG_XIUOS_FLAH_ADDRESS=0x08008000 +CONFIG_BAKUP_FLAH_ADDRESS=0x08008000 +CONFIG_DOWN_FLAH_ADDRESS=0x08008000 CONFIG_FLAG_FLAH_ADDRESS=0x08077000 CONFIG_APP_FLASH_SIZE=0x00100000 CONFIG_OTA_RX_TIMEOUT=600 -CONFIG_OTA_FRAME_SIZE=2048 +CONFIG_OTA_FRAME_SIZE=1024 # # APP_Framework @@ -311,9 +309,9 @@ CONFIG_XIUOS_PLATFORM=y # xiuos platform mqtt connection parameter configuration. # CONFIG_CLIENTID="D001" -CONFIG_USERNAME="xiuosiot" +CONFIG_USERNAME="ch32v208" CONFIG_PASSWORD="xiuosiot" -CONFIG_PLATFORM_SERVERIP="115.238.53.59" +CONFIG_PLATFORM_SERVERIP="47.115.50.232" CONFIG_PLATFORM_SERVERPORT="1883" # CONFIG_USING_DOWNLOAD_JSON is not set diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/link_bootloader.ld b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/link_bootloader.ld index 023a03265..92faae8e4 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/link_bootloader.ld +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/link_bootloader.ld @@ -66,6 +66,7 @@ SECTIONS *board/ch32v208rbt6/third_party_driver/Peripheral/src/ch32v20x_usart.o(.text) *board/ch32v208rbt6/third_party_driver/lte/connect_lte.o(.text) *kernel/thread*.o(.text) + *resources/serial*.o(.text) . = ALIGN(4); } >FLASH_FAST AT>FLASH_FAST diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/flash_for_ota.c b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/flash_for_ota.c index 506108feb..e2a3d4501 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/flash_for_ota.c +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/flash_for_ota.c @@ -75,42 +75,21 @@ void FLASH_DeInit(void) imageSize:要擦除的字节数 * 返 回 值: 如果函数执行成功,状态值为 kStatus_Success,否则状态值为其他错误码 *******************************************************************************/ -#ifdef MCUBOOT_BOOTLOADER status_t Flash_Erase(uint32_t start_addr, uint32_t imageSize) { uint32_t page_count; uint32_t pageNum = (imageSize%FLASH_PAGE_FAST_SIZE != 0)? (imageSize/FLASH_PAGE_FAST_SIZE + 1):(imageSize/FLASH_PAGE_FAST_SIZE); - KPrintf("Flash_Erase start_addr=%08x imageSize=0x%x\n", start_addr, imageSize); FLASH_Unlock_Fast(); for(page_count = 0; page_count < pageNum; page_count++) { FLASH_ErasePage_Fast(start_addr + (page_count * FLASH_PAGE_FAST_SIZE)); } FLASH_Lock_Fast(); - KPrintf("Flash_Erase start_addr=%08x success\n", start_addr); return (status_t)kStatus_Success; } -#else -status_t Flash_Erase(uint32_t start_addr, uint32_t imageSize) -{ -/* - uint32_t page_count; - uint32_t pageNum = (imageSize%FLASH_BLOCK_SIZE != 0)? (imageSize/FLASH_BLOCK_SIZE + 1):(imageSize/FLASH_BLOCK_SIZE); - KPrintf("Flash_Erase start_addr=%08x pageNum=0x%x\n", start_addr, imageSize); - FLASH_Unlock(); - for(page_count = 0; page_count < pageNum; page_count++) - { - FLASH_ErasePage(start_addr + (page_count * FLASH_BLOCK_SIZE)); - } - FLASH_Lock(); - KPrintf("Flash_Erase start_addr=%08x success\n", start_addr); -*/ - return (status_t)kStatus_Success; -} -#endif /******************************************************************************* * 函 数 名: Flash_Write * 功能描述: 写入W25QXX在指定地址开始写入指定长度的数据 @@ -120,40 +99,21 @@ status_t Flash_Erase(uint32_t start_addr, uint32_t imageSize) * 返 回 值: 如果函数执行成功,状态值为 kStatus_Success,否则状态值为其他错误码 * 注 释: 该函数带擦除操作 *******************************************************************************/ -#ifdef MCUBOOT_BOOTLOADER status_t Flash_Write(uint32_t WriteAddr, uint8_t *pBuffer, uint32_t NumByteToWrite) { uint32_t page_count; uint32_t pageNum = (NumByteToWrite%FLASH_PAGE_FAST_SIZE != 0)? (NumByteToWrite/FLASH_PAGE_FAST_SIZE + 1):(NumByteToWrite/FLASH_PAGE_FAST_SIZE); - KPrintf("Flash_Write start_addr=%08x pBuffer=%p NumByteToWrite=0x%x\n", WriteAddr, pBuffer, NumByteToWrite); FLASH_Unlock_Fast(); for(page_count = 0; page_count < pageNum; page_count++) { FLASH_ProgramPage_Fast(WriteAddr + (page_count * FLASH_PAGE_FAST_SIZE), (uint32_t *)&pBuffer[page_count * FLASH_PAGE_FAST_SIZE]); } FLASH_Lock_Fast(); - KPrintf("Flash_Write start_addr=%08x success\n", WriteAddr); return (status_t)kStatus_Success; } -#else -status_t Flash_Write(uint32_t WriteAddr, uint8_t *pBuffer, uint32_t NumByteToWrite) -{ - uint32_t addr; - uint32_t *p_buff = (uint32_t *)pBuffer; - KPrintf("Flash_Write start_addr=%08x pBuffer=%p NumByteToWrite=0x%x\n", WriteAddr, pBuffer, NumByteToWrite); - FLASH_Unlock(); - for (addr = WriteAddr; addr < WriteAddr + NumByteToWrite; addr += 4, p_buff++) { - FLASH_ProgramWord(addr, *p_buff); - } - FLASH_Lock(); - KPrintf("Flash_Write start_addr=%08x success\n", WriteAddr); - - return (status_t)kStatus_Success; -} -#endif /******************************************************************************* * 函 数 名: Flash_Read * 功能描述: 读Flash内容 diff --git a/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.c b/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.c index 827134bf3..f69ddea61 100644 --- a/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.c +++ b/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.c @@ -970,6 +970,7 @@ reconnect: } else if(MqttRxbuf[0] == 0x30) { + KPrintf("recv datalen %d \n", datalen); freecnt = 0; payloadLen = MQTT_DealPublishData(MqttRxbuf, datalen); @@ -989,7 +990,6 @@ reconnect: UpdateOTAFlag(p_ota_info); MQTT_Disconnect(); mcuboot.flash_deinit(); - MdelayKTask(2000); mcuboot.op_reset(); } #endif From 4eb5f245cbb09b088a6e729af9834a0b26778c72 Mon Sep 17 00:00:00 2001 From: songyanguang <345810377@qq.com> Date: Wed, 18 Jun 2025 11:21:23 +0800 Subject: [PATCH 10/15] Modify the PWEKEY and RESET_N pins of EC801E --- APP_Framework/Framework/connection/adapter_agent.c | 2 +- Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/board.c | 3 ++- .../ch32v208rbt6/third_party_driver/lte/connect_lte.c | 9 ++++++++- Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.c | 6 +++--- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/APP_Framework/Framework/connection/adapter_agent.c b/APP_Framework/Framework/connection/adapter_agent.c index 4e2702d15..421fcb1fb 100755 --- a/APP_Framework/Framework/connection/adapter_agent.c +++ b/APP_Framework/Framework/connection/adapter_agent.c @@ -232,7 +232,7 @@ int AtCmdConfigAndCheck(ATAgentType agent, char *cmd, char *check) #endif if (!strstr(result, check)) { - printf("%s %d check[%s] reply[%s] failed.\n", __func__, __LINE__, check, result); + printf("%s %d cmd[%s] check[%s] reply[%s] failed.\n", __func__, __LINE__, cmd, check, result); ret = -1; goto __exit; } diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/board.c b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/board.c index 76bf4c672..bf1eeb2c2 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/board.c +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/board.c @@ -215,7 +215,8 @@ void InitBoardHardware() { #ifdef BSP_USING_UART InitHwUart(); InstallConsole("uart1", SERIAL_DRV_NAME_1, SERIAL_1_DEVICE_NAME_0); - KPrintf("console init completed.\n"); + KPrintf("\nconsole init completed.\n"); + KPrintf("compiled on: %s at %s\n", __DATE__, __TIME__); #endif readRomConfiguration(); // 读取配置信息到外部变量CFG中 diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/lte/connect_lte.c b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/lte/connect_lte.c index 43aa0822a..d158dda6f 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/lte/connect_lte.c +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/lte/connect_lte.c @@ -315,12 +315,19 @@ int InitHwLte(void) { USART_Cmd(USART2, ENABLE); /* Enable module pin */ + GPIO_InitStructure_Lte.GPIO_Pin = GPIO_Pin_7; + GPIO_InitStructure_Lte.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStructure_Lte.GPIO_Mode = GPIO_Mode_Out_PP; + GPIO_Init(GPIOA, &GPIO_InitStructure_Lte); + GPIO_SetBits(GPIOA, GPIO_Pin_7); + Delay_Ms(500); // >= 300ms + GPIO_ResetBits(GPIOA, GPIO_Pin_7); GPIO_InitStructure_Lte.GPIO_Pin = GPIO_Pin_6; GPIO_InitStructure_Lte.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure_Lte.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOA, &GPIO_InitStructure_Lte); GPIO_SetBits(GPIOA, GPIO_Pin_6); - Delay_Ms(2000); + Delay_Ms(1000); // >= 500ms GPIO_ResetBits(GPIOA, GPIO_Pin_6); return ret; diff --git a/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.c b/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.c index f69ddea61..d819c1351 100644 --- a/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.c +++ b/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.c @@ -993,9 +993,6 @@ reconnect: mcuboot.op_reset(); } #endif - - KPrintf("------Start the firmware file transfer!------\r\n"); - KPrintf("---------------------------------------------\r\n"); if(platform_ota.size > APP_FLASH_SIZE) { KPrintf("File size is larger than partition size,the partition size is %dk.\n",APP_FLASH_SIZE/1024); @@ -1006,6 +1003,7 @@ reconnect: UpdateOTAFlag(p_ota_info); break; } + KPrintf("Start erase download partition\n"); if(mcuboot.op_flash_erase(DOWN_FLAH_ADDRESS,platform_ota.size) != kStatus_Success) { KPrintf("Failed to erase download partition!\n"); @@ -1016,6 +1014,8 @@ reconnect: UpdateOTAFlag(p_ota_info); break; } + KPrintf("------Start the firmware file transfer!------\r\n"); + KPrintf("---------------------------------------------\r\n"); platform_ota.counter = (platform_ota.size%FRAME_LEN != 0)? (platform_ota.size/FRAME_LEN + 1):(platform_ota.size/FRAME_LEN); platform_ota.num = 1; //下载次数,初始值为1 platform_ota.downlen = FRAME_LEN; //记录本次下载量 From fc82573bbeb04fa7568a4f5052b489ceb7f59820 Mon Sep 17 00:00:00 2001 From: songyanguang <345810377@qq.com> Date: Wed, 18 Jun 2025 16:04:09 +0800 Subject: [PATCH 11/15] Modify ota version and jump flag --- .../XiZi_IIoT/board/ch32v208rbt6/.defconfig | 2 +- .../board/ch32v208rbt6/.defconfig_app | 6 +-- .../board/ch32v208rbt6/.defconfig_boot | 2 +- .../XiZi_IIoT/board/ch32v208rbt6/board.c | 5 +++ .../XiZi_IIoT/tool/bootloader/ota/ota.c | 42 +++++++++++++------ 5 files changed, 39 insertions(+), 18 deletions(-) diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig index 06a963ac8..9f90f6201 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig @@ -181,7 +181,7 @@ CONFIG_DOWN_FLAH_ADDRESS=0x08008000 CONFIG_FLAG_FLAH_ADDRESS=0x08077000 CONFIG_APP_FLASH_SIZE=0x00100000 CONFIG_OTA_RX_TIMEOUT=600 -CONFIG_OTA_FRAME_SIZE=1024 +CONFIG_OTA_FRAME_SIZE=2048 # # APP_Framework diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig_app b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig_app index d14fce06d..49ba76687 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig_app +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig_app @@ -29,7 +29,7 @@ CONFIG_LTE_DEVICE_NAME_1="lte_dev1" # CONFIG_RESOURCES_SERIAL=y CONFIG_SERIAL_USING_DMA=y -CONFIG_SERIAL_RB_BUFSZ=128 +CONFIG_SERIAL_RB_BUFSZ=2048 # # Kernel feature @@ -117,7 +117,7 @@ CONFIG_SHELL_LOCK_TIMEOUT=10000 # # Set shell config param # -CONFIG_SHELL_TASK_STACK_SIZE=1024 +CONFIG_SHELL_TASK_STACK_SIZE=4096 CONFIG_SHELL_TASK_PRIORITY=20 CONFIG_SHELL_MAX_NUMBER=5 CONFIG_SHELL_PARAMETER_MAX_NUMBER=8 @@ -206,7 +206,7 @@ CONFIG_DOWN_FLAH_ADDRESS=0x08008000 CONFIG_FLAG_FLAH_ADDRESS=0x08077000 CONFIG_APP_FLASH_SIZE=0x00100000 CONFIG_OTA_RX_TIMEOUT=600 -CONFIG_OTA_FRAME_SIZE=1024 +CONFIG_OTA_FRAME_SIZE=2048 # # APP_Framework diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig_boot b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig_boot index 06a963ac8..9f90f6201 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig_boot +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/.defconfig_boot @@ -181,7 +181,7 @@ CONFIG_DOWN_FLAH_ADDRESS=0x08008000 CONFIG_FLAG_FLAH_ADDRESS=0x08077000 CONFIG_APP_FLASH_SIZE=0x00100000 CONFIG_OTA_RX_TIMEOUT=600 -CONFIG_OTA_FRAME_SIZE=1024 +CONFIG_OTA_FRAME_SIZE=2048 # # APP_Framework diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/board.c b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/board.c index bf1eeb2c2..dc69f4824 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/board.c +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/board.c @@ -250,4 +250,9 @@ void InitBoardHardware() { (x_ubase)MEMORY_END_ADDRESS, SRAM_SIZE, __stack_size); KPrintf("board init done.\n"); KPrintf("start kernel...\n"); + +#ifdef TOOL_USING_OTA + extern void app_clear_jumpflag(void); + app_clear_jumpflag(); // set lastjumpflag to JUMP_SUCCESS_FLAG +#endif } diff --git a/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.c b/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.c index d819c1351..8175599ce 100644 --- a/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.c +++ b/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.c @@ -487,12 +487,15 @@ static void BootLoaderJumpApp(void) if(p_ota_info->lastjumpflag == JUMP_FAILED_FLAG) { mcuboot.print_string("\r\n------Jump to app partition failed,start version rollback!------\r\n"); -#ifdef BOARD_CH32V208RBT6 - p_ota_info->lastjumpflag = JUMP_SUCCESS_FLAG; - UpdateOTAFlag(p_ota_info); -#else - BackupVersion(); -#endif + if(XIUOS_FLAH_ADDRESS == DOWN_FLAH_ADDRESS) + { + p_ota_info->status = OTA_STATUS_BOOT_DOWNLOAD; + UpdateOTAFlag(p_ota_info); + } + else + { + BackupVersion(); + } } else { @@ -985,6 +988,11 @@ reconnect: #ifndef MCUBOOT_BOOTLOADER if(XIUOS_FLAH_ADDRESS == DOWN_FLAH_ADDRESS) { + if (strcmp(platform_ota.version, p_ota_info->os.version) == 0) { + KPrintf("current version is the latest version and does not upgrade\n"); + MdelayKTask(2000); + continue; + } KPrintf("mqttCloudInteraction write OTA flag and reboot\n"); p_ota_info->status = OTA_STATUS_BOOT_DOWNLOAD; UpdateOTAFlag(p_ota_info); @@ -1134,6 +1142,11 @@ reconnect: memset(p_ota_info->down.description,0,sizeof(p_ota_info->down.description)); strncpy(p_ota_info->down.description, "MQTT OTA bin.",sizeof(p_ota_info->down.description)); + if(XIUOS_FLAH_ADDRESS == DOWN_FLAH_ADDRESS) + { + memcpy(&p_ota_info->os, &p_ota_info->down,sizeof(p_ota_info->os)); + } + p_ota_info->status = OTA_STATUS_READY; memset(p_ota_info->error_message,0,sizeof(p_ota_info->error_message)); @@ -1419,13 +1432,13 @@ int OtaTask(void) *******************************************************************************/ void app_clear_jumpflag(void) { - ota_info_t ota_info; + ota_info_t *p_ota_info = &g_ota_info; mcuboot.flash_init(); //跳转成功设置lastjumpflag为JUMP_SUCCESS_FLAG - memset(&ota_info, 0, sizeof(ota_info_t)); - mcuboot.op_flash_read(FLAG_FLAH_ADDRESS, (void*)&ota_info, sizeof(ota_info_t)); - ota_info.lastjumpflag = JUMP_SUCCESS_FLAG; - UpdateOTAFlag(&ota_info); + memset(p_ota_info, 0, sizeof(ota_info_t)); + mcuboot.op_flash_read(FLAG_FLAH_ADDRESS, (void*)p_ota_info, sizeof(ota_info_t)); + p_ota_info->lastjumpflag = JUMP_SUCCESS_FLAG; + UpdateOTAFlag(p_ota_info); mcuboot.flash_deinit(); } @@ -1511,8 +1524,11 @@ void ota_entry(void) BootLoaderJumpApp(); } } - Update(); - BootLoaderJumpApp(); + else + { + Update(); + BootLoaderJumpApp(); + } } } } From 84e4f2c3a193bd4e2de283ba8b25b72189c65aa1 Mon Sep 17 00:00:00 2001 From: songyanguang <345810377@qq.com> Date: Thu, 19 Jun 2025 14:10:56 +0800 Subject: [PATCH 12/15] Add ch32v208 OTA readme --- .../third_party_driver/ota/Readme.md | 86 ++++++++++++ .../ota/img/AssemblingFileTool.png | Bin 0 -> 19860 bytes .../ota/img/WchIspStudio.png | Bin 0 -> 81873 bytes .../ota/img/boot_or_app.png | Bin 0 -> 11340 bytes .../third_party_driver/ota/img/boot_start.png | Bin 0 -> 1796 bytes .../ota/img/current_version.png | Bin 0 -> 5997 bytes .../ota/img/download_ok.png | Bin 0 -> 7068 bytes .../ota/img/download_start.png | Bin 0 -> 8672 bytes .../ota/img/jump_to_app.png | Bin 0 -> 6269 bytes .../ota/img/mqtt_config.png | Bin 0 -> 6502 bytes .../third_party_driver/ota/img/ota_flag.png | Bin 0 -> 6448 bytes .../ota/img/python_early.png | Bin 0 -> 10835 bytes .../ota/img/python_main.png | Bin 0 -> 22368 bytes .../third_party_driver/ota/publisher/main.py | 127 ++++++++++++++++++ .../ota/publisher/main_early.py | 127 ++++++++++++++++++ 15 files changed, 340 insertions(+) create mode 100644 Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/Readme.md create mode 100644 Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/img/AssemblingFileTool.png create mode 100644 Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/img/WchIspStudio.png create mode 100644 Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/img/boot_or_app.png create mode 100644 Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/img/boot_start.png create mode 100644 Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/img/current_version.png create mode 100644 Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/img/download_ok.png create mode 100644 Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/img/download_start.png create mode 100644 Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/img/jump_to_app.png create mode 100644 Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/img/mqtt_config.png create mode 100644 Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/img/ota_flag.png create mode 100644 Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/img/python_early.png create mode 100644 Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/img/python_main.png create mode 100644 Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/publisher/main.py create mode 100644 Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/publisher/main_early.py diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/Readme.md b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/Readme.md new file mode 100644 index 000000000..5cd6ead82 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/Readme.md @@ -0,0 +1,86 @@ +# 编译 +路径 Ubiquitous/XiZi_IIoT 下,执行 make BOARD=ch32v208rbt6 menuconfig,打开config 选项: + + .config - XiZi_IIoT Project Configuration + > Tool feature > OTA function > Enable support OTA function > Compile bootloader bin or application bin. + +![alt text](img/boot_or_app.png) + + + + .config - XiZi_IIoT Project Configuration + > APP_Framework > app lib > lib using MQTT > Enable support MQTT function > xiuos platform mqtt connection parameter configuration. + +![alt text](img/mqtt_config.png) + +执行 make BOARD=ch32v208rbt6,进行编译。 + +编译后,分别生成 XiZi-ch32v208rbt6-boot.bin 和 XiZi-ch32v208rbt6-app.bin,以及 XiZi-ch32v208rbt6-boot.hex 和 XiZi-ch32v208rbt6-app.hex。 + +从沁恒官网([产品手册 - 南京沁恒微电子股份有限公司](https://www.wch.cn/downloads/category/27.html))下载工具软件 WCH_AssemblingFileTool.exe,将 XiZi-ch32v208rbt6-boot.hex 和 XiZi-ch32v208rbt6-app.hex 合并成 XiZi-ch32v208rbt6.bin。 + +![alt text](img/AssemblingFileTool.png) + + + +# 烧录 +从沁恒官网下载工具软件 WchIspStudio.exe,选择芯片和串口,选择固件。 + +设备端,按boot和reset按键,让设备进入烧录模式。点击“解除代码保护”和“下载”,进行烧录。 + +![alt text](img/WchIspStudio.png) + + + +# OTA升级 + +烧录成功后,先启动 boot 程序,然后跳转到 app 程序 。 + +![alt text](img/boot_start.png) + +![alt text](img/jump_to_app.png) + +进入系统后初始化4G模块并开启线程进行mqtt通信,可以看到此时的版本是 001.000.000。 + +![alt text](img/current_version.png) + +然后,需要进入publisher,将要更新的app程序XiZi-ch32v208rbt6-app.bin放到publisher下,修改main.py中的version和文件名。 + +然后,电脑上运行 python3 main_early.py (需pip install paho-mqtt安装依赖库)。 + +![alt text](img/python_early.png) + +设备检测到版本信息后,写入OTA状态,然后重启,重启后boot进入下载状态。 + +![alt text](img/ota_flag.png) + +然后,电脑上运行 python3 main.py。 + +![alt text](img/python_main.png) + +设备检测到版本信息后,开始传输文件。 + +![alt text](img/download_start.png) + +当传输进度为100%后,更新app的bin将烧录至APP区,之后板子会自动重启。 + +![alt text](img/download_ok.png) + +重启后依然先进入boot,然后启动app。查看APP日志,以及version打印信息确认升级成功。 + + + +# 注意事项 + +CH32V208的FLASH大小是480KB,其中零等待运行区域大小是128KB。FLASH快速写函数以及系统中断等关键函数需要运行在零等待运行区域。 + +程序分布如下: + +|address|Area|Size| +|-|-|-| +|0x08000000 ~ 0x08008000 | Boot_FAST | 32KB | +|0x08008000 ~ 0x08050000 | Application | 288KB | +|0x08050000 ~ 0x08077000 | Boot_SLOW | 156KB | +|0x08077000 ~ 0x08078000 | OTA_FLAG | 4KB | + + diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/img/AssemblingFileTool.png b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/img/AssemblingFileTool.png new file mode 100644 index 0000000000000000000000000000000000000000..cad8ec00f6088893b7b48d01a99a2ad39855ca2f GIT binary patch literal 19860 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%0AdIKM0`b!(krFs8SDteLOQ}8Bw4kTwviX-p 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

$awlKvwT6 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 z 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 literal 0 HcmV?d00001 diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/img/download_ok.png b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/img/download_ok.png new file mode 100644 index 0000000000000000000000000000000000000000..abfbbcb1382f3a7ff3acb4a89bd6f3f25195eddf GIT binary patch literal 7068 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 literal 0 HcmV?d00001 diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/img/download_start.png b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/img/download_start.png new file mode 100644 index 0000000000000000000000000000000000000000..b54165f8bf3a813a0c7157fe995561a1c00de367 GIT binary patch literal 8672 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 literal 0 HcmV?d00001 diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/img/jump_to_app.png b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/img/jump_to_app.png new file mode 100644 index 0000000000000000000000000000000000000000..f47ad3ff337b78e040c88a98b60b8d97d7d57d43 GIT binary patch literal 6269 zcmb_gX;f3$n!O-OQBn?2g(wP^0ucp~*?@skQ49zXP$3M7GDT&G5W^G#JhikC1Z5C0 zgeZeS2!weIQ=uSJB4ZdN0f7Vv0U;znAkfr%{eJX%-M#v))j#gJ_pEi+clTLmf8W{r zi@9cJ_0x}segpvEC+HPR2LO-;ZGRJf*tI=Yx0;E!Us4zcs|!FO{qW58LojmcmE0;0|0xP|9Yfa(Yam#psWD3JbyhD!5@7d$gA2D-ObnHS1GT2b8%}g zXg>8KQ^oZl-Z8+NnRQN;yiXq z0l;OwN1-4jvsJ=wXytn(U!rHo0*%f--&NdHE2An~KWXDy(!v|^b?f$2Y%O)QoocZN z-y;PyygscI-+1`4`o5FX_Vg)cewW6zLZnFx}SKa#+-{tL3+^SJn zXHJB##3!_jkwPNrn%&A@!6RwB>j6YrV6{1JtPI>10|M=VY9bwjw4fRqXARy>S(a&D zl!V(|=)de^%|Y@RNy*dU?bcz$=oKR0=6FhhKRL`^MInrsmzG%Akn_iy*Qcm|YtqWbq3n5ASfea^-d24d8x8iR7?8aZA9 z|GfZk^FGwr_t@PnIC;Y@X@WVa(^|mRHiTLae}P(q@DkILHrRfD5qK!|enb;Tz282* zgWWSN5E)5~JRz;qt4-k8mLfA0!eR=AqCb1!9~>_QY#3j@kHR=4wlCeFiTku$Q&uJ6 zqw1Mc=_ha7a@3QJVhm0arj18n-zx<8HkCw*DzXTiHf_#2&7--r77j<+y+R)vHeKdT z)8&oprVarIPpumsHbXW{=AL(X(m(DODYYn zSAghtVFwplCxdWb(TZSHO+z6@g;&jTTbF#LN39QI0uUa;^3m1!m1f6(z+#ONEN>r9 z`s|V8*>u6a|DaBg>@4MTU~guXx^h@u#mmH(!!JJb(hp~fMB;%y& zFx1L3K|CZX#@Dr)n%~n+q}mTf^bzR78Z?8q|2fa^VDw&(o!n3DZV#6Ax{ke2^2Z}E z0m2ohkKvJPwK@ct6AoK5yxHFtFdAnVJd9bdb_{-nM4dB_Dx5lp+O%U}Ej5aa$Aw>Y zF@IiVKR7b`G%zZ_14l*Wsr`=Iy3-NnTi3x+KaA_6(#>lr6QlyntNCgnjmz3=uSS0* zwR-es5%;Hn!^d|QuE*HKGv!(Wvb68CT6`)W7V}_1s6Q^^QohPTXamXx#%wTKXmdSA@9c&%9{6v=&Hkud-tAp)*8X+(iqWh~>HPDnPW^6Ji=^f~ub}$`%FQm9V+SUnP=-xt0M6bbq~(75 zOHswdDQ}^h3U~H#(7nRrLX(?ek1{!t)Vk~Qqp`1o5f6wC1N4jTD@$6)>9DkQA{H@n zAETf0bR~@q8*Sy63$Gl>(+RwV@UtcMw`BV-jIICL^&CSV(g#Q%Qyl?fUPM^w>BXG2eP!6db#+g zA+x)IF|u-#?S<8Fw*{)*zSLGen;)px;bIjJIhMd<8xBkc-}Rv06SQqML?jjWlA8Gt zGt>a~bw^|~NB#M@**p?hEsuMv{eESAQoL$ijI04yf1R~-4)Z3k`?h-P^DRKUpQz2~ z?*U9TfR(ZTDj|tC5q?S~F&J|!mM?}@vdUz<1>`Y@0fE-KzVJ3A(kG(iw6~S2y}?;5>m)BEk|W=pVhw{9H_3~k`6FXeJuK*B91N^WZtIguCxj>IkkS- z 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 r)@IUCEH{>*_vpWs*0R@^q7td literal 0 HcmV?d00001 diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/img/mqtt_config.png b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/img/mqtt_config.png new file mode 100644 index 0000000000000000000000000000000000000000..9f3c8577ee243b0d83305c08996bbbfac59f60a6 GIT binary patch literal 6502 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 KHA}A9WBv#9Ek_0b literal 0 HcmV?d00001 diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/img/ota_flag.png b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/img/ota_flag.png new file mode 100644 index 0000000000000000000000000000000000000000..6511c0c19e6110cac26ba9515beaf2192a935939 GIT binary patch literal 6448 zcmch6XH-*LyLA*if`|$z(os-Q=^`D%0VyH^qVxa}IDnK8AR;wE#X_VVM0$xwq$m)G z^o~kVT0|g$1VRZt6d{C=K*$a6xZn4U@xJ4`KktvdpS{;ud+xQKwf35Gu8q8FZO(r} z>;wP+;J3JCat{DF+Q7N?=lO$kcKj$K!wE-V_sop}=s}5P&JDM(k(ChufJx!o_c+G6 z=MBE)3#lW3SiVbM4D6egt3Q>9Y+$O}720;vy6bLShk7+cu)3CdhKpkhku%ok>|HA3Eo z^%K2qa)a1f6n+lC!PVlBh4?c}lc&VQJs5mqk&YP^!U>mBs@ zZiQ*!NJgskLj<%wwuZ!ca$4F;%vWDcb|*Ba{zPIQq*ke4zR(slr%uoB>^C)8o3R8!=-deQc1PWJ%voz3ny<9KL zQ6LXSY>O2X9R218@?YsX91w7_Umk|rSm6XQTE=#!whNfHbkF!6TESN6gzM&Hy^=Bd zT%Y(Z=H%Ri1NC@0;1BOBa+{UZ6DuU-(zLr3-lmFa*4Q^?zy6JJu9GhHvk=m`gje{;WlyNmRWIg6#;gIHd)QXJ}JtT z#dT}#YUmZIe%mn{Rc6ovP`mC2@M$jF&-h~>33HeiOVuRxhee2YUG{$_oZdH_{f?IpyxT6MMiw$y^}VqEVyw*fiLoNCX|;# z;4;ytypjy0s%h+1sn~0~W}faN7iJq$sI@T`-rFqR(-n_%UsGc>7H2l$;MS?BJ!c^E;e2p}2jZZ2Ky` zk$idURmaMr(0pb)y;AD zx}(oXW)qQe?Ha`uk>I@%7IO#Vv@;ObSgiSXPW0EJpfsn|NJ>{qo7NKkOqb`TD8+k9 zf}!TO!qe5nN+XGg84zR1&?6JQi^(r^SObU;Q!E3WfOyeXZf2 z3u(sp4Q;;kREtQ(j^GTUTWa~B#agc)EX!HTHRRlg{`yxa4D8&mr&;KS8L5Geau0QeqeHZAoHh<`d0Uwb-FQ~Fj>V{iWjZZj$T=2<_U&)K zMZrsbsI7cfZgo`J7In5?&8bm^mD}>%7x!lB@uMJfAQz~uc<0(iczN|E*1wbKJm#Oa znaA+M+qaTS`VTEV*iBRkbih< z8YeB`eDR|rjMaVF!{;K;j7!H9F>`F{qs*)+mnNqi#QmPg& zdd}ks%;^4{FqnN0r+Y=My(-BS-49QbCk72>zq^DI3$j4So9l+cmd!)fE#CP_ouX+> zo732obpc`28@c2|K4ws(X#vgq(^Pf9aFE_Rww}7#?YSKJ!ln_6*jdfjiV$d3 zv+*e~new@lMSC!Y8FC_{$M`zk8v1T}t<~>lYL_%9<3UXOVI`%BEkN2Hjq9@%UJ|;~ z=zG5cvlReg8Tbr*J-+ZI=W;Iiyh5E=AuH+hj%>gWNOV*XOn;gBb56WV2Hq4I)u#*E zByU^5^RnL8rRP%xYLb%hvMiu)s|c_ed;4sfX$(6xk}dKyx&fEgK2pyx3jJ2Hw{N#g zyAc{eh6Pg&+^EVS)^v1Z86$-tEUou{X5%m4PxJRt(GgrPZGqD+{U0bhH-E(jGmqoj zPLorQPlaF}=RRNC4{o-K1xp40a$wg0A3e)uMnYtr7`1f=Qq?{S`=dINW!d1&y4I2u zgXHSg*mv!mLD?d9?(|O#-fEfT`iV4M*U-xM^+JZC)W|idx`y&Wi+la9RJqv!FCrAy z5|rkW+J>rjKZ)|II1fT6ghj1U36a?C-2JZ>{;m7b1b%MSnfedD)a5P3&;Oz{~*&!M_O*_iov zrdlSyY%f#_<~JM?v?yh8W2dqxNgI5<9)f6scy2m#Cyr`vW`q?JS95kmfSEdkAqQlF zEXu3X^^1 zTM#EV6k(euZWo4GY=Me9sobQh>XOWIfB)J{bjgK>kBGXz;PA@s^)0i%5`-d@M#KOI zIvj$T4!BZ+!Xaf^g#Gye($D^bdj5l(oFXrd7=I>j#i`X0p;uaB~&CS3NM(OonH&t4BovfIn0dKif{p&2cXy;I4~l zqw^+ZI?LBe?yT_!dXicS>sFxwaUq%)H%2O&+Z!K;I_>9>y@~el!n*=DJP?*swN|KG z%HZ?Pgk0!=^S%bFX(!bMntv*2WVqMhD-$OJp~C3om|~pNGI!mUM^{h22LwEr;dhyHtz8KYGp5wZz6v za7j*q%)b<%x|Cv^dqAG1DD=LF6Fk@Hmz)E-uptM5hV~U}{wZ2X%pwB6#(b@J#nX$d z92lt-f0*)z{T#%)&uZ7b-&+YQqVwxjd3Vv|A1qN*(Zl{p<-)?t-P z!2RL1&98;NfF6)AgMjerZ@?F(CkKFx;n_QT;oUCUKM^$r0$8 zB3AwQ7m>PEAhY0aJ5Hmg|2_GddV zl?ZY?JhsBEe}WjY=k(GfxTE@LJqUli6TVcPVC3egu>~~OJZMQ^ms&A07wyhj>cvvS zMlxbX8Jy-hJ`j<8s>g246P#2YC?2k|=;jqBeHAfI|mdM^q_ItTtmkZ2;D9A!QRjiSU#}$bxhT#PPfV^|V z4RM=R`~XsXe1lnk!r$9A@f^L|COq80#jV`o`?DZ8RE!q@U_1XmM|UWL0lr-~IF96B z0RLh6pwn(pkaizP;#8+j`{_q;@Dh_`Podc?yA>?6b5cn2xqefby4xh&4(o#o!*CmH z5DQuN+IR|2t}Zv?Xm0k&;!XYw!KZmA_T1ol=}gb3>-i5JQZm$?x4kL0iyLl9c8xvW&<$bDY0i^*LB^ENYbt6Wa78=NiU|0rNFVs`^FQNDUYDZ644%wg zQ|m>245|%&n{{454u%^*s`-R(=?!j$6}z!@(P!y`mUil2$}I0>oxV!85h2Z zx%>W049!)G^0i7w8&MEAVQSf?Tt4{XLY9y7j$3Mc7tiVSI=+1Asi;a_rd?yZT<)4|GORi->9$~ zfIz40ZETPqs}W?9cepq`*>zVW&xh=_8Yue^)m!>Dz?;+tQmk})+Pi&tn3T%-2H#Se zIxWT&;R{aTRG)qzD$tiY=LxKHiti`}19Ud`+a7N`nFk6>kVyAnfx@3A5)R5&|KniqHWXd(G~ zi#th?w^qv*A0xi#-_U8<2#KN!t!GSQ@Ow00{Km;TzT_O?HIv9 z@e``XYL+5T6ACFM{|cPHyY5FlgCf*vIZ_U;9EYc943ak0U-=vGPAHy*wa7e(l{3nH z5tw$9;)|)p1dR@_$eOSS7z1g}n}S0Xy_z={hrd1&l=CbW_*3S!Ch-?dz-Z{TpsBXI zo&#Lz=pF0dO~ai765O&Wmv-eYI?i-LJV)gQzto%V@GQgL;Vg-|K1#u168=g`nzFco zC|!mrt4TuQU+9k&3oqZ+PyK!VD1KQe8NXA_I{Q!a?s&hEYD{)XS#;H`_>V7xef8$t z@RtklHEF&H2NQ8}5N;T$v4WpJGk3V1;@f>)Q@ougE;Qfz``bT<@V20>%Lq_NbrR3V z^$+$uJpo;o7koZ|1x#~wcrsKlwZ;*r3$PUuiXaTzwt~*%+L|HU((*nkigAo}uirZ_ z=FLRco7rd|DGqH+b5$ieUn*~(tu_6#SU}X4*cs}1?S}j_pp||TO0QshD1<`MY#)*! zAcUATs=QZ91}<+k${(Lpq59SeM_&m}Z&#L{)Wj4P1R;zJCl?<(liiquIx@i=XzL_D z?g)XG@rScMLZw(>+VsL<@ibN~iBs}F^O0)1|7*M{r#2w(RNpR|O=X#|&0DVq_hoYN zVCObJhW%uuhj+QqTi=BB2bHh1HV>Y^>$F6l*4!AZm`WwKu*cT$c<=qzuL9=yr;gRW zWJOlkoeFHRk3b>yXB`JuKgHW*x?4ZDM`z_{tm$T%z~-fAR})I3%InMuHH5$vI8Cb> zd0N9-(0QIz3P!@#>DQCX<4S$7UD<8ivPOj$}fdNG0{G&_tG3j;%=zNJ$>KV5FOvC9RG zI1rA%$d^GLfpMMewrnRUi$4~=O4!6!<4#90nu{u!Rf8{9&m3q!sIeA^zN>%b7fx2* zT=2fp{;1Mj2s>ioHCpbWYOS=dd{e$i6-4VKi; z_7M#EBy6VZWOQGTK1{GyYSxyWdRi(j+`8;U1f#5D~M9x*CWeUUZ-6U;74 zAuVQ2iw)SU4^vjgb^Xj%)MgF$KAJ{!?@TV7jcYi@A@t|oftuZyPA*V(@Tp8)f6KNV zNb)fOm-)^L88K)|$0$ST20gG2IUsQCDmpY);A{cZ)CsHkhiq{jTQ0LF>|^!rFq{&Q zou={Xsgvj%Eip{?zW2{-uU@%imO$AW zm7NxtCw-FJQKuJzsft^4o&Bbnz(_A@ij-m_{_GbqkS{fiBaeU6k^4zs(pQVYUtl}1h2U9tjgRoNr-8F_! zRT2Tp5;C6OcKGMmi=rx_6FNJT)4FacM{S}9(T>T4CFa%&Dr*ea%N9~uu+~rER?Hgi ziunqP#E+)%YpDyuwi|qJ3@40Fi)no|rj-yo-h}o=N#x5?01^_bzXlu@>m(r&bXa=F zHZ_!X|81MTcmHIuO(g~_6n@#Jw-jpM&7$f~b&w87tV%5xvYO05Au8g5cWY14I~+=c z&kL%zei!Sr$%U@!oriqF*D{?iSbG;X;<+FLTxj?x&ujXm-xa=J^j^s64Q@jSW&saE zKA1E|7owuW+q_kYiKs`j;Cv(}q_n22Urfo4gKMIJ{K4d74xgBe1&&-B8xusuR{DzVeK`QfRilslGsx zm!0q|Q)zvK!#U46$Ji9YtSVBg|13mXBX)d08!+{eI;0}|H>Pb0dNiXKM0!+oQk0qa zn@A#4{ST&0>}bxKy&wW|OSXK7e%?QV5{F{M8NoU@VoVfDq`A%rvAjhyaqLIAF8tRO3)%FN9m z^(fpG1F-K>!shR+wT;k6-PavN8(?d{4WBMW35SacyL(hn(U0?mi%9~c8EYdc`o(9) ztv&2J0DYfU-$?%8B~^rIEpe!&@cltXW4A8XZD7nB;pJ_UAItuXZOsF=oP^JQ*e zTJpxlQ1-os8k-S7WP}@UkzgE(`Wl^fssdBd=C6eLb?g_3ISc5WtKK?8gnp|wGnnGi z;_RPL{orRE_f#TQN5C&D?S>1%FLDp?Xn3Elo*WIqTiznW8+ttgEuz0_f4$dLfdL?$ zq3AtNu0=aPtBz`al3-kdsZLda{>dwWzW2=o-<^lw4GW!AmOYdi8~(7ygItvP`GO0$ zj+_}b2xA;n1Tx(>r0`E`p80#>uUuu#jP;ROb6axkFb{LsmXFrtgwpKf2kF(o?930B+PFS?SDZy0{Q|oSgfbXjK(M;2kKXu|9h2l1TYvL8R_^ zlpKD^Ct5}}fCOV+R0piK-8xzt@pJ;KjCb3^Kf~m!%N`W&ID-D|EiH4SS75Zbvf)XX z#&`>u!zi;#tmXy85ZHah^i8f3aE3W$-E*`j1fD;L>o&F!q)Mjx0Z+Dfq*#5BJCl6F zv!LZ7J^M^PNMpbm4)&`kU&6I@6rL$7Y)<>iJI6XG`;?-ZM#xHc}fnkWh7i=+a&1Z%^X=>~44Ov+SD8zSa8f5PR zqFHdOJ9U(063Pi08&ygx|JH<2AzvlA7_B(yDwaFgRWO47>UpV3ITyY|;!aVcIny5W zX)2)s++{ffW9~ME5}~)IW-||V+?-ffHn>zCfzEG30m}XCa1|{v{RU1^ZOKqLT<832t!ka@6-@_xw7)?q%*RhIR&33tI2jde-J0UHj)jvx^k}1 z&9Ry&Zv=TTh0r@o99u@r2*Sxz^$WU{7$tMPsuRlsC7sC$Oql3t^fBQV9y6P{YX+Cy zaC#XU;(1$sL1+3#IB|*2NMOxMQJX3}7HItcuJKON(DVOKY z8+DKy7Q#GLvSBk80%u6uorpb1Y}L7HGaVN1z~h?XR+k+TM{7?F!#auSNd`sJZ%o_f zyYra5LzLFd`bDERMGKBUdKU1rqh)}wt^QzRoraAdux4|ShJlG%DPj*UcS?&&wXoU6mizbq5K4+kz5z)L*S z0|j%)fN@FPb?{fr@WuVIqz>6i%%w$t@>Ft&NwmA{IGKtmK=QLjx^$iEnl=tjj@*orMrF2g={4SyNh;gP0jA_(eDmu zdFxF#2eDHZqGpt;RF0_=@gtxymn~kDV?G=G${oMzS%D+_PkQ8YGSvs0;s}S z;{8LQ7dN>!_P4^%HuhyL=ekrFwZv;Vj>{R+jb&C7hlWtR-G?IXskreomrp`dSoV#7 z@@M?Ua7CKC*@moCJ!i_nh*AQ0kcksr$nRs)*5*tCZ&Wid+KtAm1lH41z~jGK9& zii25D<_G0E^&JbN(~%V4R#89qA@0VQ!SEnPo9V#+F?ND%Q3rh6iLf&m5Hx2Z@~x6q zTEc^ED@ZNoPR;4Q6$&8}L2M-+V(2->olLxfG4yF*_lbSoo!*a@O$U}^xZE>&!iyX| z;l;BPUW^WPh8gW>jY5mnxku^Q-G7!p} zh(F0Z*j@byvLM>Hi+hGiUgH-%Fu=qMXQ|d6!mSVA=~d=A^ra_N^R898*`e3sFpdKg zUz4g=_-A$WR#;d&U594kkF%T_kO?S(bFkc8nSz1P!M(B6kvT>GrdA^KQPFxYw(Zx# zRL6rD*)@NYuSiB@?H@OSY!RK&YK?iKj<#HW<}n)`|Fvg@*8p*F`LTg%QFXx&$n6iy z{mpTwzP}9JKk#8~ymgW@P&1=UnxtpSzQp?&jOV^#422t;TNbdJ{KlR6LSt6C;K8WX zgW;$Z6Z7winb?WRJJii?rR8Oo*2)9`?eK0qYPZ8dz}8{+-|BvKSO!h&eD?)155H^4 zO*C){l#>^}LABr93Z6DO&WDGH#cMLn63`Eg*T-wTibwf~wR7uV7zrjIgm-M%Z7-ph zoRm(|if8JINyk(sy$=&Nh@}5~V@z8Vdduj;ZR!ETNW^NQWl={j6=Q%gwbQDPi(XCk z==DT&VVP?>wmW!L%N5%xDGNH_X zbcs*-7*V>UtR#2Ps0W-)KpjEdfO)OO2EU8)isO3?Dws-7QmYy zPhi77#u`*^*u2{bH_};b4gPBX@yF}TeW2A~G!W^dKxlDev;@V&l6JkK4Z7e<)F|25 z*$b1#QvdXLDQLmw#@1PS=JO2s+KIwSbD7Fy``BaC|9tk*p5tNCk=jdYclPe(XC6pxhdAn$)S%07@2V&DhrEcp7^Bu$He*~4 zP*Z3xm}l#*)+C4ObioQl;a;A-HPfn0TI~jrNSMTRVQU%igPkF%Zw*xjr1i+yuWiY~ zux8CLeV?QHOR(@{M^7^d`+4o>;Den=R)mLnHrJzCJKoTP=btp?bgez`S)h&`Qh0q& z|L*VyHObgV^h>P+M%-TRo&`5I4r5jKhp|Z7(l<7fgD(7)?Ec9qa);ZVUm&W3RV5mB zE_(YCx}6$k(vPd%{+9bW&__!%(5&B>7Xa*o9ULN`NU?1+A*sku1jb<22 zolgq(RB4@F45-02%z*q%B96TQ>+6w2P9}6KUkMKiM2WtnGmyp+n~hnAHTxTM-!7>2 zjC{d-4y9mXF+HXoWqOLc<9cwT3IM|Mlj(I8o44SYH2B?ofHb9JJ$j!jwWGPR^gyxS zQn*VMy$nnf5N`S0M^=Q+^;7QmTc9@p=8TF>duH%gHr-#8vtp7hbn}Z=b%wg@tI>tv zbcW7>YAKg?S_+-7UjV-x?TOeTCZHBmL;EOCy2>9>v%#DJP7ELvp#t~KkJ2;9))RGG z`WnvxPX(@iRB!nn6mV)(>x1q&8MZ5u`K>!_j`c?VMbvG2@;LR*UEtG=T}4QXrSQ=G zGYjOW*a0d_Zs~{k@-@yd%x_gD*)P{8NPt^ z6X|aReKobJu;7odjcot2*ed77%(O5tiauUe@Pnjy@=M(nD{p!IWY{ortD?Qo431D% zrU!%Xj^+17XVEFQCLuS={o1g1_yKe2#}n{Q?CikK=2M)_^Sa|NDcMW}^-a`bBF*23 z+8XXIw$ObqPsv=|6ZYF*$|+5^k~_@8B#ZZPdv(u+Q#wv>#0*NEx=A6;jKTSDcj;^T z7xAM1@+?196}#6WCgvZKR`l^6)L_1H00W+-bt2yAksVB}Dpe-jeOk|>eBhm9-9@Uh zE)evnY^fq_lG;9>8W_PBEQ}T~jFweZH?#%|6>ZIY&Flk{zN)Si)BHz*h{LX9)0xEd zN^>E7xoM5@kcy^60#jb+S6}zOx)d$d-TaOqcV>SmLDl{}(?UE~em1LYbB-#%qtKmg7s~ zH>3Isj`24=Ns4_uc*vtV-*C6l=ln|0m4O5n;SbUETYGOHtHxaE0X_;8yU_#&i>Awl z7V>EWA7JP!@ikG5Bs%F7?t?93B=|Fn7kN>IoIp|Ihu9)M;uxcP8$nI8{)-usN2nWf zUMCvJ4zR*{%A@b;Bnqfi$v+CI(3?2l;%f*B@kQMkmt++-I1}q0O}%My`MJqL)62=p zj(Gt3>2zKF3slhzKP_f4Ug-w^E`QQ>Bd7`#PB^Vd1Ecj5Zp33POuu2f4E2Kx;?V~& zUr-HcyTeDiVekUcjhA0Q_nf9%BUsYpXPP5u%gQ}&EyP9pb27;%f=g}^z6B9p)}@5% zbKXW-XtR@O&YqPmz;O1)6DItTeA9S!MfpNqlf-8rGU5b%a1gGA&+Z!gGl;e;cqm(o zSLj_24Ana^Rvt0bi@o6F*nk`by&(>3 z-KvewE||j!vo*3CPNB`pd6AWS$!*Y+tu9@8tMwSY!Vqx$R>I^Yl=LVa)ufc?KVt0D zZOka1YP%fybjf|zd$|Ow(s%JkQ$d(^ihECBQo21Vt;HBI(LHPhFXJH+_-Uidf$U*F zvAg=78tUilb+tsl4{Hbaoo8A3-!u?sDWbHyK>BwrS}`^!vVJ3c$>21_KOAq1M}1># zDL#2%_!#n{6+|9W7%mSN5Kvo|J!AJJ3tVc0>_17o=tAO8Xy!u^IA5K6=zoA+PJ5#b z^&u%Sf1srd%&b#cC$>@<D10@sb!8BWN@swO;hnrlZ$yxec;wy82WWK!WXx6lFI<5< z%CRKSD=}5D)@DZTB7cSRlUZuKt#b5^IuoW~J!Wd`=#;qj`koLl1<+Oh3$r#ax#d`s z!gySR2Ni%a${F4yejICA9*Q7;nz{*|xC-`tb+DKMG*M`IHdZwdL62_z5@0JwK$hHOQ{~CRAO4j& zV=P_viav*+v4fzLyz`Z6t2`chfCBTEW!*HN#m`POk{pEBuDtDA(7#X+58GS<>+aFb z=af%hBhyM-zAf2&Y&HY;fA`D%$S=QI z(qOvxSs*<#^J+}@^@hbf<|IK)H3jf}iLr~uBd1dtq#8VGgRaZ=WPvaB*di=20b+`1!vCn%@H0^bz?O+O#A`P7h^=NyW8{AY^X zfvZ=hmET9yWQXTH`$xxJY1>IdmZbxu<*O_!NONN;Br z$Y<9L@UH{lo^K5sL)Su8C`}#N4Mp_OID|Nk3f+jw;TWau+V}H-DOi~#PmR!tiUY8r z2W)3wy<)yuq}e4wRXZ~dsY53=QV523sk8N%d{4|F($b2^xET7JgF+L8pJ8RAefN!Q z{eutWXgC3?Q{A#Rs&&x%~)3pyvk6qV~(A zm4->#=i`i8jTK2&jfxhIMGS^O4&(%40v#+>&P{4*+2;b`AtU(B^)|kLo|L=p@>>~5 z(6{V`>Oi%&dSXJCYh`M!ImyU4b;)B{K9W{fq$W*ONCJt4`e;eReyQx*YxP_2t4l60 z)t{E5YN;^2(;7hqqEZ^!Pl8n60wYimNaZxIr_kXwGo#Ox#trQGM(xbtup zv@S9U3P+avSu15-ZcIdaTiGh82~^seaj%Tc)( zomKNj*94{R(a?hfXsmxSY$1g&SO>6V_E zOv^&9@}xz1Ix>^{lXau~15zGIZ=^z~U8y%>$LU{?g}T(GtAZY>H|B6#!rlEA-bI*8LEk^DmY=ZqJc{d-+t&G^pLcxiad2O$3i=4K@gM5f79U{Q(=8fQffZqlXB)) zmub%&4lbfM{OG^518GXT>M|pHUpP3xIpww&FJv6c_|a04bKSwqB5w)OmXs>BLi@V; zDe|LM6DJq}7a^}yPA+HsYffY{AC%{EvDj3wL)$S9+a{#Y?nZ~9?OWaztyk=h!-aC= z3_T$t#;2qUfn;n&PeNH(>(sZggL}4BO)a=D8bl--C{Ca&#?y5bC_^-=;Q_Br&Gw@Q2Zaelg2dAeH(w0P5?ZCioW z&VZ@BirxSYb3{8`{kI`;Do=wt!9d-G93SHM z70umlC-c2l*sce!POH23rG}_{w{sK zwS#;-1w97c+HOYPJM6C1wevJ0r}CWEht|oGCEME!xpzmBo{uePB%v_I?vatM)O}&r z`T|tK{nqlYB~$trmR97b6G?DxjQt(&aSE?9>QH0m2t&YZbNu0@)j};AKiV@h`oko1 z+h3~MDMUQgx)vLk@ug{}qh|h*!#doZEq1xJyf?=Bnst=&a*$@~iF2M0b??eurBJk? zu7sVFV^6upfqMoUOM6ZA=+`y)nWu;LJ(Y_2sKpP>M}e63v~n!En7H9ySSOb7KB)I& zYR3IbrIYXXW;VlqS=HQKy2au=mKXTx~nb;TLY zwU~Tm|22FSzt?i8mKfm9Nr+@-8{S!TK$wp^idD&f4ouM@GDvGKr8(Rl^$i!(_vW#H zqR2>ln}vxreb{R`GC1cqicOLR(_4Nnm(s+^;qU_+C>#Zm-*{rwLp>=ca+yCX7|M9~~L>fVQA{w|pqYas->K z`evHNkqma@wGAo>-r03wxN-+Gz(uqNT2QPJb+<)yzkC?~wwn9KGlH4t^hv&{Q*W@lezhcI znLl-wyjW{?Vr;Q%^Yx~3in#SHAp*K9&EH?qSUyKG%kMGB7||D9r=mM)YL6moZ>*G; zAC0?5RLk}@3j|!d;!#iMP1oSuxg15I-iBvby=KYVuCCE9(q+G#eg>DF?fx~o22wcu;BKG#8Ec*a zsRk#g9Q#dnV^CKG@T2Yr?2+xsm;!t?*2wndAj#Se@$KaXWD}cg7~z1JV8XqfW1J|5 zo?Iz=6;3WICt-5O1CyY3emT5Be{KFlUTf&KM) zl6^mP!Jj0X6ZR<}Is~7S0}JW0C!ewH`3{)OR1bc9HlR=6&s#eZ2+v_ezCEcv&Chr= zyQLtQ$l;dxTguJ)e`Sc;?*8t))rsn7K3&S5VG>6m{{Z=2rwL&AGewF&yz&mu)F~;* zo$TPi0_XTwr=RI*Hi5v}zTx!5$2sm@&3xc=^l!#ZEnG`gB~-7xi((#@EIE<8>MUh_ z#2)c0#mXrsv^eWs-_Fqlc=^8^k}kgZ3+2ZKMYe4DgNxZK9jQD-E^!k{ z19jhyY{a%W(JHFcOJJ$K#t%gfv6eaR3lg7 zq}UkQ0n~>TXpfaNK_-Om-iJp*(~2rO2N~6i$z||*$7bY{%4g>=?eB=Ux6a;xM4jF^ z(UaLS(59wHtyS~PkH3wW@yMnrvc;-@$7o4Qcb~6$C6{fy&r_{XMe4fnkcq=TL!Hr8 z-d5II765|e0^;+_y_hfa_cc>IRcUHm724k3du7!HmW{mpp0VyTV<1~gJd>2<_3}vo zkag4AV$BHJy>7zAVP{uu50Zk=RZp&oQRR1oUU4_(ez}M|?`kKdDfOPIlLK-*=83jh z>rZ2x`3dAvxxk(G_Wb)&tl67ZefW5@lZugsibo4xgL~Lgv65NQ|FPbPk2om(O zLCE#1y%o>(#z}#N{{rJj{vSGt|F*T?m-(>(;@AwDNSHZ-g+?`-6^aB=XrFGZW7DK4 zP8iiOJ0mWGFxR5?K?)laOT~xB#7IUlz}NcslAX6^fUpbsvXNXz+cza#gQdy^aWqetdn zPlg-h{O}!SSk3q;`vqi3vBNRjVq(>@68bZC}n)$ z_qXqGNxE^X!vR13C|#1@)yVx+e<2G9$hwSWNF|}HA9iB!OaHQ-_pX@_{uWuYA}>u( z=Y5^0FDRP13lD}x0hmwxs8z9Jv33>*CNCvgg4IU`iIm4*%$Ki@xuYKmEXRIgLWxyU zz*Lt8RA)!NsCwgBfX&iV^+!7??MC6~uqHc1$(GJhkvwImrB4Td8ri!GA6#^5qvn z-uO&qXaV;|tpTp@=`a>mlf@b6YNT@5ic#Ih6HWA;K8sX~|D1n&1ae5Qa zxgPR^F;tuEE_|(xh(?*INnL6Uv#t2Koj^|>B&jpKCm*JLPFj0<2%9lILmhQ!f!^P5 zJ3V4e22tn@c@ImxOxl`%&Ne_xT0Rvm3V}UKbDr5=F$qN4|JH=pTJ4~VcG!)6dj?_w Qf10k%1qaJ2i|haV2aV99mjD0& literal 0 HcmV?d00001 diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/img/python_main.png b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/img/python_main.png new file mode 100644 index 0000000000000000000000000000000000000000..801b64eb25f824dbb32b9ef0fd5874f76509dffc GIT binary patch literal 22368 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 literal 0 HcmV?d00001 diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/publisher/main.py b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/publisher/main.py new file mode 100644 index 000000000..689a6a9a0 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/publisher/main.py @@ -0,0 +1,127 @@ +import paho.mqtt.client as mqtt +import json +import os +import hashlib + +# 配置参数(根据实际情况修改) +MQTT_BROKER = "47.115.50.232" # MQTT代理地址 +MQTT_PORT = 1883 # 端口 +FILE_PATH = "XiZi-ch32v208rbt6-app.bin" # 要发送的固件文件路径 +CLIENT_ID = "D001" # 设备客户端ID +VERSION = "001.000.002" # 新固件版本号 +FILE_ID = 1 # 文件标识符 + +def calculate_md5(file_path): + """ 计算文件的MD5哈希值 """ + hash_md5 = hashlib.md5() + with open(file_path, "rb") as f: + for chunk in iter(lambda: f.read(4096), b""): + hash_md5.update(chunk) + return hash_md5.hexdigest() + +def compact_json(payload: dict) -> str: + """生成无空格/换行的紧凑JSON字符串""" + return json.dumps(payload, separators=(',', ':')) + +def on_connect(client, userdata, flags, rc): + """ 连接回调函数 """ + if rc == 0: + print("连接成功!") + # 订阅文件请求主题 + client.subscribe("xiuosiot/ota/files") + + # 发送初始更新信息 + init_payload = { + "fileSize": userdata["file_size"], + "version": userdata["fw_version"], + "fileId": userdata["file_id"], + "md5": userdata["file_md5"] + } + client.publish( + topic=f"ota/{CLIENT_ID}/update", + payload=compact_json(init_payload), + qos=1 + ) + print(f"已发送初始化消息到 ota/{CLIENT_ID}/update") + + else: + print(f"连接失败,错误码:{rc}") + +def on_message(client, userdata, msg): + """ 消息到达回调函数 """ + try: + payload = json.loads(msg.payload.decode()) + print("收到文件请求:", payload) + + # 验证必要字段 + required_fields = ["clientId", "fileId", "fileOffset", "size"] + if not all(field in payload for field in required_fields): + print("错误:缺少必要字段") + return + + # 验证客户端ID + if payload["clientId"] != CLIENT_ID: + print(f"忽略非目标客户端请求:{payload['clientId']}") + return + + # 提取请求参数 + offset = payload["fileOffset"] + request_size = payload["size"] + reply_topic = f"ota/{CLIENT_ID}/files" + + # 读取文件内容 + try: + with open(FILE_PATH, "rb") as f: + f.seek(offset) + file_data = f.read(request_size) + + if len(file_data) == 0: + print("错误:读取到空数据或超出文件范围") + return + except Exception as e: + print(f"文件读取失败:{str(e)}") + return + + # 发送文件片段 + client.publish(reply_topic, file_data, qos=1) + print(f"已发送 {len(file_data)} 字节到 {reply_topic}") + + except json.JSONDecodeError: + print("错误:无效的JSON格式") + except Exception as e: + print(f"处理消息时出错:{str(e)}") + +def main(): + # 验证文件存在性 + if not os.path.exists(FILE_PATH): + print(f"错误:文件 {FILE_PATH} 不存在") + exit(1) + + # 计算文件参数 + file_size = os.path.getsize(FILE_PATH) + file_md5 = calculate_md5(FILE_PATH) + + # 创建MQTT客户端 + client = mqtt.Client(userdata={ + "file_size": file_size, + "fw_version": VERSION, + "file_id": FILE_ID, + "file_md5": file_md5 + }) + + # 设置回调函数 + client.on_connect = on_connect + client.on_message = on_message + + try: + client.username_pw_set("ch32v208", "xiuosiot") # 取消注释并填写凭证 + client.connect(MQTT_BROKER, MQTT_PORT, 60) + client.loop_forever() + except KeyboardInterrupt: + print("\n程序已终止") + except Exception as e: + print(f"连接错误:{str(e)}") + exit(1) + +if __name__ == "__main__": + main() diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/publisher/main_early.py b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/publisher/main_early.py new file mode 100644 index 000000000..301ccc51e --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/publisher/main_early.py @@ -0,0 +1,127 @@ +import paho.mqtt.client as mqtt +import json +import os +import hashlib + +# 配置参数(根据实际情况修改) +MQTT_BROKER = "47.115.50.232" # MQTT代理地址 +MQTT_PORT = 1883 # 端口 +FILE_PATH = "XiZi-ch32v208rbt6-app.bin" # 要发送的固件文件路径 +CLIENT_ID = "D001" # 设备客户端ID +VERSION = "001.000.002" # 新固件版本号 +FILE_ID = 1 # 文件标识符 + +def calculate_md5(file_path): + """ 计算文件的MD5哈希值 """ + hash_md5 = hashlib.md5() + with open(file_path, "rb") as f: + for chunk in iter(lambda: f.read(4096), b""): + hash_md5.update(chunk) + return hash_md5.hexdigest() + +def compact_json(payload: dict) -> str: + """生成无空格/换行的紧凑JSON字符串""" + return json.dumps(payload, separators=(',', ':')) + +def on_connect(client, userdata, flags, rc): + """ 连接回调函数 """ + if rc == 0: + print("连接成功!") + # 订阅文件请求主题 + client.subscribe("xiuosiot/ota/files") + + # 发送初始更新信息 + init_payload = { + "fileSize": userdata["file_size"], + "version": userdata["fw_version"], + "fileId": userdata["file_id"], + "md5": userdata["file_md5"] + } + client.publish( + topic=f"ota/{CLIENT_ID}/update", + payload=compact_json(init_payload), + qos=1 + ) + print(f"已发送初始化消息到 ota/{CLIENT_ID}/update") + + else: + print(f"连接失败,错误码:{rc}") + +def on_message(client, userdata, msg): + """ 消息到达回调函数 """ + try: + payload = json.loads(msg.payload.decode()) + print("收到文件请求:", payload) + + # 验证必要字段 + required_fields = ["clientId", "fileId", "fileOffset", "size"] + if not all(field in payload for field in required_fields): + print("错误:缺少必要字段") + return + + # 验证客户端ID + if payload["clientId"] != CLIENT_ID: + print(f"忽略非目标客户端请求:{payload['clientId']}") + return + + # 提取请求参数 + offset = payload["fileOffset"] + request_size = payload["size"] + reply_topic = f"ota/{CLIENT_ID}/files" + + # 读取文件内容 + try: + with open(FILE_PATH, "rb") as f: + f.seek(offset) + file_data = f.read(request_size) + + if len(file_data) == 0: + print("错误:读取到空数据或超出文件范围") + return + except Exception as e: + print(f"文件读取失败:{str(e)}") + return + + # 发送文件片段 + #client.publish(reply_topic, file_data, qos=1) + #print(f"已发送 {len(file_data)} 字节到 {reply_topic}") + + except json.JSONDecodeError: + print("错误:无效的JSON格式") + except Exception as e: + print(f"处理消息时出错:{str(e)}") + +def main(): + # 验证文件存在性 + if not os.path.exists(FILE_PATH): + print(f"错误:文件 {FILE_PATH} 不存在") + exit(1) + + # 计算文件参数 + file_size = os.path.getsize(FILE_PATH) + file_md5 = calculate_md5(FILE_PATH) + + # 创建MQTT客户端 + client = mqtt.Client(userdata={ + "file_size": file_size, + "fw_version": VERSION, + "file_id": FILE_ID, + "file_md5": file_md5 + }) + + # 设置回调函数 + client.on_connect = on_connect + client.on_message = on_message + + try: + client.username_pw_set("ch32v208", "xiuosiot") # 取消注释并填写凭证 + client.connect(MQTT_BROKER, MQTT_PORT, 60) + client.loop_forever() + except KeyboardInterrupt: + print("\n程序已终止") + except Exception as e: + print(f"连接错误:{str(e)}") + exit(1) + +if __name__ == "__main__": + main() From c5aa020398c9d8d0920dcb455e0fbf0b2482e337 Mon Sep 17 00:00:00 2001 From: songyanguang <345810377@qq.com> Date: Thu, 19 Jun 2025 20:15:38 +0800 Subject: [PATCH 13/15] Modify printf --- .../Framework/connection/4g/ec801e/ec801e.c | 2 -- APP_Framework/Framework/connection/adapter.c | 2 +- APP_Framework/lib/mqtt/platform_mqtt.c | 11 ++------ .../XiZi_IIoT/arch/risc-v/ch32v208rbt6/boot.S | 6 ++-- .../XiZi_IIoT/board/ch32v208rbt6/board.c | 5 +--- .../ch32v208rbt6/third_party_driver/Kconfig | 2 +- Ubiquitous/XiZi_IIoT/tool/bootloader/Kconfig | 28 +++++++++---------- 7 files changed, 21 insertions(+), 35 deletions(-) diff --git a/APP_Framework/Framework/connection/4g/ec801e/ec801e.c b/APP_Framework/Framework/connection/4g/ec801e/ec801e.c index c777d3ce4..b9b17bd73 100644 --- a/APP_Framework/Framework/connection/4g/ec801e/ec801e.c +++ b/APP_Framework/Framework/connection/4g/ec801e/ec801e.c @@ -200,8 +200,6 @@ static int Ec801eConnect(struct Adapter *adapter, enum NetRoleType net_role, con int try = 0; uint8_t ec801e_cmd[64]; - printf("%s enter\n", __func__); - AtSetReplyEndChar(adapter->agent, 0x4F, 0x4B); /*step1: serial write "+++", quit transparent mode*/ diff --git a/APP_Framework/Framework/connection/adapter.c b/APP_Framework/Framework/connection/adapter.c index c49a5ce5e..8b4d9ad59 100644 --- a/APP_Framework/Framework/connection/adapter.c +++ b/APP_Framework/Framework/connection/adapter.c @@ -407,7 +407,7 @@ int AdapterDeviceConnect(struct Adapter *adapter, enum NetRoleType net_role, con if (NULL == ip_done->connect) return -1; - printf("AdapterDeviceConnect to connect ip=%s port=%s\n", ip, port); + return ip_done->connect(adapter, net_role, ip, port, ip_type); } else { printf("AdapterDeviceConnect net_protocol %d not support\n", adapter->net_protocol); diff --git a/APP_Framework/lib/mqtt/platform_mqtt.c b/APP_Framework/lib/mqtt/platform_mqtt.c index c3fcfcbf5..7c2368358 100644 --- a/APP_Framework/lib/mqtt/platform_mqtt.c +++ b/APP_Framework/lib/mqtt/platform_mqtt.c @@ -46,8 +46,6 @@ int AdapterNetActive(void) { int ret = 0; uint32_t baud_rate = BAUD_RATE_115200; - - KPrintf("%s enter\n", __func__); adapter = AdapterDeviceFindByName(ADAPTER_4G_NAME); adapter->socket.socket_id = 0; @@ -68,13 +66,11 @@ int AdapterNetActive(void) { goto out; } - KPrintf("%s success\n", __func__); out: if (ret < 0) { AdapterDeviceClose(adapter); - KPrintf("%s fail\n", __func__); } return ret; @@ -116,8 +112,6 @@ bool MQTT_Connect(void) { uint8_t TryConnect_time = 10; //尝试登录次数 - KPrintf("%s enter\n", __func__); - memset(&Platform_mqtt,0,sizeof(Platform_mqtt)); #ifdef XIUOS_PLATFORM sprintf(Platform_mqtt.ClientID,"%s",CLIENTID); //客户端ID存入缓冲区 @@ -184,7 +178,8 @@ bool MQTT_Connect(void) MQTT_Send(Platform_mqtt.Pack_buff,Platform_mqtt.Fixed_len + Platform_mqtt.Variable_len + Platform_mqtt.Payload_len); MdelayKTask(50); MQTT_Recv(mqtt_rxbuf, 4); - if(mqtt_rxbuf[0] == parket_connetAck[0] && mqtt_rxbuf[1] == parket_connetAck[1] && mqtt_rxbuf[2] == parket_connetAck[2] && mqtt_rxbuf[3] == parket_connetAck[3]) //连接成功 + if(mqtt_rxbuf[0] == parket_connetAck[0] && mqtt_rxbuf[1] == parket_connetAck[1] + && mqtt_rxbuf[2] == parket_connetAck[2] && mqtt_rxbuf[3] == parket_connetAck[3]) //连接成功 { return true; } @@ -216,8 +211,6 @@ bool MQTT_SubscribeTopic(uint8_t *topic_name) { uint8_t TrySub_time = 10; //尝试订阅次数 - KPrintf("%s topic_name=%s\n", __func__, topic_name); - Platform_mqtt.Fixed_len = 1; //SUBSCRIBE报文,固定报头长度暂定为1 Platform_mqtt.Variable_len = 2;//SUBSCRIBE报文,可变报头长度=2,2为字节报文标识符 Platform_mqtt.Payload_len = 0; //SUBSCRIBE报文,负载数据长度暂定为0 diff --git a/Ubiquitous/XiZi_IIoT/arch/risc-v/ch32v208rbt6/boot.S b/Ubiquitous/XiZi_IIoT/arch/risc-v/ch32v208rbt6/boot.S index 871086a72..f6cec39f0 100644 --- a/Ubiquitous/XiZi_IIoT/arch/risc-v/ch32v208rbt6/boot.S +++ b/Ubiquitous/XiZi_IIoT/arch/risc-v/ch32v208rbt6/boot.S @@ -268,11 +268,11 @@ handle_reset: csrw mtvec, t0 jal SystemInit -#ifdef __BOOTLOADER /* BOOT */ +#ifdef __BOOTLOADER la t0, ota_entry -#else /* APP */ +#else la t0, entry -#endif /* BOOT */ +#endif csrw mepc, t0 mret diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/board.c b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/board.c index dc69f4824..eb23113e1 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/board.c +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/board.c @@ -72,16 +72,13 @@ void readRomConfiguration(void) { extern pmodule_cfg CFG; // 指向配置信息的指针 /* 从EEPROM中读取网络配置信息 */ - KPrintf("%s PAGE_READ_START_ADDR=%08x\n", __func__, PAGE_WRITE_START_ADDR); CFG_READ(PAGE_WRITE_START_ADDR, Configbuf, MODULE_CFG_LEN); /* 如果存储在EEPROM中的网络配置信息无效,或者WCHNET还没有被主机配置过,通过默认配置信息初始化WCHNET */ if ((CFG->cfgFlag[0] != checkcode1) || (CFG->cfgFlag[1] != checkcode2)) { - KPrintf("%s PAGE_ERASE_START_ADDR=%08x\n", __func__, PAGE_WRITE_START_ADDR); CFG_ERASE(PAGE_WRITE_START_ADDR, FLASH_PAGE_SIZE); - KPrintf("%s PAGE_WRITE_START_ADDR=%08x\n", __func__, PAGE_WRITE_START_ADDR); CFG_WRITE(PAGE_WRITE_START_ADDR, (u8 *)&defaultConfiguration, MODULE_CFG_LEN); - KPrintf("%s NVIC_SystemReset\n\n", __func__); + KPrintf("%s NVIC_SystemReset\n", __func__); NVIC_SystemReset(); // 复位ch32v208 } diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/Kconfig b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/Kconfig index b81a76455..5e66b2e60 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/Kconfig +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/Kconfig @@ -111,6 +111,6 @@ menuconfig BSP_USING_LTE default "lte_dev1" config LTE_TEST bool "Enable lte test" - default y + default n endif \ No newline at end of file diff --git a/Ubiquitous/XiZi_IIoT/tool/bootloader/Kconfig b/Ubiquitous/XiZi_IIoT/tool/bootloader/Kconfig index 45fe943b6..14464502f 100644 --- a/Ubiquitous/XiZi_IIoT/tool/bootloader/Kconfig +++ b/Ubiquitous/XiZi_IIoT/tool/bootloader/Kconfig @@ -16,24 +16,22 @@ menu "OTA function" bool "Config as application." endchoice - #if MCUBOOT_APPLICATION - choice - prompt "The way of OTA firmware upgrade." - default OTA_BY_PLATFORM + choice + prompt "The way of OTA firmware upgrade." + default OTA_BY_PLATFORM - config OTA_BY_PLATFORM - bool "Through IoT management platform." - select LIB_USING_MQTT + config OTA_BY_PLATFORM + bool "Through IoT management platform." + select LIB_USING_MQTT - config OTA_BY_TCPSERVER - bool "Through the public network TCP server." - select SUPPORT_CONNECTION_FRAMEWORK - select CONNECTION_ADAPTER_4G + config OTA_BY_TCPSERVER + bool "Through the public network TCP server." + select SUPPORT_CONNECTION_FRAMEWORK + select CONNECTION_ADAPTER_4G - config OTA_BY_NONE - bool "Not download firmware." - endchoice - #endif + config OTA_BY_NONE + bool "Not download firmware." + endchoice menu "Flash area address and size configuration." config CHIP_FLAH_BASE From fb1cf06b6eb204006601b0b4341c2508d716f019 Mon Sep 17 00:00:00 2001 From: songyanguang <345810377@qq.com> Date: Fri, 20 Jun 2025 11:00:07 +0800 Subject: [PATCH 14/15] Modify ota readme --- Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/board.c | 2 +- .../ch32v208rbt6/third_party_driver/ota/Readme.md | 13 +++++++++++-- Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.c | 5 ++++- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/board.c b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/board.c index eb23113e1..c17c7cc7a 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/board.c +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/board.c @@ -78,7 +78,7 @@ void readRomConfiguration(void) { if ((CFG->cfgFlag[0] != checkcode1) || (CFG->cfgFlag[1] != checkcode2)) { CFG_ERASE(PAGE_WRITE_START_ADDR, FLASH_PAGE_SIZE); CFG_WRITE(PAGE_WRITE_START_ADDR, (u8 *)&defaultConfiguration, MODULE_CFG_LEN); - KPrintf("%s NVIC_SystemReset\n", __func__); + KPrintf("%s NVIC_SystemReset\r\n\r\n", __func__); NVIC_SystemReset(); // 复位ch32v208 } diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/Readme.md b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/Readme.md index 5cd6ead82..06152c822 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/Readme.md +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/Readme.md @@ -1,5 +1,15 @@ # 编译 -路径 Ubiquitous/XiZi_IIoT 下,执行 make BOARD=ch32v208rbt6 menuconfig,打开config 选项: +生成支持OTA升级的固件,需要分别编译boot和app。其中,boot是升级需要的固件,app是正常系统固件。 + +编译boot之前,需要在路径 Ubiquitous/XiZi_IIoT 下,执行: + + cp board/ch32v208rbt6/.defconfig_boot board/ch32v208rbt6/.defconfig + +编译app之前,需要在路径 Ubiquitous/XiZi_IIoT 下,执行: + + cp board/ch32v208rbt6/.defconfig_app board/ch32v208rbt6/.defconfig + +可以执行 make BOARD=ch32v208rbt6 menuconfig,查看config 选项。 .config - XiZi_IIoT Project Configuration > Tool feature > OTA function > Enable support OTA function > Compile bootloader bin or application bin. @@ -83,4 +93,3 @@ CH32V208的FLASH大小是480KB,其中零等待运行区域大小是128KB。FLA |0x08050000 ~ 0x08077000 | Boot_SLOW | 156KB | |0x08077000 ~ 0x08078000 | OTA_FLAG | 4KB | - diff --git a/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.c b/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.c index 8175599ce..84f2f909e 100644 --- a/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.c +++ b/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.c @@ -486,14 +486,15 @@ static void BootLoaderJumpApp(void) if(p_ota_info->lastjumpflag == JUMP_FAILED_FLAG) { - mcuboot.print_string("\r\n------Jump to app partition failed,start version rollback!------\r\n"); if(XIUOS_FLAH_ADDRESS == DOWN_FLAH_ADDRESS) { + mcuboot.print_string("\r\n------Jump to app partition failed, retry download!------\r\n"); p_ota_info->status = OTA_STATUS_BOOT_DOWNLOAD; UpdateOTAFlag(p_ota_info); } else { + mcuboot.print_string("\r\n------Jump to app partition failed,start version rollback!------\r\n"); BackupVersion(); } } @@ -1514,6 +1515,8 @@ void ota_entry(void) extern int InitHwLte(void); InitHwLte(); #endif + app_clear_jumpflag(); + mcuboot.print_string("ota_entry to XiUOSStartup\r\n"); extern int XiUOSStartup(void); XiUOSStartup(); From a621543f24ed6d315adcb517bc1bb82b79bfda2e Mon Sep 17 00:00:00 2001 From: songyanguang <345810377@qq.com> Date: Fri, 20 Jun 2025 11:22:31 +0800 Subject: [PATCH 15/15] Delete invalid code --- .../third_party_driver/common/ymodem.c | 5 - .../include/flash_for_ota.h | 1 - .../third_party_driver/include/ymodem.h | 26 ---- .../third_party_driver/ota/flash_for_ota.c | 120 ------------------ 4 files changed, 152 deletions(-) diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/common/ymodem.c b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/common/ymodem.c index 078ba3296..4032793ae 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/common/ymodem.c +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/common/ymodem.c @@ -23,11 +23,6 @@ #include "flash_for_ota.h" #include "boot_for_ota.h" -uint8_t tab_1024[1024] ={0}; -uint8_t FileName[FILE_NAME_LENGTH]; - - - /******************************************************************************* * 函 数 名: Ymodem_Receive * 功能描述: 使用ymodem协议接收文件 diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/include/flash_for_ota.h b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/include/flash_for_ota.h index 79aed412f..9e6a72a45 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/include/flash_for_ota.h +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/include/flash_for_ota.h @@ -25,7 +25,6 @@ #include "common.h" #define FLASH_PAGE_FAST_SIZE 256 -#define FLASH_BLOCK_SIZE 4096 typedef int32_t status_t; diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/include/ymodem.h b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/include/ymodem.h index d40b826fe..8de5dc59c 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/include/ymodem.h +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/include/ymodem.h @@ -24,32 +24,6 @@ #include -#define PACKET_SEQNO_INDEX (1) -#define PACKET_SEQNO_COMP_INDEX (2) - -#define PACKET_HEADER (3) -#define PACKET_TRAILER (2) -#define PACKET_OVERHEAD (PACKET_HEADER + PACKET_TRAILER) -#define PACKET_SIZE (128) -#define PACKET_1K_SIZE (1024) - -#define FILE_NAME_LENGTH (256) -#define FILE_SIZE_LENGTH (16) - -#define SOH (0x01) /* start of 128-byte data packet */ -#define STX (0x02) /* start of 1024-byte data packet */ -#define EOT (0x04) /* end of transmission */ -#define ACK (0x06) /* acknowledge */ -#define NAK (0x15) /* negative acknowledge */ -#define CA (0x18) /* two of these in succession aborts transfer */ -#define CRC16 (0x43) /* 'C' == 0x43, request 16-bit CRC */ - -#define ABORT1 (0x41) /* 'A' == 0x41, abort by user */ -#define ABORT2 (0x61) /* 'a' == 0x61, abort by user */ - -#define NAK_TIMEOUT (0x100000) -#define MAX_ERRORS (5) - int32_t SerialDownload(const uint32_t addr); int32_t Ymodem_Receive(uint8_t *buf, const uint32_t addr); diff --git a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/flash_for_ota.c b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/flash_for_ota.c index e2a3d4501..87e0b42ef 100644 --- a/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/flash_for_ota.c +++ b/Ubiquitous/XiZi_IIoT/board/ch32v208rbt6/third_party_driver/ota/flash_for_ota.c @@ -23,12 +23,6 @@ #include "flash_for_ota.h" #include "ch32v20x_flash.h" -#if 0 -uint8_t NorFlash_BUFFER[4096]; //4K buffer cache -uint8_t buffer[FLASH_PAGE_SIZE]; //256 bytes buffer cache -#endif - - /******************************************************************************* * 函 数 名: FLASH_Init @@ -38,19 +32,8 @@ uint8_t buffer[FLASH_PAGE_SIZE]; //256 bytes buffer cache *******************************************************************************/ void FLASH_Init(void) { - #if 0 - /* Update LUT Table for Status, Write Enable, Erase and Program */ - ROM_FLEXSPI_NorFlash_UpdateLut(0, NOR_CMD_LUT_SEQ_IDX_READSTATUS, (const uint32_t *)FlashLookupTable.ReadStatus_Seq, 10U); - /* Use 30MHz Flexspi clock for safe operation */ - flexspi_clock_config(0, kFLEXSPISerialClk_30MHz, kFLEXSPIClk_DDR); - extern flexspi_nor_config_t Qspiflash_config; - flexspi_config_mcr1(0, &Qspiflash_config.memConfig); - flexspi_configure_dll(0, &Qspiflash_config.memConfig); - ROM_FLEXSPI_NorFlash_ClearCache(0); - #endif } - /******************************************************************************* * 函 数 名: FLASH_DeInit * 功能描述: Flash接口反初始化,需在完成Flash相关操作后进行调用 @@ -59,13 +42,6 @@ void FLASH_Init(void) *******************************************************************************/ void FLASH_DeInit(void) { - #if 0 - lookuptable_t clearlut; - memset(&clearlut, 0, sizeof(lookuptable_t)); - ROM_FLEXSPI_NorFlash_UpdateLut(0, NOR_CMD_LUT_SEQ_IDX_READSTATUS, (const uint32_t *)FlashLookupTable.ReadStatus_Seq, 10U); - /* Use 30MHz Flexspi clock for safe operation */ - flexspi_clock_config(0, kFLEXSPISerialClk_30MHz, kFLEXSPIClk_DDR); - #endif } /******************************************************************************* @@ -132,7 +108,6 @@ status_t Flash_Read(uint32_t addr, uint8_t *buf, uint32_t len) return 0; } - /******************************************************************************* * 函 数 名: Flash_Copy * 功能描述: 实现flash数据在分区之间的拷贝 @@ -143,61 +118,6 @@ status_t Flash_Read(uint32_t addr, uint8_t *buf, uint32_t len) *******************************************************************************/ status_t Flash_Copy(uint32_t srcAddr,uint32_t dstAddr, uint32_t imageSize) { - #if 0 - uint32_t PageNum, Remain, i; - status_t status; - - if((srcAddr == dstAddr) || imageSize > APP_FLASH_SIZE) - { - return (status_t)kStatus_Fail; - } - - status = Flash_Erase(dstAddr,imageSize); - if(status != kStatus_Success) - { - KPrintf("Erase flash 0x%08x failure !\r\n",dstAddr); - return status; - } - - PageNum = imageSize/FLASH_PAGE_SIZE; - Remain = imageSize%FLASH_PAGE_SIZE; - - for(i=0;i=SECTOR_SIZE) - { - status = Flash_Write(WriteAddr,dataBuff,dataLen); - if(status != kStatus_Success) - { - return status; - } - packetNum = 0; - dataLen = 0; - } - *FlashAddress += DataLength; - } - else - { - status = Flash_Write(WriteAddr,dataBuff,dataLen); - if(status != kStatus_Success) - { - return status; - } - packetNum = 0; - dataLen = 0; - } - return (status_t)kStatus_Success;; - #endif return 0; }