From 53055754878de1ff41896fa550ec614b305caaf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E9=AA=A2?= <2592509183@qq.com> Date: Tue, 23 Apr 2024 18:06:28 +0800 Subject: [PATCH] fix driver for stm32h7. --- .gitmodules | 6 + .gitmodules_cn | 6 + hw/bsp/mc02/config/7dofengineer.config | 142 --- hw/bsp/mc02/config/blink.config | 61 +- hw/bsp/mc02/drivers/CMakeLists.txt | 7 +- hw/bsp/mc02/drivers/armtoolbox/CMakeLists.txt | 26 - hw/bsp/mc02/drivers/bsp.c | 3 +- hw/bsp/mc02/drivers/bsp_can.c | 24 +- hw/bsp/mc02/drivers/bsp_def.h | 56 -- hw/bsp/mc02/drivers/bsp_dwt.c | 132 --- hw/bsp/mc02/drivers/bsp_dwt.h | 94 -- hw/bsp/mc02/drivers/flash/ef_port.c | 6 +- hw/bsp/mc02/drivers/flash/w25q64.c | 818 +++++++++--------- hw/bsp/mc02/drivers/flash/w25q64.h | 72 +- hw/bsp/mc02/drivers/rtos/rtos.c | 2 +- hw/bsp/mc02/ld/LinkerScripts.ld | 12 +- hw/mcu/st/cmake/mcu_stm32h7.cmake | 28 + hw/mcu/st/cmsis_device_h7 | 1 + hw/mcu/st/stm32h7xx_hal_driver | 1 + 19 files changed, 536 insertions(+), 961 deletions(-) delete mode 100644 hw/bsp/mc02/config/7dofengineer.config delete mode 100644 hw/bsp/mc02/drivers/armtoolbox/CMakeLists.txt delete mode 100644 hw/bsp/mc02/drivers/bsp_def.h delete mode 100644 hw/bsp/mc02/drivers/bsp_dwt.c delete mode 100644 hw/bsp/mc02/drivers/bsp_dwt.h create mode 100644 hw/mcu/st/cmake/mcu_stm32h7.cmake create mode 160000 hw/mcu/st/cmsis_device_h7 create mode 160000 hw/mcu/st/stm32h7xx_hal_driver diff --git a/.gitmodules b/.gitmodules index 85ed594b..06940abb 100644 --- a/.gitmodules +++ b/.gitmodules @@ -64,3 +64,9 @@ [submodule "lib/eigen"] path = lib/eigen url = https://gitlab.com/libeigen/eigen.git +[submodule "hw/mcu/st/stm32h7xx_hal_driver"] + path = hw/mcu/st/stm32h7xx_hal_driver + url = https://github.com/STMicroelectronics/stm32h7xx_hal_driver.git +[submodule "hw/mcu/st/cmsis_device_h7"] + path = hw/mcu/st/cmsis_device_h7 + url = https://github.com/STMicroelectronics/cmsis_device_h7.git diff --git a/.gitmodules_cn b/.gitmodules_cn index 43209102..5a2f56b4 100644 --- a/.gitmodules_cn +++ b/.gitmodules_cn @@ -64,3 +64,9 @@ [submodule "lib/eigen"] path = lib/eigen url = https://gitee.com/x-robot/eigen.git +[submodule "hw/mcu/st/stm32h7xx_hal_driver"] + path = hw/mcu/st/stm32h7xx_hal_driver + url = https://gitee.com/x-robot/stm32h7xx_hal_driver.git +[submodule "hw/mcu/st/cmsis_device_h7"] + path = hw/mcu/st/cmsis_device_h7 + url = https://gitee.com/x-robot/cmsis_device_h7.git diff --git a/hw/bsp/mc02/config/7dofengineer.config b/hw/bsp/mc02/config/7dofengineer.config deleted file mode 100644 index 7b24dbaf..00000000 --- a/hw/bsp/mc02/config/7dofengineer.config +++ /dev/null @@ -1,142 +0,0 @@ -# CONFIG_auto_generated_config_prefix_board-c-mini is not set -# CONFIG_auto_generated_config_prefix_board-dual_canfd is not set -# CONFIG_auto_generated_config_prefix_board-esp32-c3-arduino is not set -# CONFIG_auto_generated_config_prefix_board-esp32-c3-idf is not set -# CONFIG_auto_generated_config_prefix_board-f103_can is not set -# CONFIG_auto_generated_config_prefix_board-f334_supercap is not set -# CONFIG_auto_generated_config_prefix_board-mangopi_r818 is not set -CONFIG_auto_generated_config_prefix_board-mc02=y -# CONFIG_auto_generated_config_prefix_board-microswitch is not set -# CONFIG_auto_generated_config_prefix_board-MiniPC is not set -# CONFIG_auto_generated_config_prefix_board-MiniPC_with_canfd is not set -# CONFIG_auto_generated_config_prefix_board-node_imu is not set -# CONFIG_auto_generated_config_prefix_board-rm-c is not set -# CONFIG_auto_generated_config_prefix_board-Webots is not set -# CONFIG_auto_generated_config_prefix_system-Bootloader is not set -CONFIG_auto_generated_config_prefix_system-FreeRTOS=y -# CONFIG_auto_generated_config_prefix_system-Linux is not set -# CONFIG_auto_generated_config_prefix_system-Linux_Webots is not set -# CONFIG_auto_generated_config_prefix_system-None is not set - -# -# FreeRTOS -# -CONFIG_INIT_TASK_STACK_DEPTH=1024 -CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=256 -CONFIG_FREERTOS_USB_TASK_STACK_DEPTH=256 -CONFIG_FREERTOS_TERM_TASK_STACK_DEPTH=512 -# end of FreeRTOS - -CONFIG_auto_generated_config_prefix_robot-7DOF_engineer=y -# CONFIG_auto_generated_config_prefix_robot-balance_infantry is not set -# CONFIG_auto_generated_config_prefix_robot-ble_net_config is not set -# CONFIG_auto_generated_config_prefix_robot-blink is not set -# CONFIG_auto_generated_config_prefix_robot-bootloader is not set -# CONFIG_auto_generated_config_prefix_robot-canfd_to_uart is not set -# CONFIG_auto_generated_config_prefix_robot-can_to_uart is not set -# CONFIG_auto_generated_config_prefix_robot-custom_controller is not set -# CONFIG_auto_generated_config_prefix_robot-dart is not set -# CONFIG_auto_generated_config_prefix_robot-dev_7darm is not set -# CONFIG_auto_generated_config_prefix_robot-dev_supercap is not set -# CONFIG_auto_generated_config_prefix_robot-engineer is not set -# CONFIG_auto_generated_config_prefix_robot-hero is not set -# CONFIG_auto_generated_config_prefix_robot-infantry is not set -# CONFIG_auto_generated_config_prefix_robot-microswitch is not set -# CONFIG_auto_generated_config_prefix_robot-sentry is not set -# CONFIG_auto_generated_config_prefix_robot-sim_balance is not set -# CONFIG_auto_generated_config_prefix_robot-sim_mecanum is not set -# CONFIG_auto_generated_config_prefix_robot-uart_net_config is not set -# CONFIG_auto_generated_config_prefix_robot-udp_to_uart is not set -# CONFIG_auto_generated_config_prefix_robot-wearlab_imu is not set -# CONFIG_auto_generated_config_prefix_robot-wheelleg_chassis is not set -# CONFIG_auto_generated_config_prefix_robot-wheelleg_gimbal is not set - -# -# 组件 -# - -# -# 设备 -# -# CONFIG_auto_generated_config_prefix_device-ahrs is not set -# CONFIG_auto_generated_config_prefix_device-ahrs-9 is not set -# CONFIG_auto_generated_config_prefix_device-ai is not set -CONFIG_auto_generated_config_prefix_device-blink_led=y -CONFIG_auto_generated_config_prefix_device-bmi088=y -CONFIG_DEVICE_BMI088_TASK_STACK_DEPTH=256 -# CONFIG_auto_generated_config_prefix_device-buzzer is not set -# CONFIG_auto_generated_config_prefix_device-can is not set -CONFIG_auto_generated_config_prefix_device-canfd=y -# CONFIG_auto_generated_config_prefix_device-cap is not set -# CONFIG_auto_generated_config_prefix_device-custom_controller is not set -CONFIG_auto_generated_config_prefix_device-dr16=y -CONFIG_DEVICE_DR16_TASK_STACK_DEPTH=256 -# CONFIG_auto_generated_config_prefix_device-icm42688 is not set -# CONFIG_auto_generated_config_prefix_device-imu is not set -# CONFIG_auto_generated_config_prefix_device-ina226 is not set -CONFIG_auto_generated_config_prefix_device-ins=y -CONFIG_DEVICE_QEKFIns_TASK_STACK_DEPTH=1024 -# CONFIG_auto_generated_config_prefix_device-laser is not set -# CONFIG_auto_generated_config_prefix_device-led_rgb is not set -# CONFIG_auto_generated_config_prefix_device-mech is not set -# CONFIG_auto_generated_config_prefix_device-microswitch is not set -# CONFIG_auto_generated_config_prefix_device-mmc5603 is not set -CONFIG_auto_generated_config_prefix_device-motor=y -# CONFIG_auto_generated_config_prefix_device-net_config is not set -CONFIG_auto_generated_config_prefix_device-referee=y -CONFIG_DEVICE_REF_TRANS_TASK_STACK_DEPTH=256 -CONFIG_DEVICE_REF_RECV_TASK_STACK_DEPTH=256 - -# -# 裁判系统 -# -# CONFIG_REF_VIRTUAL is not set -CONFIG_REF_LAUNCH_SPEED=30 -CONFIG_REF_HEAT_LIMIT_17=100 -CONFIG_REF_HEAT_LIMIT_42=100 -CONFIG_REF_POWER_LIMIT=200 -CONFIG_REF_POWER_BUFF=100 -# end of 裁判系统 - -# -# 操作手UI -# -CONFIG_UI_DYNAMIC_CYCLE=20 -CONFIG_UI_STATIC_CYCLE=1000 -# end of 操作手UI - -# CONFIG_auto_generated_config_prefix_device-servo is not set -# CONFIG_auto_generated_config_prefix_device-simulator is not set -# CONFIG_auto_generated_config_prefix_device-tof is not set -# end of 设备 - -# -# 模块 -# -CONFIG_auto_generated_config_prefix_module-7DOFARM=y -# CONFIG_auto_generated_config_prefix_module-7dof_arm is not set -# CONFIG_auto_generated_config_prefix_module-balance is not set -# CONFIG_auto_generated_config_prefix_module-ble_net_config is not set -# CONFIG_auto_generated_config_prefix_module-canfd_to_uart is not set -# CONFIG_auto_generated_config_prefix_module-can_imu is not set -# CONFIG_auto_generated_config_prefix_module-can_imu_wearlab is not set -# CONFIG_auto_generated_config_prefix_module-can_usart is not set -# CONFIG_auto_generated_config_prefix_module-chassis is not set -# CONFIG_auto_generated_config_prefix_module-custom_controller is not set -# CONFIG_auto_generated_config_prefix_module-dart_gimbal is not set -# CONFIG_auto_generated_config_prefix_module-dart_launcher is not set -# CONFIG_auto_generated_config_prefix_module-engineer_chassis is not set -# CONFIG_auto_generated_config_prefix_module-free_gimbal is not set -# CONFIG_auto_generated_config_prefix_module-gimbal is not set -# CONFIG_auto_generated_config_prefix_module-launcher is not set -# CONFIG_auto_generated_config_prefix_module-launcher_can is not set -# CONFIG_auto_generated_config_prefix_module-microswitch is not set -# CONFIG_auto_generated_config_prefix_module-ore_collect is not set -# CONFIG_auto_generated_config_prefix_module-performance is not set -# CONFIG_auto_generated_config_prefix_module-super_cap_buck is not set -# CONFIG_auto_generated_config_prefix_module-topic_share_uart is not set -# CONFIG_auto_generated_config_prefix_module-uart_update is not set -# CONFIG_auto_generated_config_prefix_module-wheel_leg is not set -# CONFIG_auto_generated_config_prefix_module-wheel_leg_eigen is not set -# CONFIG_auto_generated_config_prefix_module-wheel_leg_gimbal is not set -# end of 模块 diff --git a/hw/bsp/mc02/config/blink.config b/hw/bsp/mc02/config/blink.config index c74dd3ac..0b0c1b2c 100644 --- a/hw/bsp/mc02/config/blink.config +++ b/hw/bsp/mc02/config/blink.config @@ -3,7 +3,6 @@ # CONFIG_auto_generated_config_prefix_board-esp32-c3-arduino is not set # CONFIG_auto_generated_config_prefix_board-esp32-c3-idf is not set # CONFIG_auto_generated_config_prefix_board-f103_can is not set -# CONFIG_auto_generated_config_prefix_board-f334_supercap is not set # CONFIG_auto_generated_config_prefix_board-mangopi_r818 is not set CONFIG_auto_generated_config_prefix_board-mc02=y # CONFIG_auto_generated_config_prefix_board-microswitch is not set @@ -12,6 +11,10 @@ CONFIG_auto_generated_config_prefix_board-mc02=y # CONFIG_auto_generated_config_prefix_board-node_imu is not set # CONFIG_auto_generated_config_prefix_board-rm-c is not set # CONFIG_auto_generated_config_prefix_board-Webots is not set +# CONFIG_auto_generated_config_prefix_board-canfd_imu_bsp is not set +# CONFIG_auto_generated_config_prefix_board-collar is not set +# CONFIG_auto_generated_config_prefix_board-emg-bsp-stm32g431cb is not set +# CONFIG_auto_generated_config_prefix_board-esp32c3_wifi_imu is not set # CONFIG_auto_generated_config_prefix_system-Bootloader is not set CONFIG_auto_generated_config_prefix_system-FreeRTOS=y # CONFIG_auto_generated_config_prefix_system-Linux is not set @@ -35,9 +38,9 @@ CONFIG_auto_generated_config_prefix_robot-blink=y # CONFIG_auto_generated_config_prefix_robot-can_to_uart is not set # CONFIG_auto_generated_config_prefix_robot-custom_controller is not set # CONFIG_auto_generated_config_prefix_robot-dart is not set -# CONFIG_auto_generated_config_prefix_robot-dev_7darm is not set -# CONFIG_auto_generated_config_prefix_robot-dev_supercap is not set +# CONFIG_auto_generated_config_prefix_robot-drone_gimbal is not set # CONFIG_auto_generated_config_prefix_robot-engineer is not set +# CONFIG_auto_generated_config_prefix_robot-helm_infantry is not set # CONFIG_auto_generated_config_prefix_robot-hero is not set # CONFIG_auto_generated_config_prefix_robot-infantry is not set # CONFIG_auto_generated_config_prefix_robot-microswitch is not set @@ -47,8 +50,8 @@ CONFIG_auto_generated_config_prefix_robot-blink=y # CONFIG_auto_generated_config_prefix_robot-uart_net_config is not set # CONFIG_auto_generated_config_prefix_robot-udp_to_uart is not set # CONFIG_auto_generated_config_prefix_robot-wearlab_imu is not set -# CONFIG_auto_generated_config_prefix_robot-wheelleg_chassis is not set -# CONFIG_auto_generated_config_prefix_robot-wheelleg_gimbal is not set +# CONFIG_auto_generated_config_prefix_robot-robot_collar is not set +# CONFIG_auto_generated_config_prefix_robot-robot_wifi_imu is not set # # 组件 @@ -61,20 +64,18 @@ CONFIG_auto_generated_config_prefix_robot-blink=y # CONFIG_auto_generated_config_prefix_device-ahrs-9 is not set # CONFIG_auto_generated_config_prefix_device-ai is not set CONFIG_auto_generated_config_prefix_device-blink_led=y -CONFIG_auto_generated_config_prefix_device-bmi088=y -CONFIG_DEVICE_BMI088_TASK_STACK_DEPTH=256 +# CONFIG_auto_generated_config_prefix_device-bmi088 is not set +# CONFIG_auto_generated_config_prefix_device-bq27220 is not set # CONFIG_auto_generated_config_prefix_device-buzzer is not set # CONFIG_auto_generated_config_prefix_device-can is not set # CONFIG_auto_generated_config_prefix_device-canfd is not set # CONFIG_auto_generated_config_prefix_device-cap is not set # CONFIG_auto_generated_config_prefix_device-custom_controller is not set -CONFIG_auto_generated_config_prefix_device-dr16=y -CONFIG_DEVICE_DR16_TASK_STACK_DEPTH=256 +# CONFIG_auto_generated_config_prefix_device-dev_bw16 is not set +# CONFIG_auto_generated_config_prefix_device-dr16 is not set # CONFIG_auto_generated_config_prefix_device-icm42688 is not set # CONFIG_auto_generated_config_prefix_device-imu is not set # CONFIG_auto_generated_config_prefix_device-ina226 is not set -CONFIG_auto_generated_config_prefix_device-ins=y -CONFIG_DEVICE_QEKFIns_TASK_STACK_DEPTH=1024 # CONFIG_auto_generated_config_prefix_device-laser is not set # CONFIG_auto_generated_config_prefix_device-led_rgb is not set # CONFIG_auto_generated_config_prefix_device-mech is not set @@ -82,37 +83,19 @@ CONFIG_DEVICE_QEKFIns_TASK_STACK_DEPTH=1024 # CONFIG_auto_generated_config_prefix_device-mmc5603 is not set # CONFIG_auto_generated_config_prefix_device-motor is not set # CONFIG_auto_generated_config_prefix_device-net_config is not set -CONFIG_auto_generated_config_prefix_device-referee=y -CONFIG_DEVICE_REF_TRANS_TASK_STACK_DEPTH=256 -CONFIG_DEVICE_REF_RECV_TASK_STACK_DEPTH=256 - -# -# 裁判系统 -# -# CONFIG_REF_VIRTUAL is not set -CONFIG_REF_LAUNCH_SPEED=30 -CONFIG_REF_HEAT_LIMIT_17=100 -CONFIG_REF_HEAT_LIMIT_42=100 -CONFIG_REF_POWER_LIMIT=200 -CONFIG_REF_POWER_BUFF=100 -# end of 裁判系统 - -# -# 操作手UI -# -CONFIG_UI_DYNAMIC_CYCLE=20 -CONFIG_UI_STATIC_CYCLE=1000 -# end of 操作手UI - +# CONFIG_auto_generated_config_prefix_device-referee is not set # CONFIG_auto_generated_config_prefix_device-servo is not set # CONFIG_auto_generated_config_prefix_device-simulator is not set +# CONFIG_auto_generated_config_prefix_device-spl06_001 is not set # CONFIG_auto_generated_config_prefix_device-tof is not set +# CONFIG_auto_generated_config_prefix_device-dev_gps is not set +# CONFIG_auto_generated_config_prefix_device-dev_net_config_smartconfig is not set +# CONFIG_auto_generated_config_prefix_device-dev_rdss is not set # end of 设备 # # 模块 # -# CONFIG_auto_generated_config_prefix_module-7dof_arm is not set # CONFIG_auto_generated_config_prefix_module-balance is not set # CONFIG_auto_generated_config_prefix_module-ble_net_config is not set # CONFIG_auto_generated_config_prefix_module-canfd_to_uart is not set @@ -124,17 +107,17 @@ CONFIG_UI_STATIC_CYCLE=1000 # CONFIG_auto_generated_config_prefix_module-dart_gimbal is not set # CONFIG_auto_generated_config_prefix_module-dart_launcher is not set # CONFIG_auto_generated_config_prefix_module-engineer_chassis is not set -# CONFIG_auto_generated_config_prefix_module-free_gimbal is not set # CONFIG_auto_generated_config_prefix_module-gimbal is not set +# CONFIG_auto_generated_config_prefix_module-helm_chassis is not set # CONFIG_auto_generated_config_prefix_module-launcher is not set -# CONFIG_auto_generated_config_prefix_module-launcher_can is not set +# CONFIG_auto_generated_config_prefix_module-launcher_drone is not set # CONFIG_auto_generated_config_prefix_module-microswitch is not set # CONFIG_auto_generated_config_prefix_module-ore_collect is not set CONFIG_auto_generated_config_prefix_module-performance=y -# CONFIG_auto_generated_config_prefix_module-super_cap_buck is not set # CONFIG_auto_generated_config_prefix_module-topic_share_uart is not set # CONFIG_auto_generated_config_prefix_module-uart_update is not set # CONFIG_auto_generated_config_prefix_module-wheel_leg is not set -# CONFIG_auto_generated_config_prefix_module-wheel_leg_eigen is not set -# CONFIG_auto_generated_config_prefix_module-wheel_leg_gimbal is not set +# CONFIG_auto_generated_config_prefix_module-canfd_imu is not set +# CONFIG_auto_generated_config_prefix_module-collar_ctrl is not set +# CONFIG_auto_generated_config_prefix_module-mod_research_imu is not set # end of 模块 diff --git a/hw/bsp/mc02/drivers/CMakeLists.txt b/hw/bsp/mc02/drivers/CMakeLists.txt index 341a08d3..05c0530d 100644 --- a/hw/bsp/mc02/drivers/CMakeLists.txt +++ b/hw/bsp/mc02/drivers/CMakeLists.txt @@ -6,13 +6,14 @@ add_library(${PROJECT_NAME} STATIC) target_sources(${PROJECT_NAME} PRIVATE ${${PROJECT_NAME}_SOURCES}) +include(${MCU_DIR}/default/CMakeLists.txt) + target_link_libraries( ${PROJECT_NAME} PRIVATE hal PUBLIC flash PUBLIC rtos PUBLIC usb - PUBLIC armtool ) target_include_directories( @@ -22,13 +23,11 @@ target_include_directories( PUBLIC $ PUBLIC $ PUBLIC $ - PRIVATE $ ) -add_dependencies(${PROJECT_NAME} hal flash rtos usb armtool) +add_dependencies(${PROJECT_NAME} hal flash rtos usb) add_subdirectory(${BOARD_DIR}/drivers/hal) add_subdirectory(${BOARD_DIR}/drivers/rtos) add_subdirectory(${BOARD_DIR}/drivers/usb) add_subdirectory(${BOARD_DIR}/drivers/flash) -add_subdirectory(${BOARD_DIR}/drivers/armtoolbox) diff --git a/hw/bsp/mc02/drivers/armtoolbox/CMakeLists.txt b/hw/bsp/mc02/drivers/armtoolbox/CMakeLists.txt deleted file mode 100644 index 83e233e0..00000000 --- a/hw/bsp/mc02/drivers/armtoolbox/CMakeLists.txt +++ /dev/null @@ -1,26 +0,0 @@ -cmake_minimum_required(VERSION 3.11) -project(armtool) - -add_compile_options(-w) - - -file(GLOB ${PROJECT_NAME}_SOURCES "${LIB_DIR}/arm_toolbox/*.cpp") - -add_library(${PROJECT_NAME} STATIC) - -target_sources(${PROJECT_NAME} -PRIVATE ${${PROJECT_NAME}_SOURCES}) - -target_link_libraries(${PROJECT_NAME} - PRIVATE hal -) - -target_include_directories( - ${PROJECT_NAME} - PUBLIC ${LIB_DIR}/arm_toolbox - PRIVATE $ - ) - -add_dependencies(${PROJECT_NAME} - hal -) diff --git a/hw/bsp/mc02/drivers/bsp.c b/hw/bsp/mc02/drivers/bsp.c index eb832f55..0954d755 100644 --- a/hw/bsp/mc02/drivers/bsp.c +++ b/hw/bsp/mc02/drivers/bsp.c @@ -1,10 +1,10 @@ #include "bsp.h" -#include "bsp_dwt.h" #include "bsp_uart.h" #include "main.h" #include "stm32h7xx_hal_tim.h" #include "stm32h7xx_it.h" + extern TIM_HandleTypeDef htim23; void bsp_init(void) { HAL_Init(); @@ -34,6 +34,5 @@ void bsp_init(void) { MX_USB_OTG_HS_PCD_Init(); MX_TIM7_Init(); MX_SPI6_Init(); - DWT_Init(550); // 喵喵时钟频率550MHz HAL_TIM_Base_Stop_IT(&htim23); } diff --git a/hw/bsp/mc02/drivers/bsp_can.c b/hw/bsp/mc02/drivers/bsp_can.c index cfd67ac0..cc31b786 100644 --- a/hw/bsp/mc02/drivers/bsp_can.c +++ b/hw/bsp/mc02/drivers/bsp_can.c @@ -69,7 +69,7 @@ void bsp_can_init(void) { } can_filter.IdType = FDCAN_EXTENDED_ID; - can_filter.FilterIndex = 1; + can_filter.FilterIndex = 0; can_filter.FilterType = FDCAN_FILTER_MASK; can_filter.FilterConfig = FDCAN_FILTER_TO_RXFIFO0; can_filter.FilterID1 = 0x0000; @@ -84,9 +84,9 @@ void bsp_can_init(void) { }; can_filter.IdType = FDCAN_STANDARD_ID; - can_filter.FilterIndex = 2; + can_filter.FilterIndex = 1; can_filter.FilterType = FDCAN_FILTER_MASK; - can_filter.FilterConfig = FDCAN_FILTER_TO_RXFIFO0; + can_filter.FilterConfig = FDCAN_FILTER_TO_RXFIFO1; can_filter.FilterID1 = 0x0000; can_filter.FilterID2 = 0x0000; if (HAL_FDCAN_ConfigFilter(&hfdcan2, &can_filter) != HAL_OK) { @@ -97,9 +97,9 @@ void bsp_can_init(void) { } can_filter.IdType = FDCAN_EXTENDED_ID; - can_filter.FilterIndex = 3; + can_filter.FilterIndex = 1; can_filter.FilterType = FDCAN_FILTER_MASK; - can_filter.FilterConfig = FDCAN_FILTER_TO_RXFIFO0; + can_filter.FilterConfig = FDCAN_FILTER_TO_RXFIFO1; can_filter.FilterID1 = 0x0000; can_filter.FilterID2 = 0x0000; if (HAL_FDCAN_ConfigFilter(&hfdcan2, &can_filter) != HAL_OK) { @@ -109,23 +109,23 @@ void bsp_can_init(void) { XB_ASSERT(false); } - if (HAL_FDCAN_ConfigGlobalFilter(&hfdcan2, FDCAN_ACCEPT_IN_RX_FIFO0, + if (HAL_FDCAN_ConfigGlobalFilter(&hfdcan2, FDCAN_ACCEPT_IN_RX_FIFO1, FDCAN_REJECT, ENABLE, ENABLE) != HAL_OK) { XB_ASSERT(false); }; - if (HAL_FDCAN_ConfigGlobalFilter(&hfdcan3, FDCAN_ACCEPT_IN_RX_FIFO0, + if (HAL_FDCAN_ConfigGlobalFilter(&hfdcan3, FDCAN_ACCEPT_IN_RX_FIFO1, FDCAN_REJECT, ENABLE, ENABLE) != HAL_OK) { XB_ASSERT(false); }; - HAL_FDCAN_Start(&hfdcan1); //开启FDCAN - HAL_FDCAN_Start(&hfdcan2); //开启FDCAN - HAL_FDCAN_Start(&hfdcan3); //开启FDCAN + HAL_FDCAN_Start(&hfdcan1); // 开启FDCAN + HAL_FDCAN_Start(&hfdcan2); // 开启FDCAN + HAL_FDCAN_Start(&hfdcan3); // 开启FDCAN HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0); HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_TX_FIFO_EMPTY, 0); - HAL_FDCAN_ActivateNotification(&hfdcan2, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0); + HAL_FDCAN_ActivateNotification(&hfdcan2, FDCAN_IT_RX_FIFO1_NEW_MESSAGE, 0); HAL_FDCAN_ActivateNotification(&hfdcan2, FDCAN_IT_TX_FIFO_EMPTY, 0); - HAL_FDCAN_ActivateNotification(&hfdcan3, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0); + HAL_FDCAN_ActivateNotification(&hfdcan3, FDCAN_IT_RX_FIFO1_NEW_MESSAGE, 0); HAL_FDCAN_ActivateNotification(&hfdcan3, FDCAN_IT_TX_FIFO_EMPTY, 0); bsp_can_initd = true; diff --git a/hw/bsp/mc02/drivers/bsp_def.h b/hw/bsp/mc02/drivers/bsp_def.h deleted file mode 100644 index 53d82100..00000000 --- a/hw/bsp/mc02/drivers/bsp_def.h +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "stm32h723xx.h" -#define XB_TO_STR(_arg) #_arg -#define XB_DEF2STR(_arg) XB_TO_STR(_arg) - -#if MCU_DEBUG_BUILD -#define XB_ASSERT(arg) \ - if (!(arg)) \ - while (1) { \ - printf("Assert error at %s:%d\r\n", __FILE__, __LINE__); \ - } -#else -#define XB_ASSERT(arg) (void)0; -#endif - -#define XB_UNUSED(_x) ((void)(_x)) - -#define XB_OFFSET_OF(type, member) ((size_t) & ((type*)0)->member) - -#define XB_MEMBER_SIZE_OF(type, member) (sizeof(typeof(((type*)0)->member))) - -#define XB_CONTAINER_OF(ptr, type, member) \ - ({ \ - const typeof(((type*)0)->member)* __mptr = (ptr); \ - (type*)((char*)__mptr - ms_offset_of(type, member)); \ - }) - -typedef enum { - BSP_OK, - BSP_ERR, - BSP_ERR_NULL, - BSP_ERR_INITED, - BSP_ERR_NO_DEV, - BSP_ERR_BUSY, - BSP_ERR_TIMEOUT, - BSP_ERR_FULL, - BSP_ERR_EMPTY, -} bsp_status_t; - -#ifdef __cplusplus -} -#endif diff --git a/hw/bsp/mc02/drivers/bsp_dwt.c b/hw/bsp/mc02/drivers/bsp_dwt.c deleted file mode 100644 index a55f09d4..00000000 --- a/hw/bsp/mc02/drivers/bsp_dwt.c +++ /dev/null @@ -1,132 +0,0 @@ -/** - ****************************************************************************** - * @file bsp_dwt.c - * @author Wang Hongxi - * @author modified by Neo with annotation - * @version V1.1.0 - * @date 2022/3/8 - * @brief - */ - -#include "bsp_dwt.h" - -static DWT_Time_t SysTime; -static uint32_t CPU_FREQ_Hz, CPU_FREQ_Hz_ms, CPU_FREQ_Hz_us; -static uint32_t CYCCNT_RountCount; -static uint32_t CYCCNT_LAST; -static uint64_t CYCCNT64; - -/** - * @brief 私有函数,用于检查DWT CYCCNT寄存器是否溢出,并更新CYCCNT_RountCount - * @attention 此函数假设两次调用之间的时间间隔不超过一次溢出 - * - * @todo 更好的方案是为dwt的时间更新单独设置一个任务? - * 不过,使用dwt的初衷是定时不被中断/任务等因素影响,因此该实现仍然有其存在的意义 - * - */ -static void DWT_CNT_Update(void) { - static volatile uint8_t bit_locker = 0; - if (!bit_locker) { - bit_locker = 1; - volatile uint32_t cnt_now = DWT->CYCCNT; - if (cnt_now < CYCCNT_LAST) CYCCNT_RountCount++; - - CYCCNT_LAST = DWT->CYCCNT; - bit_locker = 0; - } -} - -void DWT_Init(uint32_t CPU_Freq_mHz) { - /* 使能DWT外设 */ - CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; - - /* DWT CYCCNT寄存器计数清0 */ - DWT->CYCCNT = (uint32_t)0u; - - /* 使能Cortex-M DWT CYCCNT寄存器 */ - DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; - - CPU_FREQ_Hz = CPU_Freq_mHz * 1000000; - CPU_FREQ_Hz_ms = CPU_FREQ_Hz / 1000; - CPU_FREQ_Hz_us = CPU_FREQ_Hz / 1000000; - CYCCNT_RountCount = 0; - - DWT_CNT_Update(); -} - -float DWT_GetDeltaT(uint32_t *cnt_last) { - volatile uint32_t cnt_now = DWT->CYCCNT; - float dt = ((uint32_t)(cnt_now - *cnt_last)) / ((float)(CPU_FREQ_Hz)); - *cnt_last = cnt_now; - - DWT_CNT_Update(); - - return dt; -} -float DWT_GetDeltaT_Constant(uint32_t *cnt_last) { - volatile uint32_t cnt_now = DWT->CYCCNT; - float dt = ((uint32_t)(cnt_now - *cnt_last)) / ((float)(CPU_FREQ_Hz)); - - DWT_CNT_Update(); - - return dt; -} -double DWT_GetDeltaT64(uint32_t *cnt_last) { - volatile uint32_t cnt_now = DWT->CYCCNT; - double dt = ((uint32_t)(cnt_now - *cnt_last)) / ((double)(CPU_FREQ_Hz)); - *cnt_last = cnt_now; - - DWT_CNT_Update(); - - return dt; -} - -void DWT_SysTimeUpdate(void) { - volatile uint32_t cnt_now = DWT->CYCCNT; - static uint64_t CNT_TEMP1, CNT_TEMP2, CNT_TEMP3; - - DWT_CNT_Update(); - - CYCCNT64 = - (uint64_t)CYCCNT_RountCount * (uint64_t)UINT32_MAX + (uint64_t)cnt_now; - CNT_TEMP1 = CYCCNT64 / CPU_FREQ_Hz; - CNT_TEMP2 = CYCCNT64 - CNT_TEMP1 * CPU_FREQ_Hz; - SysTime.s = CNT_TEMP1; - SysTime.ms = CNT_TEMP2 / CPU_FREQ_Hz_ms; - CNT_TEMP3 = CNT_TEMP2 - SysTime.ms * CPU_FREQ_Hz_ms; - SysTime.us = CNT_TEMP3 / CPU_FREQ_Hz_us; -} - -float DWT_GetTimeline_s(void) { - DWT_SysTimeUpdate(); - - float DWT_Timelinef32 = - SysTime.s + SysTime.ms * 0.001f + SysTime.us * 0.000001f; - - return DWT_Timelinef32; -} - -float DWT_GetTimeline_ms(void) { - DWT_SysTimeUpdate(); - - float DWT_Timelinef32 = SysTime.s * 1000 + SysTime.ms + SysTime.us * 0.001f; - - return DWT_Timelinef32; -} - -uint64_t DWT_GetTimeline_us(void) { - DWT_SysTimeUpdate(); - - uint64_t DWT_Timelinef32 = - SysTime.s * 1000000 + SysTime.ms * 1000 + SysTime.us; - - return DWT_Timelinef32; -} - -void DWT_Delay(float Delay) { - uint32_t tickstart = DWT->CYCCNT; - float wait = Delay; - - while ((DWT->CYCCNT - tickstart) < wait * (float)CPU_FREQ_Hz) - ; -} diff --git a/hw/bsp/mc02/drivers/bsp_dwt.h b/hw/bsp/mc02/drivers/bsp_dwt.h deleted file mode 100644 index ddc2deca..00000000 --- a/hw/bsp/mc02/drivers/bsp_dwt.h +++ /dev/null @@ -1,94 +0,0 @@ -#ifndef _BSP_DWT_H -#define _BSP_DWT_H -#ifdef __cplusplus -extern "C" { -#endif - -#include "bsp.h" -#include "stdint.h" -#include "stm32h723xx.h" -typedef struct { - uint32_t s; - uint16_t ms; - uint16_t us; -} DWT_Time_t; - -/** - * @brief 该宏用于计算代码段执行时间,单位为秒/s,返回值为float类型 - * 首先需要创建一个float类型的变量,用于存储时间间隔 - * 计算得到的时间间隔同时还会通过RTT打印到日志终端,你也可以将你的dt变量添加到查看 - */ -#define TIME_ELAPSE(dt, code) \ - do { \ - float tstart = DWT_GetTimeline_s(); \ - code; \ - dt = DWT_GetTimeline_s() - tstart; \ - LOGINFO("[DWT] " #dt " = %f s\r\n", dt); \ - } while (0) - -/** - * @brief 初始化DWT,传入参数为CPU频率,单位MHz - * - * @param CPU_Freq_mHz c板为168MHz,A板为180MHz - */ -void DWT_Init(uint32_t CPU_Freq_mHz); - -/** - * @brief 获取两次调用之间的时间间隔,单位为秒/s - * - * @param cnt_last 上一次调用的时间戳 - * @return float 时间间隔,单位为秒/s - */ -float DWT_GetDeltaT(uint32_t *cnt_last); - -float DWT_GetDeltaT_Constant(uint32_t *cnt_last); - -/** - * @brief 获取两次调用之间的时间间隔,单位为秒/s,高精度 - * - * @param cnt_last 上一次调用的时间戳 - * @return double 时间间隔,单位为秒/s - */ -double DWT_GetDeltaT64(uint32_t *cnt_last); - -/** - * @brief 获取当前时间,单位为秒/s,即初始化后的时间 - * - * @return float 时间轴 - */ -float DWT_GetTimeline_s(void); - -/** - * @brief 获取当前时间,单位为毫秒/ms,即初始化后的时间 - * - * @return float - */ -float DWT_GetTimeline_ms(void); - -/** - * @brief 获取当前时间,单位为微秒/us,即初始化后的时间 - * - * @return uint64_t - */ -uint64_t DWT_GetTimeline_us(void); - -/** - * @brief DWT延时函数,单位为秒/s - * @attention 该函数不受中断是否开启的影响,可以在临界区和关闭中断时使用 - * @note - * 禁止在__disable_irq()和__enable_irq()之间使用HAL_Delay()函数,应使用本函数 - * - * @param Delay 延时时间,单位为秒/s - */ -void DWT_Delay(float Delay); - -/** - * @brief DWT更新时间轴函数,会被三个timeline函数调用 - * @attention - * 如果长时间不调用timeline函数,则需要手动调用该函数更新时间轴,否则CYCCNT溢出后定时和时间轴不准确 - */ -void DWT_SysTimeUpdate(void); -#ifdef __cplusplus -} -#endif -#endif /* BSP_DWT_H_ */ diff --git a/hw/bsp/mc02/drivers/flash/ef_port.c b/hw/bsp/mc02/drivers/flash/ef_port.c index 774da8e8..a51970d5 100644 --- a/hw/bsp/mc02/drivers/flash/ef_port.c +++ b/hw/bsp/mc02/drivers/flash/ef_port.c @@ -33,11 +33,7 @@ /* default environment variables set for user */ /* default environment variables set for user */ -static const ef_env default_env_set[] = { - {"iap_need_copy_app", "0"}, {"iap_copy_app_size", "0"}, - {"stop_in_bootloader", "0"}, {"device_id", "1"}, - {"boot_times", "0"}, -}; +static const ef_env default_env_set[] = {}; /** * Flash port for hardware initialize. diff --git a/hw/bsp/mc02/drivers/flash/w25q64.c b/hw/bsp/mc02/drivers/flash/w25q64.c index defe6efc..f2505fed 100644 --- a/hw/bsp/mc02/drivers/flash/w25q64.c +++ b/hw/bsp/mc02/drivers/flash/w25q64.c @@ -3,717 +3,723 @@ extern OSPI_HandleTypeDef hospi2; /************************************************************************************************* - * : OSPI_W25Qxx_Init - * ڲ: - * ֵ: OSPI_W25Qxx_OK - ʼɹW25Qxx_ERROR_INIT - ʼ - * : ʼ OSPI ãȡW25Q64ID - * ˵ : + * 函 数 名: OSPI_W25Qxx_Init + * 入口参数: 无 + * 返 回 值: OSPI_W25Qxx_OK - 初始化成功,W25Qxx_ERROR_INIT - 初始化错误 + * 函数功能: 初始化 OSPI 配置,读取W25Q64ID + * 说 明: 无 *************************************************************************************************/ int8_t OSPI_W25Qxx_Init(void) { - uint32_t Device_ID; // ID + uint32_t Device_ID; // 器件ID - Device_ID = OSPI_W25Qxx_ReadID(); // ȡID + Device_ID = OSPI_W25Qxx_ReadID(); // 读取器件ID - if (Device_ID == W25Qxx_FLASH_ID) // ƥ + if (Device_ID == W25Qxx_FLASH_ID) // 进行匹配 { // printf ("W25Q64 OK,flash ID:%X\r\n",Device_ID); // - // ʼɹ - return OSPI_W25Qxx_OK; // سɹ־ + // 初始化成功 + return OSPI_W25Qxx_OK; // 返回成功标志 } else { // printf ("W25Q64 ERROR!!!!! ID:%X\r\n",Device_ID); // - // ʼʧ - return W25Qxx_ERROR_INIT; // ش־ + // 初始化失败 + return W25Qxx_ERROR_INIT; // 返回错误标志 } } /************************************************************************************************* - * : OSPI_W25Qxx_AutoPollingMemReady - * ڲ: - * ֵ: OSPI_W25Qxx_OK - ͨW25Qxx_ERROR_AUTOPOLLING - - *ѯȴӦ : ʹԶѯ־ѯȴͨŽ ˵ : - *ÿһͨŶӦõô˺ȴͨŽIJ + * 函 数 名: OSPI_W25Qxx_AutoPollingMemReady + * 入口参数: 无 + * 返 回 值: OSPI_W25Qxx_OK - 通信正常结束,W25Qxx_ERROR_AUTOPOLLING - + *轮询等待无响应 函数功能: 使用自动轮询标志查询,等待通信结束 说 明: + *每一次通信都应该调用此函数,等待通信结束,避免错误的操作 ******************************************************************************************FANKE*****/ int8_t OSPI_W25Qxx_AutoPollingMemReady(void) { - OSPI_RegularCmdTypeDef sCommand; // OSPI - OSPI_AutoPollingTypeDef sConfig; // ѯȽò + OSPI_RegularCmdTypeDef sCommand; // OSPI传输配置 + OSPI_AutoPollingTypeDef sConfig; // 轮询比较相关配置参数 - sCommand.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG; // ͨ + sCommand.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG; // 通用配置 sCommand.FlashId = HAL_OSPI_FLASH_ID_1; // flash ID - sCommand.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE; // 1ָģʽ - sCommand.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS; // ָ8λ + sCommand.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE; // 1线指令模式 + sCommand.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS; // 指令长度8位 sCommand.InstructionDtrMode = - HAL_OSPI_INSTRUCTION_DTR_DISABLE; // ָֹDTRģʽ - sCommand.Address = 0x0; // ַ0 - sCommand.AddressMode = HAL_OSPI_ADDRESS_NONE; // ޵ַģʽ - sCommand.AddressSize = HAL_OSPI_ADDRESS_24_BITS; // ַ24λ - sCommand.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE; // ַֹDTRģʽ - sCommand.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE; // ޽ֽ - sCommand.DataMode = HAL_OSPI_DATA_1_LINE; // 1ģʽ - sCommand.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE; // ֹDTRģʽ - sCommand.NbData = 1; // ͨݳ - sCommand.DummyCycles = 0; // ڸ - sCommand.DQSMode = HAL_OSPI_DQS_DISABLE; // ʹDQS - sCommand.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD; // ÿδݶָ - - sCommand.Instruction = W25Qxx_CMD_ReadStatus_REG1; // ״̬ϢĴ + HAL_OSPI_INSTRUCTION_DTR_DISABLE; // 禁止指令DTR模式 + sCommand.Address = 0x0; // 地址0 + sCommand.AddressMode = HAL_OSPI_ADDRESS_NONE; // 无地址模式 + sCommand.AddressSize = HAL_OSPI_ADDRESS_24_BITS; // 地址长度24位 + sCommand.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE; // 禁止地址DTR模式 + sCommand.AlternateBytesMode = + HAL_OSPI_ALTERNATE_BYTES_NONE; // 无交替字节 + sCommand.DataMode = HAL_OSPI_DATA_1_LINE; // 1线数据模式 + sCommand.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE; // 禁止数据DTR模式 + sCommand.NbData = 1; // 通信数据长度 + sCommand.DummyCycles = 0; // 空周期个数 + sCommand.DQSMode = HAL_OSPI_DQS_DISABLE; // 不使用DQS + sCommand.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD; // 每次传输数据都发送指令 + + sCommand.Instruction = W25Qxx_CMD_ReadStatus_REG1; // 读状态信息寄存器 if (HAL_OSPI_Command(&hospi2, &sCommand, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { - return W25Qxx_ERROR_AUTOPOLLING; // ѯȴӦ + return W25Qxx_ERROR_AUTOPOLLING; // 轮询等待无响应 } - // ͣIJѯ W25Qxx_CMD_ReadStatus_REG1 Ĵȡ״ֽ̬е - // W25Qxx_Status_REG1_BUSY ͣ0Ƚ - // ״̬Ĵ1ĵ0λֻBusy־λڲ/д/дʱᱻ1лͨŽΪ0 + // 不停的查询 W25Qxx_CMD_ReadStatus_REG1 寄存器,将读取到的状态字节中的 + // W25Qxx_Status_REG1_BUSY 不停的与0作比较 + // 读状态寄存器1的第0位(只读),Busy标志位,当正在擦除/写入数据/写命令时会被置1,空闲或通信结束为0 // FANKE - sConfig.Match = 0; // ƥֵ - sConfig.MatchMode = HAL_OSPI_MATCH_MODE_AND; // - sConfig.Interval = 0x10; // ѯ - sConfig.AutomaticStop = HAL_OSPI_AUTOMATIC_STOP_ENABLE; // Զֹͣģʽ + sConfig.Match = 0; // 匹配值 + sConfig.MatchMode = HAL_OSPI_MATCH_MODE_AND; // 与运算 + sConfig.Interval = 0x10; // 轮询间隔 + sConfig.AutomaticStop = HAL_OSPI_AUTOMATIC_STOP_ENABLE; // 自动停止模式 sConfig.Mask = - W25Qxx_Status_REG1_BUSY; // ѯģʽ½յ״ֽ̬ڽΣֻȽҪõλ + W25Qxx_Status_REG1_BUSY; // 对在轮询模式下接收的状态字节进行屏蔽,只比较需要用到的位 - // ѯȴ + // 发送轮询等待命令 if (HAL_OSPI_AutoPolling(&hospi2, &sConfig, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { - return W25Qxx_ERROR_AUTOPOLLING; // ѯȴӦ + return W25Qxx_ERROR_AUTOPOLLING; // 轮询等待无响应 } - return OSPI_W25Qxx_OK; // ͨ + return OSPI_W25Qxx_OK; // 通信正常结束 } /************************************************************************************************* - * : OSPI_W25Qxx_ReadID - * ڲ: - * ֵ: W25Qxx_ID - ȡIDW25Qxx_ERROR_INIT - - *ͨšʼ : ʼ OSPI ãȡID ˵ : + * 函 数 名: OSPI_W25Qxx_ReadID + * 入口参数: 无 + * 返 回 值: W25Qxx_ID - 读取到的器件ID,W25Qxx_ERROR_INIT - + *通信、初始化错误 函数功能: 初始化 OSPI 配置,读取器件ID 说 明: 无 **************************************************************************************************/ uint32_t OSPI_W25Qxx_ReadID(void) { - OSPI_RegularCmdTypeDef sCommand; // OSPI + OSPI_RegularCmdTypeDef sCommand; // OSPI传输配置 - uint8_t OSPI_ReceiveBuff[3]; // 洢OSPI - uint32_t W25Qxx_ID; // ID + uint8_t OSPI_ReceiveBuff[3]; // 存储OSPI读到的数据 + uint32_t W25Qxx_ID; // 器件的ID - sCommand.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG; // ͨ + sCommand.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG; // 通用配置 sCommand.FlashId = HAL_OSPI_FLASH_ID_1; // flash ID - sCommand.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE; // 1ָģʽ - sCommand.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS; // ָ8λ + sCommand.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE; // 1线指令模式 + sCommand.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS; // 指令长度8位 sCommand.InstructionDtrMode = - HAL_OSPI_INSTRUCTION_DTR_DISABLE; // ָֹDTRģʽ - sCommand.AddressMode = HAL_OSPI_ADDRESS_NONE; // ޵ַģʽ - sCommand.AddressSize = HAL_OSPI_ADDRESS_24_BITS; // ַ24λ - sCommand.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE; // ޽ֽ - sCommand.DataMode = HAL_OSPI_DATA_1_LINE; // 1ģʽ - sCommand.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE; // ֹDTRģʽ - sCommand.NbData = 3; // ݵij - sCommand.DummyCycles = 0; // ڸ - sCommand.DQSMode = HAL_OSPI_DQS_DISABLE; // ʹDQS - sCommand.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD; // ÿδݶָ - - sCommand.Instruction = W25Qxx_CMD_JedecID; // ִжID + HAL_OSPI_INSTRUCTION_DTR_DISABLE; // 禁止指令DTR模式 + sCommand.AddressMode = HAL_OSPI_ADDRESS_NONE; // 无地址模式 + sCommand.AddressSize = HAL_OSPI_ADDRESS_24_BITS; // 地址长度24位 + sCommand.AlternateBytesMode = + HAL_OSPI_ALTERNATE_BYTES_NONE; // 无交替字节 + sCommand.DataMode = HAL_OSPI_DATA_1_LINE; // 1线数据模式 + sCommand.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE; // 禁止数据DTR模式 + sCommand.NbData = 3; // 传输数据的长度 + sCommand.DummyCycles = 0; // 空周期个数 + sCommand.DQSMode = HAL_OSPI_DQS_DISABLE; // 不使用DQS + sCommand.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD; // 每次传输数据都发送指令 + + sCommand.Instruction = W25Qxx_CMD_JedecID; // 执行读器件ID命令 HAL_OSPI_Command(&hospi2, &sCommand, - HAL_OSPI_TIMEOUT_DEFAULT_VALUE); // ָ + HAL_OSPI_TIMEOUT_DEFAULT_VALUE); // 发送指令 HAL_OSPI_Receive(&hospi2, OSPI_ReceiveBuff, - HAL_OSPI_TIMEOUT_DEFAULT_VALUE); // + HAL_OSPI_TIMEOUT_DEFAULT_VALUE); // 接收数据 W25Qxx_ID = (OSPI_ReceiveBuff[0] << 16) | (OSPI_ReceiveBuff[1] << 8) | - OSPI_ReceiveBuff[2]; // õϳID + OSPI_ReceiveBuff[2]; // 将得到的数据组合成ID - return W25Qxx_ID; // ID + return W25Qxx_ID; // 返回ID } /************************************************************************************************* - * : OSPI_W25Qxx_MemoryMappedMode - * ڲ: - * ֵ: OSPI_W25Qxx_OK - дʹܳɹW25Qxx_ERROR_WriteEnable - - *дʹʧ : OSPIΪڴӳģʽ ˵ : + * 函 数 名: OSPI_W25Qxx_MemoryMappedMode + * 入口参数: 无 + * 返 回 值: OSPI_W25Qxx_OK - 写使能成功,W25Qxx_ERROR_WriteEnable - + *写使能失败 函数功能: 将OSPI设置为内存映射模式 说 明: 无 **************************************************************************************************/ int8_t OSPI_W25Qxx_MemoryMappedMode(void) { - OSPI_RegularCmdTypeDef sCommand; // QSPI - OSPI_MemoryMappedTypeDef sMemMappedCfg; // ڴӳʲ + OSPI_RegularCmdTypeDef sCommand; // QSPI传输配置 + OSPI_MemoryMappedTypeDef sMemMappedCfg; // 内存映射访问参数 - sCommand.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG; // ͨ + sCommand.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG; // 通用配置 sCommand.FlashId = HAL_OSPI_FLASH_ID_1; // flash ID sCommand.Instruction = - W25Qxx_CMD_FastReadQuad_IO; // 1-4-4ģʽ(1ָ4ߵַ4)ٶȡָ - sCommand.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE; // 1ָģʽ - sCommand.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS; // ָ8λ + W25Qxx_CMD_FastReadQuad_IO; // 1-4-4模式下(1线指令4线地址4线数据),快速读取指令 + sCommand.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE; // 1线指令模式 + sCommand.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS; // 指令长度8位 sCommand.InstructionDtrMode = - HAL_OSPI_INSTRUCTION_DTR_DISABLE; // ָֹDTRģʽ + HAL_OSPI_INSTRUCTION_DTR_DISABLE; // 禁止指令DTR模式 - sCommand.AddressMode = HAL_OSPI_ADDRESS_4_LINES; // 4ߵַģʽ - sCommand.AddressSize = HAL_OSPI_ADDRESS_24_BITS; // ַ24λ - sCommand.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE; // ַֹDTRģʽ + sCommand.AddressMode = HAL_OSPI_ADDRESS_4_LINES; // 4线地址模式 + sCommand.AddressSize = HAL_OSPI_ADDRESS_24_BITS; // 地址长度24位 + sCommand.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE; // 禁止地址DTR模式 - sCommand.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE; // ޽ֽ + sCommand.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE; // 无交替字节 sCommand.AlternateBytesDtrMode = - HAL_OSPI_ALTERNATE_BYTES_DTR_DISABLE; // ֹֽDTRģʽ + HAL_OSPI_ALTERNATE_BYTES_DTR_DISABLE; // 禁止替字节DTR模式 - sCommand.DataMode = HAL_OSPI_DATA_4_LINES; // 4ģʽ - sCommand.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE; // ֹDTRģʽ + sCommand.DataMode = HAL_OSPI_DATA_4_LINES; // 4线数据模式 + sCommand.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE; // 禁止数据DTR模式 - sCommand.DummyCycles = 6; // ڸ - sCommand.DQSMode = HAL_OSPI_DQS_DISABLE; // ʹDQS - sCommand.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD; // ÿδݶָ + sCommand.DummyCycles = 6; // 空周期个数 + sCommand.DQSMode = HAL_OSPI_DQS_DISABLE; // 不使用DQS + sCommand.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD; // 每次传输数据都发送指令 - // д + // 写配置 if (HAL_OSPI_Command(&hospi2, &sCommand, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { - return W25Qxx_ERROR_TRANSMIT; // ݴ + return W25Qxx_ERROR_TRANSMIT; // 传输数据错误 } sMemMappedCfg.TimeOutActivation = - HAL_OSPI_TIMEOUT_COUNTER_DISABLE; // óʱ, nCS ּ״̬ - sMemMappedCfg.TimeOutPeriod = 0; // ʱж - // ڴӳģʽ - if (HAL_OSPI_MemoryMapped(&hospi2, &sMemMappedCfg) != HAL_OK) // + HAL_OSPI_TIMEOUT_COUNTER_DISABLE; // 禁用超时计数器, nCS 保持激活状态 + sMemMappedCfg.TimeOutPeriod = 0; // 超时判断周期 + // 开启内存映射模式 + if (HAL_OSPI_MemoryMapped(&hospi2, &sMemMappedCfg) != HAL_OK) // 进行配置 { - return W25Qxx_ERROR_MemoryMapped; // ڴӳģʽ + return W25Qxx_ERROR_MemoryMapped; // 设置内存映射模式错误 } - return OSPI_W25Qxx_OK; // óɹ + return OSPI_W25Qxx_OK; // 配置成功 } /************************************************************************************************* - * : OSPI_W25Qxx_WriteEnable - * ڲ: - * ֵ: OSPI_W25Qxx_OK - дʹܳɹW25Qxx_ERROR_WriteEnable - - *дʹʧ : дʹ ˵ : + * 函 数 名: OSPI_W25Qxx_WriteEnable + * 入口参数: 无 + * 返 回 值: OSPI_W25Qxx_OK - 写使能成功,W25Qxx_ERROR_WriteEnable - + *写使能失败 函数功能: 发送写使能命令 说 明: 无 **************************************************************************************************/ int8_t OSPI_W25Qxx_WriteEnable(void) { - OSPI_RegularCmdTypeDef sCommand; // OSPI - OSPI_AutoPollingTypeDef sConfig; // ѯȽò + OSPI_RegularCmdTypeDef sCommand; // OSPI传输配置 + OSPI_AutoPollingTypeDef sConfig; // 轮询比较相关配置参数 - sCommand.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG; // ͨ + sCommand.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG; // 通用配置 sCommand.FlashId = HAL_OSPI_FLASH_ID_1; // flash ID - sCommand.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE; // 1ָģʽ - sCommand.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS; // ָ8λ + sCommand.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE; // 1线指令模式 + sCommand.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS; // 指令长度8位 sCommand.InstructionDtrMode = - HAL_OSPI_INSTRUCTION_DTR_DISABLE; // ָֹDTRģʽ - sCommand.Address = 0; // ַ0 - sCommand.AddressMode = HAL_OSPI_ADDRESS_NONE; // ޵ַģʽ - sCommand.AddressSize = HAL_OSPI_ADDRESS_24_BITS; // ַ24λ - sCommand.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE; // ַֹDTRģʽ + HAL_OSPI_INSTRUCTION_DTR_DISABLE; // 禁止指令DTR模式 + sCommand.Address = 0; // 地址0 + sCommand.AddressMode = HAL_OSPI_ADDRESS_NONE; // 无地址模式 + sCommand.AddressSize = HAL_OSPI_ADDRESS_24_BITS; // 地址长度24位 + sCommand.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE; // 禁止地址DTR模式 sCommand.AlternateBytesDtrMode = - HAL_OSPI_ALTERNATE_BYTES_DTR_DISABLE; // ֹֽDTRģʽ - sCommand.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE; // ޽ֽ - sCommand.DataMode = HAL_OSPI_DATA_NONE; // ģʽ - sCommand.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE; // ֹDTRģʽ - sCommand.DummyCycles = 0; // ڸ - sCommand.DQSMode = HAL_OSPI_DQS_DISABLE; // ʹDQS - sCommand.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD; // ÿδݶָ + HAL_OSPI_ALTERNATE_BYTES_DTR_DISABLE; // 禁止替字节DTR模式 + sCommand.AlternateBytesMode = + HAL_OSPI_ALTERNATE_BYTES_NONE; // 无交替字节 + sCommand.DataMode = HAL_OSPI_DATA_NONE; // 无数据模式 + sCommand.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE; // 禁止数据DTR模式 + sCommand.DummyCycles = 0; // 空周期个数 + sCommand.DQSMode = HAL_OSPI_DQS_DISABLE; // 不使用DQS + sCommand.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD; // 每次传输数据都发送指令 - sCommand.Instruction = W25Qxx_CMD_WriteEnable; // дʹ + sCommand.Instruction = W25Qxx_CMD_WriteEnable; // 写使能命令 - // дʹ + // 发送写使能命令 if (HAL_OSPI_Command(&hospi2, &sCommand, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return W25Qxx_ERROR_WriteEnable; } - // Ͳѯ״̬Ĵ - sCommand.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG; // ͨ + // 发送查询状态寄存器命令 + sCommand.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG; // 通用配置 sCommand.FlashId = HAL_OSPI_FLASH_ID_1; // flash ID - sCommand.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE; // 1ָģʽ - sCommand.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS; // ָ8λ + sCommand.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE; // 1线指令模式 + sCommand.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS; // 指令长度8位 sCommand.InstructionDtrMode = - HAL_OSPI_INSTRUCTION_DTR_DISABLE; // ָֹDTRģʽ - sCommand.AddressMode = HAL_OSPI_ADDRESS_NONE; // ޵ַģʽ - sCommand.AlternateBytesMode = - HAL_OSPI_ALTERNATE_BYTES_NONE; // ޽ֽ - sCommand.DummyCycles = 0; // ڸ - sCommand.DQSMode = HAL_OSPI_DQS_DISABLE; // ʹDQS - sCommand.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD; // ÿδݶָ - sCommand.DataMode = HAL_OSPI_DATA_1_LINE; // 1ģʽ - sCommand.NbData = 1; // ͨݳ + HAL_OSPI_INSTRUCTION_DTR_DISABLE; // 禁止指令DTR模式 + sCommand.AddressMode = HAL_OSPI_ADDRESS_NONE; // 无地址模式 + sCommand.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE; // 无交替字节 + sCommand.DummyCycles = 0; // 空周期个数 + sCommand.DQSMode = HAL_OSPI_DQS_DISABLE; // 不使用DQS + sCommand.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD; // 每次传输数据都发送指令 + sCommand.DataMode = HAL_OSPI_DATA_1_LINE; // 1线数据模式 + sCommand.NbData = 1; // 通信数据长度 - sCommand.Instruction = W25Qxx_CMD_ReadStatus_REG1; // ѯ״̬Ĵ + sCommand.Instruction = W25Qxx_CMD_ReadStatus_REG1; // 查询状态寄存器命令 if (HAL_OSPI_Command(&hospi2, &sCommand, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return W25Qxx_ERROR_WriteEnable; } - // ͣIJѯ W25Qxx_CMD_ReadStatus_REG1 Ĵȡ״ֽ̬е - // W25Qxx_Status_REG1_WEL ͣ 0x02 Ƚ - // ״̬Ĵ1ĵ1λֻWELдʹܱ־λñ־λΪ1ʱԽд + // 不停的查询 W25Qxx_CMD_ReadStatus_REG1 寄存器,将读取到的状态字节中的 + // W25Qxx_Status_REG1_WEL 不停的与 0x02 作比较 + // 读状态寄存器1的第1位(只读),WEL写使能标志位,该标志位为1时,代表可以进行写操作 // FANKE 7B0 - sConfig.Match = 0x02; // ƥֵ - sConfig.MatchMode = HAL_OSPI_MATCH_MODE_AND; // - sConfig.Interval = 0x10; // ѯ - sConfig.AutomaticStop = HAL_OSPI_AUTOMATIC_STOP_ENABLE; // Զֹͣģʽ + sConfig.Match = 0x02; // 匹配值 + sConfig.MatchMode = HAL_OSPI_MATCH_MODE_AND; // 与运算 + sConfig.Interval = 0x10; // 轮询间隔 + sConfig.AutomaticStop = HAL_OSPI_AUTOMATIC_STOP_ENABLE; // 自动停止模式 sConfig.Mask = - W25Qxx_Status_REG1_WEL; // ѯģʽ½յ״ֽ̬ڽΣֻȽҪõλ + W25Qxx_Status_REG1_WEL; // 对在轮询模式下接收的状态字节进行屏蔽,只比较需要用到的位 if (HAL_OSPI_AutoPolling(&hospi2, &sConfig, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { - return W25Qxx_ERROR_AUTOPOLLING; // ѯȴӦ + return W25Qxx_ERROR_AUTOPOLLING; // 轮询等待无响应 } - return OSPI_W25Qxx_OK; // ͨ + return OSPI_W25Qxx_OK; // 通信正常结束 } /************************************************************************************************* * - * : OSPI_W25Qxx_SectorErase + * 函 数 名: OSPI_W25Qxx_SectorErase * - * ڲ: SectorAddress - Ҫĵַ + * 入口参数: SectorAddress - 要擦除的地址 * - * ֵ: OSPI_W25Qxx_OK - ɹ - * W25Qxx_ERROR_Erase - ʧ - * W25Qxx_ERROR_AUTOPOLLING - ѯȴӦ + * 返 回 值: OSPI_W25Qxx_OK - 擦除成功 + * W25Qxx_ERROR_Erase - 擦除失败 + * W25Qxx_ERROR_AUTOPOLLING - 轮询等待无响应 * - * : ÿβ4Kֽ + * 函数功能: 进行扇区擦除操作,每次擦除4K字节 * - * ˵ : 1. W25Q64JV ֲIJοʱ䣬ֵΪ - *45msֵΪ400ms 2.ʵʵIJٶȿܴ45msҲС45ms - * 3.flashʹõʱԽʱҲԽ + * 说 明: 1.按照 W25Q64JV 数据手册给出的擦除参考时间,典型值为 + *45ms,最大值为400ms 2.实际的擦除速度可能大于45ms,也可能小于45ms + * 3.flash使用的时间越长,擦除所需时间也会越长 * **************************************************************************************************/ int8_t OSPI_W25Qxx_SectorErase(uint32_t SectorAddress) { - OSPI_RegularCmdTypeDef sCommand; // OSPI + OSPI_RegularCmdTypeDef sCommand; // OSPI传输配置 - sCommand.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG; // ͨ + sCommand.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG; // 通用配置 sCommand.FlashId = HAL_OSPI_FLASH_ID_1; // flash ID - sCommand.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE; // 1ָģʽ - sCommand.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS; // ָ8λ + sCommand.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE; // 1线指令模式 + sCommand.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS; // 指令长度8位 sCommand.InstructionDtrMode = - HAL_OSPI_INSTRUCTION_DTR_DISABLE; // ָֹDTRģʽ - sCommand.Address = SectorAddress; // ַ - sCommand.AddressMode = HAL_OSPI_ADDRESS_1_LINE; // 1ߵַģʽ - sCommand.AddressSize = HAL_OSPI_ADDRESS_24_BITS; // ַ24λ - sCommand.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE; // ַֹDTRģʽ - sCommand.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE; // ޽ֽ - sCommand.DataMode = HAL_OSPI_DATA_NONE; // ģʽ - sCommand.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE; // ֹDTRģʽ - sCommand.DummyCycles = 0; // ڸ - sCommand.DQSMode = HAL_OSPI_DQS_DISABLE; // ʹDQS - sCommand.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD; // ÿδݶָ + HAL_OSPI_INSTRUCTION_DTR_DISABLE; // 禁止指令DTR模式 + sCommand.Address = SectorAddress; // 地址 + sCommand.AddressMode = HAL_OSPI_ADDRESS_1_LINE; // 1线地址模式 + sCommand.AddressSize = HAL_OSPI_ADDRESS_24_BITS; // 地址长度24位 + sCommand.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE; // 禁止地址DTR模式 + sCommand.AlternateBytesMode = + HAL_OSPI_ALTERNATE_BYTES_NONE; // 无交替字节 + sCommand.DataMode = HAL_OSPI_DATA_NONE; // 无数据模式 + sCommand.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE; // 禁止数据DTR模式 + sCommand.DummyCycles = 0; // 空周期个数 + sCommand.DQSMode = HAL_OSPI_DQS_DISABLE; // 不使用DQS + sCommand.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD; // 每次传输数据都发送指令 sCommand.Instruction = - W25Qxx_CMD_SectorErase; // ָÿβ4Kֽ + W25Qxx_CMD_SectorErase; // 扇区擦除指令,每次擦除4K字节 - // дʹ + // 发送写使能 if (OSPI_W25Qxx_WriteEnable() != OSPI_W25Qxx_OK) { - return W25Qxx_ERROR_WriteEnable; // дʹʧ + return W25Qxx_ERROR_WriteEnable; // 写使能失败 } - // Ͳָ + // 发送擦除指令 if (HAL_OSPI_Command(&hospi2, &sCommand, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { - return W25Qxx_ERROR_AUTOPOLLING; // ѯȴӦ + return W25Qxx_ERROR_AUTOPOLLING; // 轮询等待无响应 } - // ʹԶѯ־λȴĽ + // 使用自动轮询标志位,等待擦除的结束 if (OSPI_W25Qxx_AutoPollingMemReady() != OSPI_W25Qxx_OK) { - return W25Qxx_ERROR_AUTOPOLLING; // ѯȴӦ + return W25Qxx_ERROR_AUTOPOLLING; // 轮询等待无响应 } - return OSPI_W25Qxx_OK; // ɹ + return OSPI_W25Qxx_OK; // 擦除成功 } /************************************************************************************************* * - * : OSPI_W25Qxx_BlockErase_32K + * 函 数 名: OSPI_W25Qxx_BlockErase_32K * - * ڲ: SectorAddress - Ҫĵַ + * 入口参数: SectorAddress - 要擦除的地址 * - * ֵ: OSPI_W25Qxx_OK - ɹ - * W25Qxx_ERROR_Erase - ʧ - * W25Qxx_ERROR_AUTOPOLLING - ѯȴӦ + * 返 回 值: OSPI_W25Qxx_OK - 擦除成功 + * W25Qxx_ERROR_Erase - 擦除失败 + * W25Qxx_ERROR_AUTOPOLLING - 轮询等待无响应 * - * : пÿβ32Kֽ + * 函数功能: 进行块擦除操作,每次擦除32K字节 * - * ˵ : 1. W25Q64JV ֲIJοʱ䣬ֵΪ - *120msֵΪ1600ms 2.ʵʵIJٶȿܴ120msҲС120ms - * 3.flashʹõʱԽʱҲԽ + * 说 明: 1.按照 W25Q64JV 数据手册给出的擦除参考时间,典型值为 + *120ms,最大值为1600ms 2.实际的擦除速度可能大于120ms,也可能小于120ms + * 3.flash使用的时间越长,擦除所需时间也会越长 * *************************************************************************************************/ int8_t OSPI_W25Qxx_BlockErase_32K(uint32_t SectorAddress) { - OSPI_RegularCmdTypeDef sCommand; // OSPI + OSPI_RegularCmdTypeDef sCommand; // OSPI传输配置 - sCommand.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG; // ͨ + sCommand.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG; // 通用配置 sCommand.FlashId = HAL_OSPI_FLASH_ID_1; // flash ID - sCommand.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE; // 1ָģʽ - sCommand.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS; // ָ8λ + sCommand.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE; // 1线指令模式 + sCommand.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS; // 指令长度8位 sCommand.InstructionDtrMode = - HAL_OSPI_INSTRUCTION_DTR_DISABLE; // ָֹDTRģʽ - sCommand.Address = SectorAddress; // ַ - sCommand.AddressMode = HAL_OSPI_ADDRESS_1_LINE; // 1ߵַģʽ - sCommand.AddressSize = HAL_OSPI_ADDRESS_24_BITS; // ַ24λ - sCommand.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE; // ַֹDTRģʽ - sCommand.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE; // ޽ֽ - sCommand.DataMode = HAL_OSPI_DATA_NONE; // ģʽ - sCommand.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE; // ֹDTRģʽ - sCommand.DummyCycles = 0; // ڸ - sCommand.DQSMode = HAL_OSPI_DQS_DISABLE; // ʹDQS - sCommand.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD; // ÿδݶָ + HAL_OSPI_INSTRUCTION_DTR_DISABLE; // 禁止指令DTR模式 + sCommand.Address = SectorAddress; // 地址 + sCommand.AddressMode = HAL_OSPI_ADDRESS_1_LINE; // 1线地址模式 + sCommand.AddressSize = HAL_OSPI_ADDRESS_24_BITS; // 地址长度24位 + sCommand.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE; // 禁止地址DTR模式 + sCommand.AlternateBytesMode = + HAL_OSPI_ALTERNATE_BYTES_NONE; // 无交替字节 + sCommand.DataMode = HAL_OSPI_DATA_NONE; // 无数据模式 + sCommand.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE; // 禁止数据DTR模式 + sCommand.DummyCycles = 0; // 空周期个数 + sCommand.DQSMode = HAL_OSPI_DQS_DISABLE; // 不使用DQS + sCommand.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD; // 每次传输数据都发送指令 sCommand.Instruction = - W25Qxx_CMD_BlockErase_32K; // ָÿβ32Kֽ + W25Qxx_CMD_BlockErase_32K; // 块擦除指令,每次擦除32K字节 - // дʹ + // 发送写使能 if (OSPI_W25Qxx_WriteEnable() != OSPI_W25Qxx_OK) { - return W25Qxx_ERROR_WriteEnable; // дʹʧ + return W25Qxx_ERROR_WriteEnable; // 写使能失败 } - // Ͳָ + // 发送擦除指令 if (HAL_OSPI_Command(&hospi2, &sCommand, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { - return W25Qxx_ERROR_AUTOPOLLING; // ѯȴӦ + return W25Qxx_ERROR_AUTOPOLLING; // 轮询等待无响应 } - // ʹԶѯ־λȴĽ + // 使用自动轮询标志位,等待擦除的结束 if (OSPI_W25Qxx_AutoPollingMemReady() != OSPI_W25Qxx_OK) { - return W25Qxx_ERROR_AUTOPOLLING; // ѯȴӦ + return W25Qxx_ERROR_AUTOPOLLING; // 轮询等待无响应 } - return OSPI_W25Qxx_OK; // ɹ + return OSPI_W25Qxx_OK; // 擦除成功 } /************************************************************************************************* * - * : OSPI_W25Qxx_BlockErase_64K + * 函 数 名: OSPI_W25Qxx_BlockErase_64K * - * ڲ: SectorAddress - Ҫĵַ + * 入口参数: SectorAddress - 要擦除的地址 * - * ֵ: OSPI_W25Qxx_OK - ɹ - * W25Qxx_ERROR_Erase - ʧ - * W25Qxx_ERROR_AUTOPOLLING - ѯȴӦ + * 返 回 值: OSPI_W25Qxx_OK - 擦除成功 + * W25Qxx_ERROR_Erase - 擦除失败 + * W25Qxx_ERROR_AUTOPOLLING - 轮询等待无响应 * - * : пÿβ64Kֽ + * 函数功能: 进行块擦除操作,每次擦除64K字节 * - * ˵ : 1. W25Q64JV ֲIJοʱ䣬ֵΪ - *150msֵΪ2000ms 2.ʵʵIJٶȿܴ150msҲС150ms - * 3.flashʹõʱԽʱҲԽ - * 4.ʵʹýʹ64Kʱ + * 说 明: 1.按照 W25Q64JV 数据手册给出的擦除参考时间,典型值为 + *150ms,最大值为2000ms 2.实际的擦除速度可能大于150ms,也可能小于150ms + * 3.flash使用的时间越长,擦除所需时间也会越长 + * 4.实际使用建议使用64K擦除,擦除的时间最快 * **************************************************************************************************/ int8_t OSPI_W25Qxx_BlockErase_64K(uint32_t SectorAddress) { - OSPI_RegularCmdTypeDef sCommand; // OSPI + OSPI_RegularCmdTypeDef sCommand; // OSPI传输配置 - sCommand.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG; // ͨ + sCommand.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG; // 通用配置 sCommand.FlashId = HAL_OSPI_FLASH_ID_1; // flash ID - sCommand.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE; // 1ָģʽ - sCommand.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS; // ָ8λ + sCommand.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE; // 1线指令模式 + sCommand.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS; // 指令长度8位 sCommand.InstructionDtrMode = - HAL_OSPI_INSTRUCTION_DTR_DISABLE; // ָֹDTRģʽ - sCommand.Address = SectorAddress; // ַ - sCommand.AddressMode = HAL_OSPI_ADDRESS_1_LINE; // 1ߵַģʽ - sCommand.AddressSize = HAL_OSPI_ADDRESS_24_BITS; // ַ24λ - sCommand.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE; // ַֹDTRģʽ - sCommand.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE; // ޽ֽ - sCommand.DataMode = HAL_OSPI_DATA_NONE; // ģʽ - sCommand.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE; // ֹDTRģʽ - sCommand.DummyCycles = 0; // ڸ - sCommand.DQSMode = HAL_OSPI_DQS_DISABLE; // ʹDQS - sCommand.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD; // ÿδݶָ + HAL_OSPI_INSTRUCTION_DTR_DISABLE; // 禁止指令DTR模式 + sCommand.Address = SectorAddress; // 地址 + sCommand.AddressMode = HAL_OSPI_ADDRESS_1_LINE; // 1线地址模式 + sCommand.AddressSize = HAL_OSPI_ADDRESS_24_BITS; // 地址长度24位 + sCommand.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE; // 禁止地址DTR模式 + sCommand.AlternateBytesMode = + HAL_OSPI_ALTERNATE_BYTES_NONE; // 无交替字节 + sCommand.DataMode = HAL_OSPI_DATA_NONE; // 无数据模式 + sCommand.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE; // 禁止数据DTR模式 + sCommand.DummyCycles = 0; // 空周期个数 + sCommand.DQSMode = HAL_OSPI_DQS_DISABLE; // 不使用DQS + sCommand.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD; // 每次传输数据都发送指令 sCommand.Instruction = - W25Qxx_CMD_BlockErase_64K; // ָÿβ64Kֽ + W25Qxx_CMD_BlockErase_64K; // 扇区擦除指令,每次擦除64K字节 - // дʹ + // 发送写使能 if (OSPI_W25Qxx_WriteEnable() != OSPI_W25Qxx_OK) { - return W25Qxx_ERROR_WriteEnable; // дʹʧ + return W25Qxx_ERROR_WriteEnable; // 写使能失败 } - // Ͳָ + // 发送擦除指令 if (HAL_OSPI_Command(&hospi2, &sCommand, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { - return W25Qxx_ERROR_AUTOPOLLING; // ѯȴӦ + return W25Qxx_ERROR_AUTOPOLLING; // 轮询等待无响应 } - // ʹԶѯ־λȴĽ + // 使用自动轮询标志位,等待擦除的结束 if (OSPI_W25Qxx_AutoPollingMemReady() != OSPI_W25Qxx_OK) { - return W25Qxx_ERROR_AUTOPOLLING; // ѯȴӦ + return W25Qxx_ERROR_AUTOPOLLING; // 轮询等待无响应 } - return OSPI_W25Qxx_OK; // ɹ + return OSPI_W25Qxx_OK; // 擦除成功 } /************************************************************************************************* * - * : OSPI_W25Qxx_ChipErase + * 函 数 名: OSPI_W25Qxx_ChipErase * - * ڲ: + * 入口参数: 无 * - * ֵ: OSPI_W25Qxx_OK - ɹ - * W25Qxx_ERROR_Erase - ʧ - * W25Qxx_ERROR_AUTOPOLLING - ѯȴӦ + * 返 回 值: OSPI_W25Qxx_OK - 擦除成功 + * W25Qxx_ERROR_Erase - 擦除失败 + * W25Qxx_ERROR_AUTOPOLLING - 轮询等待无响应 * - * : Ƭ + * 函数功能: 进行整片擦除操作 * - * ˵ : 1. W25Q64JV ֲIJοʱ䣬ֵΪ - *20sֵΪ100s 2.ʵʵIJٶȿܴ20sҲС20s - * 3.flashʹõʱԽʱҲԽ + * 说 明: 1.按照 W25Q64JV 数据手册给出的擦除参考时间,典型值为 + *20s,最大值为100s 2.实际的擦除速度可能大于20s,也可能小于20s + * 3.flash使用的时间越长,擦除所需时间也会越长 * *************************************************************************************************/ int8_t OSPI_W25Qxx_ChipErase(void) { - OSPI_RegularCmdTypeDef sCommand; // OSPI - OSPI_AutoPollingTypeDef sConfig; // ѯȽò + OSPI_RegularCmdTypeDef sCommand; // OSPI传输配置 + OSPI_AutoPollingTypeDef sConfig; // 轮询比较相关配置参数 - sCommand.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG; // ͨ + sCommand.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG; // 通用配置 sCommand.FlashId = HAL_OSPI_FLASH_ID_1; // flash ID - sCommand.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE; // 1ָģʽ - sCommand.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS; // ָ8λ + sCommand.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE; // 1线指令模式 + sCommand.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS; // 指令长度8位 sCommand.InstructionDtrMode = - HAL_OSPI_INSTRUCTION_DTR_DISABLE; // ָֹDTRģʽ - sCommand.AddressMode = HAL_OSPI_ADDRESS_NONE; // ޵ַģʽ - sCommand.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE; // ַֹDTRģʽ - sCommand.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE; // ޽ֽ - sCommand.DataMode = HAL_OSPI_DATA_NONE; // ģʽ - sCommand.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE; // ֹDTRģʽ - sCommand.DummyCycles = 0; // ڸ - sCommand.DQSMode = HAL_OSPI_DQS_DISABLE; // ʹDQS - sCommand.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD; // ÿδݶָ - - sCommand.Instruction = W25Qxx_CMD_ChipErase; // ȫƬָ - - // дʹ + HAL_OSPI_INSTRUCTION_DTR_DISABLE; // 禁止指令DTR模式 + sCommand.AddressMode = HAL_OSPI_ADDRESS_NONE; // 无地址模式 + sCommand.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE; // 禁止地址DTR模式 + sCommand.AlternateBytesMode = + HAL_OSPI_ALTERNATE_BYTES_NONE; // 无交替字节 + sCommand.DataMode = HAL_OSPI_DATA_NONE; // 无数据模式 + sCommand.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE; // 禁止数据DTR模式 + sCommand.DummyCycles = 0; // 空周期个数 + sCommand.DQSMode = HAL_OSPI_DQS_DISABLE; // 不使用DQS + sCommand.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD; // 每次传输数据都发送指令 + + sCommand.Instruction = W25Qxx_CMD_ChipErase; // 全片擦除指令 + + // 发送写使能 if (OSPI_W25Qxx_WriteEnable() != OSPI_W25Qxx_OK) { - return W25Qxx_ERROR_WriteEnable; // дʹʧ + return W25Qxx_ERROR_WriteEnable; // 写使能失败 } - // Ͳָ + // 发送擦除指令 if (HAL_OSPI_Command(&hospi2, &sCommand, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { - return W25Qxx_ERROR_AUTOPOLLING; // ѯȴӦ + return W25Qxx_ERROR_AUTOPOLLING; // 轮询等待无响应 } - // Ͳѯ״̬Ĵ - sCommand.DataMode = HAL_OSPI_DATA_1_LINE; // һģʽ - sCommand.NbData = 1; // ݳ1 - sCommand.Instruction = W25Qxx_CMD_ReadStatus_REG1; // ״̬Ĵ + // 发送查询状态寄存器命令 + sCommand.DataMode = HAL_OSPI_DATA_1_LINE; // 一线数据模式 + sCommand.NbData = 1; // 数据长度1 + sCommand.Instruction = W25Qxx_CMD_ReadStatus_REG1; // 状态寄存器命令 if (HAL_OSPI_Command(&hospi2, &sCommand, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return W25Qxx_ERROR_AUTOPOLLING; } - // ͣIJѯ W25Qxx_CMD_ReadStatus_REG1 Ĵȡ״ֽ̬е - // W25Qxx_Status_REG1_BUSY ͣ0Ƚ - // ״̬Ĵ1ĵ0λֻBusy־λڲ/д/дʱᱻ1лͨŽΪ0 + // 不停的查询 W25Qxx_CMD_ReadStatus_REG1 寄存器,将读取到的状态字节中的 + // W25Qxx_Status_REG1_BUSY 不停的与0作比较 + // 读状态寄存器1的第0位(只读),Busy标志位,当正在擦除/写入数据/写命令时会被置1,空闲或通信结束为0 - sConfig.Match = 0; // ƥֵ - sConfig.MatchMode = HAL_OSPI_MATCH_MODE_AND; // - sConfig.Interval = 0x10; // ѯ - sConfig.AutomaticStop = HAL_OSPI_AUTOMATIC_STOP_ENABLE; // Զֹͣģʽ + sConfig.Match = 0; // 匹配值 + sConfig.MatchMode = HAL_OSPI_MATCH_MODE_AND; // 与运算 + sConfig.Interval = 0x10; // 轮询间隔 + sConfig.AutomaticStop = HAL_OSPI_AUTOMATIC_STOP_ENABLE; // 自动停止模式 sConfig.Mask = - W25Qxx_Status_REG1_BUSY; // ѯģʽ½յ״ֽ̬ڽΣֻȽҪõλ + W25Qxx_Status_REG1_BUSY; // 对在轮询模式下接收的状态字节进行屏蔽,只比较需要用到的位 - // W25Q64ƬĵͲοʱΪ20sʱΪ100sijʱȴֵ - // W25Qxx_ChipErase_TIMEOUT_MAX Ϊ 100S + // W25Q64整片擦除的典型参考时间为20s,最大时间为100s,这里的超时等待值 + // W25Qxx_ChipErase_TIMEOUT_MAX 为 100S if (HAL_OSPI_AutoPolling(&hospi2, &sConfig, W25Qxx_ChipErase_TIMEOUT_MAX) != HAL_OK) { - return W25Qxx_ERROR_AUTOPOLLING; // ѯȴӦ + return W25Qxx_ERROR_AUTOPOLLING; // 轮询等待无响应 } - return OSPI_W25Qxx_OK; // ɹ + return OSPI_W25Qxx_OK; // 擦除成功 } /********************************************************************************************************** * - * : OSPI_W25Qxx_WritePage + * 函 数 名: OSPI_W25Qxx_WritePage * - * ڲ: pBuffer - Ҫд - * WriteAddr - Ҫд W25Qxx ĵַ - * NumByteToWrite - ݳȣֻ256ֽ + * 入口参数: pBuffer - 要写入的数据 + * WriteAddr - 要写入 W25Qxx 的地址 + * NumByteToWrite - 数据长度,最大只能256字节 * - * ֵ: OSPI_W25Qxx_OK - дݳɹ - * W25Qxx_ERROR_WriteEnable - дʹʧ - * W25Qxx_ERROR_TRANSMIT - ʧ - * W25Qxx_ERROR_AUTOPOLLING - ѯȴӦ + * 返 回 值: OSPI_W25Qxx_OK - 写数据成功 + * W25Qxx_ERROR_WriteEnable - 写使能失败 + * W25Qxx_ERROR_TRANSMIT - 传输失败 + * W25Qxx_ERROR_AUTOPOLLING - 轮询等待无响应 * - * : ҳд룬ֻ256ֽڣд֮ǰɲ + * 函数功能: 按页写入,最大只能256字节,在数据写入之前,请务必完成擦除操作 * - * ˵ - *: 1.FlashдʱͲʱһ޶ģ˵OSPIʱ133MͿٶȽд - * 2. W25Q64JV ֲ ҳ(256ֽ) - *дοʱ䣬ֵΪ 0.4msֵΪ3ms - * 3.ʵʵдٶȿܴ0.4msҲС0.4ms - * 4.FlashʹõʱԽдʱҲԽ - * 5.д֮ǰɲ + * 说 + *明: 1.Flash的写入时间和擦除时间一样,是限定的,并不是说OSPI驱动时钟133M就可以以这个速度进行写入 + * 2.按照 W25Q64JV 数据手册给出的 页(256字节) + *写入参考时间,典型值为 0.4ms,最大值为3ms + * 3.实际的写入速度可能大于0.4ms,也可能小于0.4ms + * 4.Flash使用的时间越长,写入所需时间也会越长 + * 5.在数据写入之前,请务必完成擦除操作 * ***********************************************************************************************************/ int8_t OSPI_W25Qxx_WritePage(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite) { - OSPI_RegularCmdTypeDef sCommand; // OSPI + OSPI_RegularCmdTypeDef sCommand; // OSPI传输配置 - sCommand.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG; // ͨ + sCommand.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG; // 通用配置 sCommand.FlashId = HAL_OSPI_FLASH_ID_1; // flash ID sCommand.Instruction = - W25Qxx_CMD_QuadInputPageProgram; // 1-1-4ģʽ(1ָ1ߵַ4)ҳָ - sCommand.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE; // 1ָģʽ - sCommand.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS; // ָ8λ + W25Qxx_CMD_QuadInputPageProgram; // 1-1-4模式下(1线指令1线地址4线数据),页编程指令 + sCommand.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE; // 1线指令模式 + sCommand.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS; // 指令长度8位 sCommand.InstructionDtrMode = - HAL_OSPI_INSTRUCTION_DTR_DISABLE; // ָֹDTRģʽ + HAL_OSPI_INSTRUCTION_DTR_DISABLE; // 禁止指令DTR模式 - sCommand.Address = WriteAddr; // ַ - sCommand.AddressMode = HAL_OSPI_ADDRESS_1_LINE; // 1ߵַģʽ - sCommand.AddressSize = HAL_OSPI_ADDRESS_24_BITS; // ַ24λ - sCommand.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE; // ַֹDTRģʽ + sCommand.Address = WriteAddr; // 地址 + sCommand.AddressMode = HAL_OSPI_ADDRESS_1_LINE; // 1线地址模式 + sCommand.AddressSize = HAL_OSPI_ADDRESS_24_BITS; // 地址长度24位 + sCommand.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE; // 禁止地址DTR模式 - sCommand.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE; // ޽ֽ + sCommand.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE; // 无交替字节 sCommand.AlternateBytesDtrMode = - HAL_OSPI_ALTERNATE_BYTES_DTR_DISABLE; // ֹֽDTRģʽ + HAL_OSPI_ALTERNATE_BYTES_DTR_DISABLE; // 禁止替字节DTR模式 - sCommand.DataMode = HAL_OSPI_DATA_4_LINES; // 4ģʽ - sCommand.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE; // ֹDTRģʽ - sCommand.NbData = NumByteToWrite; // ݳ + sCommand.DataMode = HAL_OSPI_DATA_4_LINES; // 4线数据模式 + sCommand.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE; // 禁止数据DTR模式 + sCommand.NbData = NumByteToWrite; // 数据长度 - sCommand.DummyCycles = 0; // ڸ - sCommand.DQSMode = HAL_OSPI_DQS_DISABLE; // ʹDQS - sCommand.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD; // ÿδݶָ + sCommand.DummyCycles = 0; // 空周期个数 + sCommand.DQSMode = HAL_OSPI_DQS_DISABLE; // 不使用DQS + sCommand.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD; // 每次传输数据都发送指令 - // дʹ + // 写使能 if (OSPI_W25Qxx_WriteEnable() != OSPI_W25Qxx_OK) { - return W25Qxx_ERROR_WriteEnable; // дʹʧ + return W25Qxx_ERROR_WriteEnable; // 写使能失败 } - // д + // 写命令 if (HAL_OSPI_Command(&hospi2, &sCommand, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { - return W25Qxx_ERROR_TRANSMIT; // ݴ + return W25Qxx_ERROR_TRANSMIT; // 传输数据错误 } - // ʼ + // 开始传输数据 if (HAL_OSPI_Transmit(&hospi2, pBuffer, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { - return W25Qxx_ERROR_TRANSMIT; // ݴ + return W25Qxx_ERROR_TRANSMIT; // 传输数据错误 } - // ʹԶѯ־λȴдĽ + // 使用自动轮询标志位,等待写入的结束 if (OSPI_W25Qxx_AutoPollingMemReady() != OSPI_W25Qxx_OK) { - return W25Qxx_ERROR_AUTOPOLLING; // ѯȴӦ + return W25Qxx_ERROR_AUTOPOLLING; // 轮询等待无响应 } - return OSPI_W25Qxx_OK; // дݳɹ + return OSPI_W25Qxx_OK; // 写数据成功 } /********************************************************************************************************** * - * : OSPI_W25Qxx_WriteBuffer + * 函 数 名: OSPI_W25Qxx_WriteBuffer * - * ڲ: pBuffer - Ҫд - * WriteAddr - Ҫд W25Qxx ĵַ + * 入口参数: pBuffer - 要写入的数据 + * WriteAddr - 要写入 W25Qxx 的地址 * NumByteToWrite - - *ݳȣܳflashоƬĴС + *数据长度,最大不能超过flash芯片的大小 * - * ֵ: OSPI_W25Qxx_OK - дݳɹ - * W25Qxx_ERROR_WriteEnable - дʹʧ - * W25Qxx_ERROR_TRANSMIT - ʧ - * W25Qxx_ERROR_AUTOPOLLING - ѯȴӦ + * 返 回 值: OSPI_W25Qxx_OK - 写数据成功 + * W25Qxx_ERROR_WriteEnable - 写使能失败 + * W25Qxx_ERROR_TRANSMIT - 传输失败 + * W25Qxx_ERROR_AUTOPOLLING - 轮询等待无响应 * - * : дݣܳflashоƬĴСɲ + * 函数功能: 写入数据,最大不能超过flash芯片的大小,请务必完成擦除操作 * - * ˵ - *: 1.FlashдʱͲʱһ޶ģ˵OSPIʱ133MͿٶȽд - * 2. W25Q64JV ֲ ҳ - *дοʱ䣬ֵΪ 0.4msֵΪ3ms - * 3.ʵʵдٶȿܴ0.4msҲС0.4ms - * 4.FlashʹõʱԽдʱҲԽ - * 5.д֮ǰɲ - * 6.úֲ stm32h743i_eval_qspi.c + * 说 + *明: 1.Flash的写入时间和擦除时间一样,是有限定的,并不是说OSPI驱动时钟133M就可以以这个速度进行写入 + * 2.按照 W25Q64JV 数据手册给出的 页 + *写入参考时间,典型值为 0.4ms,最大值为3ms + * 3.实际的写入速度可能大于0.4ms,也可能小于0.4ms + * 4.Flash使用的时间越长,写入所需时间也会越长 + * 5.在数据写入之前,请务必完成擦除操作 + * 6.该函数移植于 stm32h743i_eval_qspi.c * **********************************************************************************************************/ int8_t OSPI_W25Qxx_WriteBuffer(uint8_t* pBuffer, uint32_t WriteAddr, uint32_t Size) { uint32_t end_addr, current_size, current_addr; - uint8_t* write_data; // Ҫд + uint8_t* write_data; // 要写入的数据 current_size = W25Qxx_PageSize - - (WriteAddr % W25Qxx_PageSize); // 㵱ǰҳʣĿռ + (WriteAddr % W25Qxx_PageSize); // 计算当前页还剩余的空间 - if (current_size > Size) // жϵǰҳʣĿռǷ㹻д + if (current_size > Size) // 判断当前页剩余的空间是否足够写入所有数据 { - current_size = Size; // 㹻ֱӻȡǰ + current_size = Size; // 如果足够,则直接获取当前长度 } - current_addr = WriteAddr; // ȡҪдĵַ - end_addr = WriteAddr + Size; // ַ - write_data = pBuffer; // ȡҪд + current_addr = WriteAddr; // 获取要写入的地址 + end_addr = WriteAddr + Size; // 计算结束地址 + write_data = pBuffer; // 获取要写入的数据 do { - // ҳд + // 按页写入数据 if (OSPI_W25Qxx_WritePage(write_data, current_addr, current_size) != OSPI_W25Qxx_OK) { return W25Qxx_ERROR_TRANSMIT; } - else // ҳдݳɹһдݵ׼ + else // 按页写入数据成功,进行下一次写数据的准备工作 { - current_addr += current_size; // һҪдĵַ - write_data += current_size; // ȡһҪдݴ洢ַ - // һдݵij + current_addr += current_size; // 计算下一次要写入的地址 + write_data += current_size; // 获取下一次要写入的数据存储区地址 + // 计算下一次写数据的长度 current_size = ((current_addr + W25Qxx_PageSize) > end_addr) ? (end_addr - current_addr) : W25Qxx_PageSize; } - } while (current_addr < end_addr); // жǷȫд + } while (current_addr < end_addr); // 判断数据是否全部写入完毕 - return OSPI_W25Qxx_OK; // дݳɹ + return OSPI_W25Qxx_OK; // 写入数据成功 } /********************************************************************************************************************************** * - * : OSPI_W25Qxx_ReadBuffer + * 函 数 名: OSPI_W25Qxx_ReadBuffer * - * ڲ: pBuffer - Ҫȡ - * ReadAddr - Ҫȡ W25Qxx ĵַ + * 入口参数: pBuffer - 要读取的数据 + * ReadAddr - 要读取 W25Qxx 的地址 * NumByteToRead - - *ݳȣܳflashоƬĴС + *数据长度,最大不能超过flash芯片的大小 * - * ֵ: OSPI_W25Qxx_OK - ݳɹ - * W25Qxx_ERROR_TRANSMIT - ʧ - * W25Qxx_ERROR_AUTOPOLLING - ѯȴӦ + * 返 回 值: OSPI_W25Qxx_OK - 读数据成功 + * W25Qxx_ERROR_TRANSMIT - 传输失败 + * W25Qxx_ERROR_AUTOPOLLING - 轮询等待无响应 * - * : ȡݣܳflashоƬĴС + * 函数功能: 读取数据,最大不能超过flash芯片的大小 * - * ˵ : 1.FlashĶȡٶȡOSPIͨʱӣܳ133M - * 2.ʹõ1-4-4ģʽ(1ָ4ߵַ4)ٶȡָ - *Fast Read Quad I/O 3.ʹÿٶȡָпڵģοW25Q64JVֲ Fast - *Read Quad I/O 0xEBָ - * 4.ʵʹУǷʹDMAŻȼԼݴ洢λ(ڲ - *TCM SRAM AXI SRAM)Ӱȡٶ FANKE + * 说 明: 1.Flash的读取速度取决于OSPI的通信时钟,最大不能超过133M + * 2.这里使用的是1-4-4模式下(1线指令4线地址4线数据),快速读取指令 + *Fast Read Quad I/O 3.使用快速读取指令是有空周期的,具体参考W25Q64JV的手册 Fast + *Read Quad I/O (0xEB)指令 + * 4.实际使用中,是否使用DMA、编译器的优化等级以及数据存储区的位置(内部 + *TCM SRAM 或者 AXI SRAM)都会影响读取的速度 FANKE *****************************************************************************************************************FANKE************/ int8_t OSPI_W25Qxx_ReadBuffer(uint8_t* pBuffer, uint32_t ReadAddr, uint32_t NumByteToRead) { - OSPI_RegularCmdTypeDef sCommand; // OSPI + OSPI_RegularCmdTypeDef sCommand; // OSPI传输配置 - sCommand.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG; // ͨ + sCommand.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG; // 通用配置 sCommand.FlashId = HAL_OSPI_FLASH_ID_1; // flash ID sCommand.Instruction = - W25Qxx_CMD_FastReadQuad_IO; // 1-4-4ģʽ(1ָ4ߵַ4)ٶȡָ - sCommand.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE; // 1ָģʽ - sCommand.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS; // ָ8λ + W25Qxx_CMD_FastReadQuad_IO; // 1-4-4模式下(1线指令4线地址4线数据),快速读取指令 + sCommand.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE; // 1线指令模式 + sCommand.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS; // 指令长度8位 sCommand.InstructionDtrMode = - HAL_OSPI_INSTRUCTION_DTR_DISABLE; // ָֹDTRģʽ + HAL_OSPI_INSTRUCTION_DTR_DISABLE; // 禁止指令DTR模式 - sCommand.Address = ReadAddr; // ַ - sCommand.AddressMode = HAL_OSPI_ADDRESS_4_LINES; // 4ߵַģʽ - sCommand.AddressSize = HAL_OSPI_ADDRESS_24_BITS; // ַ24λ - sCommand.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE; // ַֹDTRģʽ + sCommand.Address = ReadAddr; // 地址 + sCommand.AddressMode = HAL_OSPI_ADDRESS_4_LINES; // 4线地址模式 + sCommand.AddressSize = HAL_OSPI_ADDRESS_24_BITS; // 地址长度24位 + sCommand.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE; // 禁止地址DTR模式 - sCommand.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE; // ޽ֽ + sCommand.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE; // 无交替字节 sCommand.AlternateBytesDtrMode = - HAL_OSPI_ALTERNATE_BYTES_DTR_DISABLE; // ֹֽDTRģʽ + HAL_OSPI_ALTERNATE_BYTES_DTR_DISABLE; // 禁止替字节DTR模式 - sCommand.DataMode = HAL_OSPI_DATA_4_LINES; // 4ģʽ - sCommand.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE; // ֹDTRģʽ - sCommand.NbData = NumByteToRead; // ݳ + sCommand.DataMode = HAL_OSPI_DATA_4_LINES; // 4线数据模式 + sCommand.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE; // 禁止数据DTR模式 + sCommand.NbData = NumByteToRead; // 数据长度 - sCommand.DummyCycles = 6; // ڸ - sCommand.DQSMode = HAL_OSPI_DQS_DISABLE; // ʹDQS - sCommand.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD; // ÿδݶָ + sCommand.DummyCycles = 6; // 空周期个数 + sCommand.DQSMode = HAL_OSPI_DQS_DISABLE; // 不使用DQS + sCommand.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD; // 每次传输数据都发送指令 - // д + // 写命令 if (HAL_OSPI_Command(&hospi2, &sCommand, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { - return W25Qxx_ERROR_TRANSMIT; // ݴ + return W25Qxx_ERROR_TRANSMIT; // 传输数据错误 } - // + // 接收数据 if (HAL_OSPI_Receive(&hospi2, pBuffer, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { - return W25Qxx_ERROR_TRANSMIT; // ݴ + return W25Qxx_ERROR_TRANSMIT; // 传输数据错误 } - // ʹԶѯ־λȴյĽ + // 使用自动轮询标志位,等待接收的结束 if (OSPI_W25Qxx_AutoPollingMemReady() != OSPI_W25Qxx_OK) { - return W25Qxx_ERROR_AUTOPOLLING; // ѯȴӦ + return W25Qxx_ERROR_AUTOPOLLING; // 轮询等待无响应 } - return OSPI_W25Qxx_OK; // ȡݳɹ + return OSPI_W25Qxx_OK; // 读取数据成功 } diff --git a/hw/bsp/mc02/drivers/flash/w25q64.h b/hw/bsp/mc02/drivers/flash/w25q64.h index 8db122cf..d4b4f652 100644 --- a/hw/bsp/mc02/drivers/flash/w25q64.h +++ b/hw/bsp/mc02/drivers/flash/w25q64.h @@ -5,69 +5,69 @@ #include "main.h" -/*----------------------------------------------- +/*----------------------------------------------- 命名参数宏 * -------------------------------------------*/ -#define OSPI_W25Qxx_OK 0 // W25Qxxͨ -#define W25Qxx_ERROR_INIT -1 // ʼ -#define W25Qxx_ERROR_WriteEnable -2 // дʹܴ -#define W25Qxx_ERROR_AUTOPOLLING -3 // ѯȴӦ -#define W25Qxx_ERROR_Erase -4 // -#define W25Qxx_ERROR_TRANSMIT -5 // -#define W25Qxx_ERROR_MemoryMapped -6 // ڴӳģʽ +#define OSPI_W25Qxx_OK 0 // W25Qxx通信正常 +#define W25Qxx_ERROR_INIT -1 // 初始化错误 +#define W25Qxx_ERROR_WriteEnable -2 // 写使能错误 +#define W25Qxx_ERROR_AUTOPOLLING -3 // 轮询等待错误,无响应 +#define W25Qxx_ERROR_Erase -4 // 擦除错误 +#define W25Qxx_ERROR_TRANSMIT -5 // 传输错误 +#define W25Qxx_ERROR_MemoryMapped -6 // 内存映射模式错误 -#define W25Qxx_CMD_EnableReset 0x66 // ʹܸλ -#define W25Qxx_CMD_ResetDevice 0x99 // λ +#define W25Qxx_CMD_EnableReset 0x66 // 使能复位 +#define W25Qxx_CMD_ResetDevice 0x99 // 复位器件 #define W25Qxx_CMD_JedecID 0x9F // JEDEC ID -#define W25Qxx_CMD_WriteEnable 0X06 // дʹ +#define W25Qxx_CMD_WriteEnable 0X06 // 写使能 -#define W25Qxx_CMD_SectorErase 0x20 // 4Kֽڣ οʱ 45ms -#define W25Qxx_CMD_BlockErase_32K 0x52 // 32Kֽڣοʱ 120ms -#define W25Qxx_CMD_BlockErase_64K 0xD8 // 64Kֽڣοʱ 150ms -#define W25Qxx_CMD_ChipErase 0xC7 // Ƭοʱ 20S +#define W25Qxx_CMD_SectorErase 0x20 // 扇区擦除,4K字节, 参考擦除时间 45ms +#define W25Qxx_CMD_BlockErase_32K 0x52 // 块擦除, 32K字节,参考擦除时间 120ms +#define W25Qxx_CMD_BlockErase_64K 0xD8 // 块擦除, 64K字节,参考擦除时间 150ms +#define W25Qxx_CMD_ChipErase 0xC7 // 整片擦除,参考擦除时间 20S #define W25Qxx_CMD_QuadInputPageProgram \ - 0x32 // 1-1-4ģʽ(1ָ1ߵַ4)ҳָοдʱ 0.4ms + 0x32 // 1-1-4模式下(1线指令1线地址4线数据),页编程指令,参考写入时间 0.4ms #define W25Qxx_CMD_FastReadQuad_IO \ - 0xEB // 1-4-4ģʽ(1ָ4ߵַ4)ٶȡָ + 0xEB // 1-4-4模式下(1线指令4线地址4线数据),快速读取指令 -#define W25Qxx_CMD_ReadStatus_REG1 0X05 // ״̬Ĵ1 +#define W25Qxx_CMD_ReadStatus_REG1 0X05 // 读状态寄存器1 #define W25Qxx_Status_REG1_BUSY \ - 0x01 // ״̬Ĵ1ĵ0λֻBusy־λڲ/д/дʱᱻ1 + 0x01 // 读状态寄存器1的第0位(只读),Busy标志位,当正在擦除/写入数据/写命令时会被置1 #define W25Qxx_Status_REG1_WEL \ - 0x02 // ״̬Ĵ1ĵ1λֻWELдʹܱ־λñ־λΪ1ʱԽд + 0x02 // 读状态寄存器1的第1位(只读),WEL写使能标志位,该标志位为1时,代表可以进行写操作 -#define W25Qxx_PageSize 256 // ҳС256ֽ -#define W25Qxx_FlashSize 0x800000 // W25Q64С8Mֽ +#define W25Qxx_PageSize 256 // 页大小,256字节 +#define W25Qxx_FlashSize 0x800000 // W25Q64大小,8M字节 #define W25Qxx_FLASH_ID 0Xef4017 // W25Q64 JEDEC ID #define W25Qxx_ChipErase_TIMEOUT_MAX \ - 100000U // ʱȴʱ䣬W25Q64Ƭʱ100S -#define W25Qxx_Mem_Addr 0x90000000 // ڴӳģʽĵַ + 100000U // 超时等待时间,W25Q64整片擦除所需最大时间是100S +#define W25Qxx_Mem_Addr 0x90000000 // 内存映射模式的地址 -/*----------------------------------------------- +/*----------------------------------------------- 函数声明 * ---------------------------------------------------*/ -int8_t OSPI_W25Qxx_Init(void); // W25Qxxʼ -uint32_t OSPI_W25Qxx_ReadID(void); // ȡID +int8_t OSPI_W25Qxx_Init(void); // W25Qxx初始化 +uint32_t OSPI_W25Qxx_ReadID(void); // 读取器件ID -int8_t OSPI_W25Qxx_MemoryMappedMode(void); // OSPIΪڴӳģʽ +int8_t OSPI_W25Qxx_MemoryMappedMode(void); // 将OSPI设置为内存映射模式 int8_t OSPI_W25Qxx_SectorErase( - uint32_t SectorAddress); // 4Kֽڣ οʱ 45ms + uint32_t SectorAddress); // 扇区擦除,4K字节, 参考擦除时间 45ms int8_t OSPI_W25Qxx_BlockErase_32K( - uint32_t SectorAddress); // 32Kֽڣοʱ 120ms + uint32_t SectorAddress); // 块擦除, 32K字节,参考擦除时间 120ms int8_t OSPI_W25Qxx_BlockErase_64K( - uint32_t SectorAddress); // 64Kֽڣοʱ - // 150msʵʽʹ64Kʱ -int8_t OSPI_W25Qxx_ChipErase(void); // Ƭοʱ 20S + uint32_t SectorAddress); // 块擦除, 64K字节,参考擦除时间 + // 150ms,实际建议使用64K擦除,擦除的时间最快 +int8_t OSPI_W25Qxx_ChipErase(void); // 整片擦除,参考擦除时间 20S int8_t OSPI_W25Qxx_WritePage(uint8_t* pBuffer, uint32_t WriteAddr, - uint16_t NumByteToWrite); // ҳд룬256ֽ + uint16_t NumByteToWrite); // 按页写入,最大256字节 int8_t OSPI_W25Qxx_WriteBuffer( uint8_t* pBuffer, uint32_t WriteAddr, - uint32_t Size); // дݣܳflashоƬĴС + uint32_t Size); // 写入数据,最大不能超过flash芯片的大小 int8_t OSPI_W25Qxx_ReadBuffer( uint8_t* pBuffer, uint32_t ReadAddr, - uint32_t NumByteToRead); // ȡݣܳflashоƬĴС + uint32_t NumByteToRead); // 读取数据,最大不能超过flash芯片的大小 #endif diff --git a/hw/bsp/mc02/drivers/rtos/rtos.c b/hw/bsp/mc02/drivers/rtos/rtos.c index 46613b2f..7a9b4269 100644 --- a/hw/bsp/mc02/drivers/rtos/rtos.c +++ b/hw/bsp/mc02/drivers/rtos/rtos.c @@ -4,7 +4,7 @@ #include "task.h" /* FreeRTOS Heap */ -uint8_t ucHeap[configTOTAL_HEAP_SIZE] __attribute__((section(".ram_d1"))); +uint8_t ucHeap[configTOTAL_HEAP_SIZE] __attribute__((section(".itcram"))); void SysTick_Handler(void) { #if (INCLUDE_xTaskGetSchedulerState == 1) diff --git a/hw/bsp/mc02/ld/LinkerScripts.ld b/hw/bsp/mc02/ld/LinkerScripts.ld index 7e9688a0..e23b323c 100644 --- a/hw/bsp/mc02/ld/LinkerScripts.ld +++ b/hw/bsp/mc02/ld/LinkerScripts.ld @@ -177,16 +177,16 @@ SECTIONS . = ALIGN(8); } >DTCMRAM - .ram_d1 : ALIGN(4) + .itcram : ALIGN(4) { . = ALIGN(4); - _sram_d1 = .; /* create a global symbol at data start */ - *(.ram_d1) /* .data sections */ - *(.ram_d1*) /* .data* sections */ + _sitcram = .; /* create a global symbol at data start */ + *(.itcram) /* .data sections */ + *(.itcram*) /* .data* sections */ . = ALIGN(4); - _eram_d1 = .; /* define a global symbol at data end */ - } >RAM_D1 AT> FLASH + _eitcram = .; /* define a global symbol at data end */ + } >ITCMRAM /* Remove information from the standard libraries */ diff --git a/hw/mcu/st/cmake/mcu_stm32h7.cmake b/hw/mcu/st/cmake/mcu_stm32h7.cmake new file mode 100644 index 00000000..8d85c742 --- /dev/null +++ b/hw/mcu/st/cmake/mcu_stm32h7.cmake @@ -0,0 +1,28 @@ +include(${MCU_DIR}/default/custom_printf.cmake) + +set(CPU_FLAGS + "-mcpu=cortex-m7 -mfpu=fpv5-d16 -mfloat-abi=hard" + CACHE INTERNAL "" FORCE) + +set(GENERAL_FLAGS + "-Wall -fdata-sections -ffunction-sections" + CACHE INTERNAL "" FORCE) + +set(CMAKE_C_FLAGS + "${CPU_FLAGS} ${GENERAL_FLAGS} -fshort-enums -fdiagnostics-color=auto" + CACHE INTERNAL "" FORCE) + +set(CMAKE_CXX_FLAGS + "${CPU_FLAGS} ${GENERAL_FLAGS} -fno-threadsafe-statics -fno-rtti -fshort-enums -fdiagnostics-color=auto" + CACHE INTERNAL "" FORCE) + +set(CMAKE_ASM_FLAGS + "${CPU_FLAGS} -x assembler-with-cpp" + CACHE INTERNAL "" FORCE) + +# Linker Flag +set(LINKER_SCRIPT ${BOARD_DIR}/ld/LinkerScripts.ld) + +set(CMAKE_EXE_LINKER_FLAGS + "-T${LINKER_SCRIPT} --specs=nano.specs --specs=nosys.specs -Wl,--cref,--gc-sections,--print-memory-usage,-Map=${CMAKE_PROJECT_NAME}.map" + CACHE INTERNAL "" FORCE) diff --git a/hw/mcu/st/cmsis_device_h7 b/hw/mcu/st/cmsis_device_h7 new file mode 160000 index 00000000..faccfec3 --- /dev/null +++ b/hw/mcu/st/cmsis_device_h7 @@ -0,0 +1 @@ +Subproject commit faccfec37f82f7a1319c21638111b0f7335de7fe diff --git a/hw/mcu/st/stm32h7xx_hal_driver b/hw/mcu/st/stm32h7xx_hal_driver new file mode 160000 index 00000000..cd18606c --- /dev/null +++ b/hw/mcu/st/stm32h7xx_hal_driver @@ -0,0 +1 @@ +Subproject commit cd18606c04013fcb123838515fcb802b1dc1b281